import logging

# FIX: load_dotenv() dipanggil PERTAMA sebelum import apapun
# yang membaca env variable saat module di-import.
from dotenv import load_dotenv
load_dotenv()

from contextlib import asynccontextmanager

from fastapi import FastAPI, Request, Depends, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from starlette.middleware.base import BaseHTTPMiddleware
from sqlalchemy.orm import Session
from sqlalchemy import inspect, text

from app.core.database import engine, SessionLocal, Base, get_db
from app.core.templates import templates
from app.models import transkripsi as _transkripsi_model   # noqa: F401
from app.models import user as _user_model                 # noqa: F401
from app.models.berita_acara import BeritaAcara
from app.models.transaksi import Transaction
from app.models.topup_order import TopupOrder
from app.models.service_rate import ServiceRate
from app.models.feature_flag import FeatureFlag
from app.routers import routes_transkripsi, routes_record, routes_auth, routes_admin
from app.routers import routes_berita_acara
from app.routers import routes_topup
from app.services.auth_service import create_default_admin, get_current_user
from app.services.feature_flag_service import (
    seed_default_flags,
    is_enabled,
    get_flags_for_template,
)
from app.models.user import User
from app.core.config import MIDTRANS_CLIENT_KEY


# ================================================================
# Logging
# ================================================================
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger(__name__)

templates.env.globals["get_flags"] = lambda req: getattr(req.state, "feature_flags", {})


# ================================================================
# Fungsi migrasi dan seeding
# ================================================================
def migrate_and_seed_db():
    """Tambahkan kolom balance ke users jika belum ada, dan seed tarif default."""
    inspector = inspect(engine)
    if "balance" not in {c["name"] for c in inspector.get_columns("users")}:
        with engine.connect() as conn:
            conn.execute(text("ALTER TABLE users ADD COLUMN balance INTEGER DEFAULT 0 NOT NULL"))
            conn.commit()
            logger.info("[Migration] Kolom 'balance' ditambahkan ke tabel users.")

    Base.metadata.create_all(bind=engine)

    db = SessionLocal()
    try:
        if db.query(ServiceRate).count() == 0:
            db.add(ServiceRate(key="transcription_rate_per_minute", value=5000))
            db.add(ServiceRate(key="ba_rate", value=20000))
            db.commit()
            logger.info("[Startup] Tarif default disimpan.")
    except Exception as exc:
        logger.warning("[Startup] Gagal seed tarif default: %s", exc)
    finally:
        db.close()


# ================================================================
# Lifespan — startup & shutdown
# ================================================================
@asynccontextmanager
async def lifespan(app: FastAPI):
    logger.info("[Startup] Migrasi dan pembuatan tabel database...")
    migrate_and_seed_db()

    logger.info("[Startup] Mengecek akun admin default...")
    db = SessionLocal()
    try:
        create_default_admin(db)

        # ── Recovery: task yang nyangkut akibat server restart ──────
        # Task dengan status pending/processing saat startup dipastikan
        # tidak ada worker-nya lagi → langsung di-set failed agar bisa
        # dihapus oleh user/admin dan tidak memblokir antrian.
        logger.info("[Startup] Memeriksa task yang nyangkut (pending/processing)...")
        from app.utils.startup_recovery import recover_stale_tasks_aggressive
        recovered = recover_stale_tasks_aggressive(db)
        if recovered > 0:
            logger.warning(
                "[Startup] %d task nyangkut ditemukan dan di-set ke 'failed'.",
                recovered,
            )
        else:
            logger.info("[Startup] Tidak ada task yang nyangkut.")
        # ────────────────────────────────────────────────────────────

        logger.info("[Startup] Seeding feature flags default...")
        seed_default_flags(db)

    except Exception as exc:
        logger.critical("[Startup] Gagal saat startup: %s", exc, exc_info=True)
        raise
    finally:
        db.close()

    # Preload Whisper model
    import os
    if os.getenv("PRELOAD_WHISPER_MODEL", "true").lower() == "true":
        try:
            from app.core.config import WHISPER_DEFAULT_MODEL
            from app.utils.whisper_worker import run_in_threadpool
            from app.services.whisper_local import get_model

            logger.info("[Startup] Preloading Whisper model '%s'...", WHISPER_DEFAULT_MODEL)
            await run_in_threadpool(get_model, WHISPER_DEFAULT_MODEL)
            logger.info("[Startup] Whisper model '%s' berhasil dimuat.", WHISPER_DEFAULT_MODEL)
        except Exception as exc:
            logger.warning("[Startup] Preload Whisper model gagal: %s", exc)

    logger.info("[Startup] Aplikasi siap.")
    yield
    logger.info("[Shutdown] Aplikasi berhenti.")


# ================================================================
# Aplikasi
# ================================================================
app = FastAPI(
    title="Sistem Transkripsi Audio",
    lifespan=lifespan,
    docs_url="/docs",
    redoc_url="/redoc",
)

app.mount("/static", StaticFiles(directory="app/static"), name="static")


# ================================================================
# Middleware — inject feature flags ke setiap request
# ================================================================
class FeatureFlagMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            db = SessionLocal()
            request.state.feature_flags = get_flags_for_template(db)
        except Exception:
            request.state.feature_flags = {}
        finally:
            db.close()
        return await call_next(request)

app.add_middleware(FeatureFlagMiddleware)


