from flask import Blueprint, render_template, redirect, url_for, flash, request, send_file
from flask_login import login_required, current_user
from extensions import db
from models import Prediction, WordCount, User
from utils.predictor import predict
from sqlalchemy import func, or_, and_
import pandas as pd
import io

user_bp = Blueprint('user', __name__)


def visible_prediction_filter():
    """Data yang boleh dilihat user: prediksi milik sendiri + prediksi massal dari admin."""
    admin_ids = db.session.query(User.id).filter(User.role == 'admin')
    return or_(
        Prediction.user_id == current_user.id,
        and_(Prediction.tipe_input == 'bulk', Prediction.user_id.in_(admin_ids))
    )


def user_required(f):
    from functools import wraps
    @wraps(f)
    def decorated(*args, **kwargs):
        if not current_user.is_authenticated or current_user.role != 'user':
            flash('Akses ditolak.', 'danger')
            return redirect(url_for('auth.login'))
        return f(*args, **kwargs)
    return decorated


# ── Dashboard ──────────────────────────────────────────────────────────────
@user_bp.route('/dashboard')
@login_required
@user_required
def dashboard():
    base_filter = visible_prediction_filter()

    total_prediksi = Prediction.query.filter(base_filter).count()

    dist_pred = [
        (row[0], row[1]) for row in db.session.query(
            Prediction.label_hasil, func.count(Prediction.id)
        ).filter(base_filter).group_by(Prediction.label_hasil).all()
    ]

    riwayat_terakhir = Prediction.query.filter(base_filter)\
        .order_by(Prediction.created_at.desc()).limit(5).all()

    return render_template('user/dashboard.html',
        total_prediksi=total_prediksi,
        dist_pred=dist_pred,
        riwayat_terakhir=riwayat_terakhir,
    )


# ── Prediksi ───────────────────────────────────────────────────────────────
@user_bp.route('/prediksi', methods=['GET', 'POST'])
@login_required
@user_required
def prediksi():
    from models import ModelInfo
    hasil    = None
    komentar = ''

    # Ambil model default dari DB
    model_default = ModelInfo.query.filter_by(is_default=True).first()
    model_tipe    = model_default.tipe if model_default else 'indobert'
    model_nama    = model_default.nama_model if model_default else 'IndoBERT'

    if request.method == 'POST':
        komentar = request.form.get('komentar', '').strip()
        if not komentar:
            flash('Komentar tidak boleh kosong.', 'danger')
        else:
            hasil = predict(komentar, model=model_tipe)
            p = Prediction(
                user_id=current_user.id,
                komentar=komentar,
                label_hasil=hasil['label'],
                confidence=hasil['confidence'],
                prob_positif=hasil['prob_positif'],
                prob_negatif=hasil['prob_negatif'],
                prob_netral=hasil['prob_netral'],
                model_dipakai=model_tipe,
                tipe_input='manual'
            )
            db.session.add(p)
            db.session.commit()

    return render_template('user/prediksi.html', hasil=hasil, komentar=komentar,
                           model_nama=model_nama)




# ── Riwayat ────────────────────────────────────────────────────────────────
@user_bp.route('/riwayat')
@login_required
@user_required
def riwayat():
    page  = request.args.get('page', 1, type=int)
    label = request.args.get('label', '')
    q     = request.args.get('q', '').strip()

    query = Prediction.query.filter(visible_prediction_filter())
    if label:
        query = query.filter(Prediction.label_hasil == label)
    if q:
        query = query.filter(Prediction.komentar.ilike(f'%{q}%'))

    data = query.order_by(Prediction.created_at.desc()).paginate(page=page, per_page=20)
    return render_template('user/riwayat.html', data=data, label=label, q=q)


@user_bp.route('/riwayat/export')
@login_required
@user_required
def export_riwayat():
    data = Prediction.query.filter(visible_prediction_filter())\
        .order_by(Prediction.created_at.desc()).all()
    rows = [{
        'komentar': p.komentar, 'label': p.label_hasil,
        'confidence': p.confidence, 'model': p.model_dipakai, 'waktu': p.created_at
    } for p in data]
    df  = pd.DataFrame(rows)
    out = io.BytesIO()
    df.to_csv(out, index=False)
    out.seek(0)
    return send_file(out, mimetype='text/csv', as_attachment=True, download_name='riwayat_saya.csv')


@user_bp.route('/riwayat/hapus/<int:id>', methods=['POST'])
@login_required
@user_required
def hapus_riwayat(id):
    p = Prediction.query.filter_by(id=id, user_id=current_user.id).first_or_404()
    db.session.delete(p)
    db.session.commit()
    flash('Riwayat berhasil dihapus.', 'success')
    return redirect(url_for('user.riwayat'))


@user_bp.route('/riwayat/hapus-semua', methods=['POST'])
@login_required
@user_required
def hapus_semua_riwayat():
    Prediction.query.filter_by(user_id=current_user.id).delete()
    db.session.commit()
    flash('Semua riwayat berhasil dihapus.', 'success')
    return redirect(url_for('user.riwayat'))


# ── Visualisasi ────────────────────────────────────────────────────────────
@user_bp.route('/visualisasi')
@login_required
@user_required
def visualisasi():
    base_filter = visible_prediction_filter()

    dist_pred = [
        (row[0], row[1]) for row in db.session.query(
            Prediction.label_hasil, func.count(Prediction.id)
        ).filter(base_filter).group_by(Prediction.label_hasil).all()
    ]

    top_words = WordCount.query.order_by(WordCount.frekuensi.desc()).limit(20).all()

    return render_template('user/visualisasi.html',
        dist_pred=dist_pred,
        top_words=top_words,
    )
