from datetime import date, datetime
from decimal import Decimal

from flask import Blueprint, flash, redirect, render_template, request, send_file, url_for
from sqlalchemy import extract, func, or_

from app.calculations import MONEY_FIELDS, calculate
from app.exporters import build_excel, build_pdf
from app.extensions import db
from app.models import Analysis


main_bp = Blueprint("main", __name__)


TEXT_FIELDS = [
    "nama_debitur", "nik", "alamat", "nomor_hp", "jenis_usaha", "lama_usaha",
    "status_tempat_usaha", "nama_pasangan", "jenis_agunan", "nomor_sertifikat",
]
INT_FIELDS = ["jumlah_tanggungan", "score_character", "score_capacity", "score_capital", "score_collateral", "score_condition", "tenor"]


def parse_money(raw):
    cleaned = str(raw or "0").replace("Rp", "").replace(".", "").replace(",", ".").strip()
    try:
        value = Decimal(cleaned or "0")
    except Exception:
        value = Decimal("0")
    return max(value, Decimal("0"))


def hydrate_analysis(analysis, form):
    for field in TEXT_FIELDS:
        setattr(analysis, field, (form.get(field) or "").strip())
    for field in MONEY_FIELDS:
        setattr(analysis, field, parse_money(form.get(field)))
    for field in INT_FIELDS:
        try:
            value = int(form.get(field) or 0)
        except ValueError:
            value = 0
        setattr(analysis, field, max(value, 0))
    tanggal = form.get("tanggal_analisis") or date.today().isoformat()
    analysis.tanggal_analisis = datetime.strptime(tanggal, "%Y-%m-%d").date()
    return analysis


def validate_analysis(analysis):
    errors = []
    required = {
        "nama_debitur": "Nama Debitur",
        "nik": "NIK",
        "alamat": "Alamat",
        "nomor_hp": "Nomor HP",
        "jenis_usaha": "Jenis Usaha",
        "lama_usaha": "Lama Usaha",
        "status_tempat_usaha": "Status Tempat Usaha",
    }
    for field, label in required.items():
        if not getattr(analysis, field):
            errors.append(f"{label} wajib diisi.")
    for field in ["score_character", "score_capacity", "score_capital", "score_collateral", "score_condition"]:
        value = getattr(analysis, field) or 0
        if value > 5:
            errors.append("Skor 5C maksimal 5 untuk setiap aspek.")
    return errors


@main_bp.route("/")
def dashboard():
    analyses = Analysis.query.order_by(Analysis.tanggal_analisis.desc()).all()
    calculated = [calculate(item) for item in analyses]
    count = len(analyses)
    totals = {
        "jumlah_analisis": count,
        "total_aset": sum(item["total_aset"] for item in calculated),
        "total_kewajiban": sum(item["total_kewajiban"] for item in calculated),
        "total_modal": sum(item["modal"] for item in calculated),
        "rata_der": (sum(item["der"] for item in calculated) / count).quantize(Decimal("0.01")) if count else Decimal("0"),
        "rata_rpc": (sum(item["rpc"] for item in calculated) / count).quantize(Decimal("0.01")) if count else Decimal("0"),
    }
    monthly_rows = (
        db.session.query(
            extract("year", Analysis.tanggal_analisis).label("year"),
            extract("month", Analysis.tanggal_analisis).label("month"),
            func.count(Analysis.id),
        )
        .group_by("year", "month")
        .order_by("year", "month")
        .all()
    )
    recommendation_counts = {"Layak": 0, "Layak Bersyarat": 0, "Tidak Layak": 0}
    for result in calculated:
        recommendation_counts[result["recommendation"]] += 1
    asset_comp = {
        "Aset Lancar": sum(item["total_aset_lancar"] for item in calculated),
        "Aset Tetap": sum(item["total_aset_tetap"] for item in calculated),
    }
    return render_template(
        "dashboard.html",
        totals=totals,
        recent=analyses[:8],
        monthly_labels=[f"{int(row.month):02d}/{int(row.year)}" for row in monthly_rows],
        monthly_values=[int(row[2]) for row in monthly_rows],
        recommendation_counts=recommendation_counts,
        asset_comp=asset_comp,
        page_title="Dashboard",
    )


