from __future__ import annotations

import shutil
from pathlib import Path

from fastapi import APIRouter, File, Form, Request, UploadFile
from fastapi.responses import FileResponse, RedirectResponse
from starlette.background import BackgroundTask

from app.core.db.common import CommonSessionLocal
from app.core.http_responses import ui_access_denied, not_found_response
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
from app.core.security.session_auth import get_current_user
from app.core.templating import templates
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
from .service import can_use, create_job, save_uploads, analyze_job, resolve_owned_job, delete_job

router = APIRouter(prefix="/tools/bank-statement-analyzer", tags=["bank-statement-analyzer-ui"])


def _ctx(request, db, user, **extra):
    data = {
        "request": request,
        "current_user": user,
        "current_user_roles": get_user_roles(db, user.id),
        "current_user_permissions": get_user_permissions(db, user.id),
        "csrf_token": get_or_create_csrf_token(request),
        "title": "Bank Statement Analyzer",
    }
    data.update(extra)
    return data


def _auth(request, db):
    user = get_current_user(request, db=db)
    if not user:
        return None, None, RedirectResponse("/login", status_code=303)
    roles = get_user_roles(db, user.id)
    if not can_use(roles):
        return user, roles, ui_access_denied("Bank Statement Analyzer is available only to Partner, Manager, Staff and Consultant roles.")
    return user, roles, None


@router.get("")
def index(request: Request):
    db = CommonSessionLocal()
    try:
        user, roles, denied = _auth(request, db)
        if denied:
            return denied
        return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error=""))
    finally:
        db.close()


@router.post("/analyze")
async def analyze(request: Request, csrf_token: str = Form(...), customer_name: str = Form(""), account_number: str = Form(""), statements: list[UploadFile] = File(...)):
    db = CommonSessionLocal()
    job_dir: Path | None = None
    try:
        user, roles, denied = _auth(request, db)
        if denied:
            return denied
        validate_csrf(request, csrf_token)
        job_id, input_dir, output_dir = create_job(user, roles)
        job_dir = input_dir.parent
        paths = await save_uploads(statements, input_dir)
        summary = analyze_job(user=user, roles=roles, job_id=job_id, paths=paths, output_dir=output_dir, customer_override=customer_name, account_override=account_number)
        return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/result.html", _ctx(request, db, user, summary=summary))
    except Exception as exc:
        if job_dir and job_dir.exists():
            # Failed jobs are retained for the configured short retention period for troubleshooting/retry.
            pass
        user = get_current_user(request, db=db)
        if not user:
            return RedirectResponse("/login", status_code=303)
        return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error=str(exc)), status_code=400)
    finally:
        db.close()


@router.get("/{job_id}/download")
def download(job_id: str, request: Request):
    db = CommonSessionLocal()
    try:
        user, roles, denied = _auth(request, db)
        if denied:
            return denied
        try:
            job, meta = resolve_owned_job(user, roles, job_id)
        except FileNotFoundError:
            return not_found_response(request, "Analysis job not found or already cleaned up.")
        output = job / "Output" / meta["output_file"]
        if not output.is_file():
            return not_found_response(request, "Analysis workbook not found.")
        return FileResponse(path=output, filename="Bank_Statement_Analysis.xlsx", media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", background=BackgroundTask(delete_job, job))
    finally:
        db.close()


@router.post("/{job_id}/delete")
def delete(job_id: str, request: Request, csrf_token: str = Form(...)):
    db = CommonSessionLocal()
    try:
        user, roles, denied = _auth(request, db)
        if denied:
            return denied
        validate_csrf(request, csrf_token)
        try:
            job, _ = resolve_owned_job(user, roles, job_id)
            delete_job(job)
        except FileNotFoundError:
            pass
        return RedirectResponse("/tools/bank-statement-analyzer", status_code=303)
    finally:
        db.close()
