from flask import Flask, render_template, redirect, url_for, request, flash, abort, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from functools import wraps

app = Flask(__name__)
app.config['SECRET_KEY'] = 'kunci_rahasia_disertasi_scopus_123'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

# ==================== DECORATOR UNTUK RBAC ====================

def role_required(*roles):
    """
    Decorator untuk membatasi akses route berdasarkan role user.
    Penggunaan: @role_required('Super Admin', 'Konsultan')
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.is_authenticated:
                return login_manager.unauthorized()
            if current_user.role not in roles:
                flash('Anda tidak memiliki hak akses ke halaman tersebut!', 'danger')
                abort(403)  # HTTP 403 Forbidden
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# ==================== MODELS ====================

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    role = db.Column(db.String(50), nullable=False, default='Peneliti')
    orders = db.relationship('Order', backref='client', lazy=True)

class Order(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    service_type = db.Column(db.String(100), nullable=False) 
    status = db.Column(db.String(50), default='Menunggu Review')
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))

# ==================== ROUTES (AUTH) ====================

@app.route('/')
def index():
    return render_template('index.html')
    
@app.route('/shoppingcart.html')
def shopping_cart():
    return render_template('shoppingcart.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get('username')
        email = request.form.get('email')
        password = request.form.get('password')
        role = request.form.get('role', 'Peneliti')
        
        user_exists = db.session.execute(
            db.select(User).where((User.email == email) | (User.username == username))
        ).scalar()
        
        if user_exists:
            flash('Username atau Email sudah terdaftar!', 'danger')
            return redirect(url_for('register'))
            
        hashed_password = generate_password_hash(password, method='pbkdf2:sha256')
        new_user = User(username=username, email=email, password=hashed_password, role=role)
        db.session.add(new_user)
        db.session.commit()
        
        flash('Registrasi berhasil! Silakan login.', 'success')
        return redirect(url_for('login'))
        
    return render_template('register.html')

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        email = request.form.get('email')
        password = request.form.get('password')
        
        user = db.session.execute(
            db.select(User).where(User.email == email)
        ).scalar()
        
        if user and check_password_hash(user.password, password):
            login_user(user)
            session['role'] = user.role 
            return redirect(url_for('dashboard'))
        else:
            flash('Login gagal. Periksa kembali email dan password Anda.', 'danger')
            
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    session.pop('role', None)
    flash('Anda telah logout.', 'success')
    return redirect(url_for('index'))

# ==================== ROUTES (CRUD & DASHBOARD) ====================

@app.route('/dashboard')
@login_required
def dashboard():
    if 'role' not in session:
        session['role'] = current_user.role

    if current_user.role == 'Peneliti':
        user_orders = db.session.execute(
            db.select(Order).where(Order.user_id == current_user.id)
        ).scalars().all()
    else:
        user_orders = db.session.execute(db.select(Order)).scalars().all()
        
    return render_template('dashboard.html', orders=user_orders)

# ----------------- HAK AKSES KHUSUS PER ROLE -----------------

@app.route('/admin/users')
@login_required
@role_required('Super Admin')
def admin_users():
    all_users = db.session.execute(db.select(User)).scalars().all()
    return render_template('dashboard.html', users=all_users, view='admin')

@app.route('/konsultan/review')
@login_required
@role_required('Super Admin', 'Konsultan')
def konsultan_review():
    return render_template('dashboard.html', view='konsultan')
    
@app.route('/peneliti/analisis')
@login_required
@role_required('Super Admin', 'Peneliti')
def peneliti_analisis():
    return render_template('dashboard.html', view='peneliti')

@app.route('/editor/review')
@login_required
@role_required('Super Admin', 'Editor')
def editor_review():
    return render_template('dashboard.html', view='editor')

# ----------------- OPERASI DATA NASKAH (ORDER) -----------------

@app.route('/order/create', methods=['POST'])
@login_required
@role_required('Peneliti', 'Super Admin')
def create_order():
    if request.method == 'POST':
        title = request.form.get('title')
        service_type = request.form.get('service_type')
        
        new_order = Order(title=title, service_type=service_type, user_id=current_user.id)
        db.session.add(new_order)
        db.session.commit()
        flash('Pesanan naskah berhasil diajukan!', 'success')
    return redirect(url_for('dashboard'))

@app.route('/order/update/<int:id>', methods=['POST'])
@login_required
def update_order(id):
    order = db.session.get(Order, id)
    if not order:
        flash('Data tidak ditemukan!', 'danger')
        return redirect(url_for('dashboard'))
        
    if current_user.role == 'Peneliti' and order.user_id != current_user.id:
        flash('Akses ditolak!', 'danger')
        return redirect(url_for('dashboard'))
        
    if 'status' in request.form and current_user.role != 'Peneliti':
        order.status = request.form.get('status')
        
    if 'title' in request.form and request.form.get('title'):
        order.title = request.form.get('title')
    if 'service_type' in request.form and request.form.get('service_type'):
        order.service_type = request.form.get('service_type')
        
    db.session.commit()
    flash('Data pesanan berhasil diperbarui!', 'success')
    return redirect(url_for('dashboard'))

@app.route('/order/delete/<int:id>', methods=['POST'])
@login_required
@role_required('Peneliti', 'Super Admin')
def delete_order(id):
    order = db.session.get(Order, id)
    
    if not order or (current_user.role == 'Peneliti' and order.user_id != current_user.id):
        flash('Akses ditolak atau data tidak ditemukan!', 'danger')
        return redirect(url_for('dashboard'))
        
    db.session.delete(order)
    db.session.commit()
    flash('Pesanan berhasil dibatalkan/dihapus.', 'success')
    return redirect(url_for('dashboard'))

# Pengamanan pembuatan database otomatis khusus server cPanel
try:
    with app.app_context():
        db.create_all()
except Exception as e:
    print(f"Database initialization skip/error: {e}")

if __name__ == '__main__':
    app.run(debug=True)