@main_bp.route("/analyses")
def analyses():
    query = Analysis.query
    search = request.args.get("q", "").strip()
    start = request.args.get("start", "").strip()
    end = request.args.get("end", "").strip()
    if search:
        query = query.filter(or_(Analysis.nama_debitur.ilike(f"%{search}%"), Analysis.nik.ilike(f"%{search}%")))
    if start:
        query = query.filter(Analysis.tanggal_analisis >= datetime.strptime(start, "%Y-%m-%d").date())
    if end:
        query = query.filter(Analysis.tanggal_analisis <= datetime.strptime(end, "%Y-%m-%d").date())
    rows = query.order_by(Analysis.tanggal_analisis.desc(), Analysis.id.desc()).all()
    return render_template("analyses/list.html", analyses=rows, calculate=calculate, page_title="Riwayat Analisis")


@main_bp.route("/analyses/new", methods=["GET", "POST"])
def create_analysis():
    analysis = Analysis(tanggal_analisis=date.today(), status_tempat_usaha="Milik")
    if request.method == "POST":
        hydrate_analysis(analysis, request.form)
        errors = validate_analysis(analysis)
        if errors:
            for error in errors:
                flash(error, "danger")
        else:
            db.session.add(analysis)
            db.session.commit()
            flash("Analisis berhasil disimpan.", "success")
            return redirect(url_for("main.detail_analysis", analysis_id=analysis.id))
    return render_template("analyses/form.html", analysis=analysis, result=calculate(analysis), page_title="Tambah Analisis")


@main_bp.route("/analyses/<int:analysis_id>")
def detail_analysis(analysis_id):
    analysis = Analysis.query.get_or_404(analysis_id)
    return render_template("analyses/detail.html", analysis=analysis, result=calculate(analysis), page_title=analysis.nama_debitur)


@main_bp.route("/analyses/<int:analysis_id>/edit", methods=["GET", "POST"])
def edit_analysis(analysis_id):
    analysis = Analysis.query.get_or_404(analysis_id)
    if request.method == "POST":
        hydrate_analysis(analysis, request.form)
        errors = validate_analysis(analysis)
        if errors:
            for error in errors:
                flash(error, "danger")
        else:
            db.session.commit()
            flash("Analisis berhasil diperbarui.", "success")
            return redirect(url_for("main.detail_analysis", analysis_id=analysis.id))
    return render_template("analyses/form.html", analysis=analysis, result=calculate(analysis), page_title="Edit Analisis")


@main_bp.route("/analyses/<int:analysis_id>/delete", methods=["POST"])
def delete_analysis(analysis_id):
    analysis = Analysis.query.get_or_404(analysis_id)
    db.session.delete(analysis)
    db.session.commit()
    flash("Analisis berhasil dihapus.", "success")
    return redirect(url_for("main.analyses"))


@main_bp.route("/analyses/<int:analysis_id>/pdf")
def export_pdf(analysis_id):
    analysis = Analysis.query.get_or_404(analysis_id)
    path = build_pdf(analysis, calculate(analysis))
    return send_file(path, as_attachment=True, download_name=f"SAKM_{analysis.nik}.pdf")


@main_bp.route("/analyses/<int:analysis_id>/excel")
def export_excel(analysis_id):
    analysis = Analysis.query.get_or_404(analysis_id)
    path = build_excel(analysis, calculate(analysis))
    return send_file(path, as_attachment=True, download_name=f"SAKM_{analysis.nik}.xlsx")


@main_bp.route("/init-db")
def init_db():
    db.create_all()
    flash("Database siap digunakan.", "success")
    return redirect(url_for("main.dashboard"))