# ================================================================
# Helper maintenance response
# ================================================================
def _maintenance_response(request: Request, current_user: User, fitur: str):
    """Menampilkan halaman maintenance dengan status 503."""
    return templates.TemplateResponse(
        "maintenance.html",
        {"request": request, "user": current_user, "fitur": fitur},
        status_code=503,
    )


# ================================================================
# Routers
# ================================================================
app.include_router(routes_auth.router)
app.include_router(routes_admin.router)
app.include_router(routes_transkripsi.router, prefix="/api")
app.include_router(routes_record.router,      prefix="/api")
app.include_router(routes_berita_acara.router, prefix="/api")
app.include_router(routes_topup.router, prefix="/api")


# ================================================================
# API — Feature flags publik (untuk polling JS di base.html)
# ================================================================

@app.get("/api/flags")
def get_public_flags(
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """
    Mengembalikan status semua feature flag yang dikontrol nav sidebar.
    Dipanggil oleh polling JS di base.html setiap 10 detik.
    Wajib login — jika 401 polling akan berhenti otomatis.
    """
    flags = get_flags_for_template(db)
    return {
        "upload_file": flags.get("upload_file", True),
        "rekam_live":  flags.get("rekam_live",  True),
        "mode_sidang": flags.get("mode_sidang", True),
        "topup":       flags.get("topup",       True),
    }


# ================================================================
# PUBLIC — Tidak perlu login
# ================================================================

@app.get("/", response_class=HTMLResponse)
def landing(request: Request):
    token = request.cookies.get("access_token")
    if token:
        return RedirectResponse(url="/home", status_code=302)
    return templates.TemplateResponse("landing.html", {"request": request})


# ================================================================
# PROTECTED — Wajib login, dengan pengecekan feature flag
# ================================================================

@app.get("/home", response_class=HTMLResponse)
def home(
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("index.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/transkripsi/file", response_class=HTMLResponse)
def upload_page(
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if not is_enabled(db, "upload_file"):
        return _maintenance_response(request, current_user, "Upload File Audio")
    return templates.TemplateResponse("upload.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/transkripsi/rekam", response_class=HTMLResponse)
def record_page(
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if not is_enabled(db, "rekam_live"):
        return _maintenance_response(request, current_user, "Rekam Audio Live")
    return templates.TemplateResponse("record.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/transkripsi/status/{task_id}", response_class=HTMLResponse)
def status_page(
    task_id: int,
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("status.html", {
        "request": request,
        "task_id": task_id,
        "user":    current_user,
    })


@app.get("/sidang", response_class=HTMLResponse)
def sidang_page(
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if not is_enabled(db, "mode_sidang"):
        return _maintenance_response(request, current_user, "Mode Sidang")
    return templates.TemplateResponse("sidang.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/profil/ganti-password", response_class=HTMLResponse)
def ganti_password_page(
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("ganti_password.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/berita-acara/{ba_id}", response_class=HTMLResponse)
def berita_acara_page(
    ba_id: int,
    request: Request,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    if not is_enabled(db, "berita_acara"):
        return _maintenance_response(request, current_user, "Berita Acara Sidang")

    ba = db.query(BeritaAcara).filter(BeritaAcara.id == ba_id).first()
    if not ba:
        raise HTTPException(status_code=404, detail="Berita Acara tidak ditemukan.")
    if current_user.role != "admin" and ba.user_id != current_user.id:
        raise HTTPException(status_code=403, detail="Akses ditolak.")
    return templates.TemplateResponse("berita_acara.html", {
        "request": request,
        "ba_id":   ba_id,
        "task_id": ba.task_id,
        "user":    current_user,
    })


@app.get("/transaksi", response_class=HTMLResponse)
def transactions_page(
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("transactions.html", {
        "request": request,
        "user":    current_user,
    })


@app.get("/topup", response_class=HTMLResponse)
def topup_page(
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("topup.html", {
        "request":              request,
        "user":                 current_user,
        "midtrans_client_key":  MIDTRANS_CLIENT_KEY,
    })


# ================================================================
# Exception Handlers
# ================================================================

@app.exception_handler(401)
async def unauthorized_handler(
    request: Request,
    exc: HTTPException,
) -> RedirectResponse | JSONResponse:
    accept = request.headers.get("accept", "")
    if "text/html" in accept:
        next_url    = request.url.path
        redirect_to = (
            f"/login?next={next_url}"
            if next_url not in ("/", "/home", "/login")
            else "/login"
        )
        return RedirectResponse(url=redirect_to, status_code=302)
    return JSONResponse(
        status_code=401,
        content={"detail": exc.detail or "Unauthorized"},
    )


@app.exception_handler(403)
async def forbidden_handler(
    request: Request,
    exc: HTTPException,
) -> JSONResponse:
    return JSONResponse(
        status_code=403,
        content={"detail": exc.detail or "Forbidden"},
    )


@app.exception_handler(404)
async def not_found_handler(
    request: Request,
    exc: HTTPException,
) -> HTMLResponse | JSONResponse:
    accept = request.headers.get("accept", "")
    if "text/html" in accept:
        return templates.TemplateResponse(
            "404.html",
            {"request": request},
            status_code=404,
        )
    return JSONResponse(
        status_code=404,
        content={"detail": exc.detail or "Not Found"},
    )
@app.get("/riwayat", response_class=HTMLResponse)
def riwayat_page(
    request: Request,
    current_user: User = Depends(get_current_user),
):
    return templates.TemplateResponse("riwayat.html", {
        "request": request,
        "user":    current_user,
    })