# app/main.py
import os, hashlib
from typing import Optional
from urllib.parse import urlparse

from fastapi import FastAPI, Request, Form, Depends, HTTPException
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse, PlainTextResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware
from jinja2 import Environment, FileSystemLoader, select_autoescape
from passlib.hash import bcrypt
from pymysql.cursors import DictCursor
import pymysql
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded

from deps import get_db, current_user  # keine Kreis-Imports
from routers.admin_post import router as admin_posts_router
from routers.admin_rag import router as admin_rag_router
from routers.admin_logs import router as admin_logs_router
from routers.admin_vectors import router as admin_vectors_router
from routers.diary_rag import router as diary_rag_router
from routers.document_rag import router as document_rag_router
from routers.home import router as home_router
from routers.chat import router as chat_router
from routers.chat_page import router as chat_page_router

from routers.crumbforest_roles import router as roles_router

SECRET = os.getenv("APP_SECRET", "dev-secret-change-me")

app = FastAPI()

# --- Rate Limiting ---
from routers.chat import limiter
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# --- Static Files ---
app.mount("/static", StaticFiles(directory="static"), name="static")

# --- Middleware ---
app.add_middleware(SessionMiddleware, secret_key=SECRET, same_site="lax", https_only=False)

# CORS: Restrictive for production (allow localhost for dev)
allowed_origins = os.getenv("CORS_ORIGINS", "http://localhost:8000,http://127.0.0.1:8000").split(",")
app.add_middleware(
    CORSMiddleware,
    allow_origins=allowed_origins,  # Set via CORS_ORIGINS env var
    allow_credentials=True,
    allow_methods=["GET", "POST"],  # Only needed methods
    allow_headers=["Content-Type", "Accept"],  # Minimal headers
)

# --- Templates & Render ---
def init_templates(app: FastAPI):
    env = Environment(
        loader=FileSystemLoader("templates"),
        autoescape=select_autoescape(["html", "htm"])
    )
    app.state.tpl_env = env

    def render(req: Request, template: str, **ctx):
        # Gemeinsamer Kontext
        path = req.url.path or "/"
        seg = [p for p in path.split("/") if p]
        
        # Priority: 1. Query Param, 2. Path Prefix, 3. Session, 4. Default 'de'
        # Also added "fr" to supported languages
        query_lang = req.query_params.get("lang")
        supported_langs = ("de", "en", "fr")
        
        if query_lang and query_lang in supported_langs:
            lang = query_lang
            req.session["lang"] = lang # Persist selection
        elif seg and seg[0] in supported_langs:
            lang = seg[0]
            req.session["lang"] = lang # Persist selection from path
        else:
            lang = req.session.get("lang") or "de"
            
        tail = "/" + "/".join(seg[1:]) if (seg and seg[0] in supported_langs and len(seg) > 1) else "/"
        user = req.session.get("user")

        flashes = req.session.pop("_flashes", [])
        base_ctx = dict(
            req=req, lang=lang, path_tail=tail, user=user, flashes=flashes,
        )
        base_ctx.update(ctx)
        tpl = app.state.tpl_env.get_template(template)
        return HTMLResponse(tpl.render(**base_ctx))

    app.state.render = render

@app.on_event("startup")
def _startup():
    init_templates(app)

# --- kleine Utils ---
def flash(req: Request, message: str, category: str = "info"):
    arr = req.session.get("_flashes", [])
    arr.append({"msg": message, "cat": category})
    req.session["_flashes"] = arr

def get_lang_from_path(path: str, default="de"):
    seg = [p for p in (path or "/").split("/") if p]
    return seg[0] if seg and seg[0] in ("de", "en", "fr") else default

# --- Health & Dev helpers ---
@app.get("/health")
def health():
    return {"ok": True}

@app.get("/__routes", response_class=JSONResponse)
def list_routes():
    data = []
    for r in app.router.routes:
        if hasattr(r, "path") and hasattr(r, "name") and hasattr(r, "methods"):
            data.append({"path": r.path, "name": r.name, "methods": sorted(list(r.methods))})
    return data

@app.get("/__whoami", response_class=JSONResponse)
def whoami(req: Request):
    lang = get_lang_from_path(req.url.path, req.session.get("lang", "de"))
    return {"user": req.session.get("user"), "lang": lang}

@app.get("/favicon.ico")
def favicon():
    return PlainTextResponse("", status_code=204)

# --- Root & Home ---
# Root path is now handled by home router
# Old authenticated home page moved to /{lang}/ for backwards compatibility
@app.get("/{lang}/", name="authenticated_home", response_class=HTMLResponse)
def authenticated_home(req: Request, lang: str, user = Depends(current_user)):
    req.session["lang"] = lang
    return req.app.state.render(req, "pages/home.html", seo={"title": "Crumbforest", "desc": "Wuuuuhuuu!"})

# --- Login / Logout ---
# Explicit /login catch-all to prevent it matching /{lang}/login with lang="login"
@app.get("/login", include_in_schema=False)
def login_redirect(req: Request):
    lang = req.session.get("lang") or "de"
    return RedirectResponse(f"/{lang}/login", status_code=302)

@app.get("/{lang}/login", name="login_form", response_class=HTMLResponse)
def login_form(req: Request, lang: str):
    # Prevent "login" as lang if it slipped through
    if lang == "login":
        return RedirectResponse("/de/login", status_code=302)
        
    req.session["lang"] = lang
    return req.app.state.render(req, "pages/login.html", seo={"title": "Login", "desc": ""})

@app.post("/{lang}/login", name="login_post")
def login_post(
    req: Request,
    lang: str,
    email: str = Form(...),
    password: str = Form(...),
):
    req.session["lang"] = lang
    # prüfe User
    try:
        with get_db().cursor(DictCursor) as cur:
            cur.execute("SELECT id, email, pass_hash, role, locale, user_group, theme, accessibility FROM users WHERE email=%s", (email,))
            row = cur.fetchone()
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"db error: {e}")

    if not row or not bcrypt.verify(password, row["pass_hash"]):
        flash(req, "Invalid credentials", "error")
        # 200 lassen, damit Fehler im Formular sichtbar bleibt
        return req.app.state.render(req, "pages/login.html", seo={"title": "Login"}, form={"email": email})

    # Erfolg
    req.session["user"] = {
        "id": row["id"],
        "email": row["email"],
        "role": row["role"],
        "locale": row["locale"],
        "user_group": row.get("user_group", "demo"),
        "theme": row.get("theme", "pico-default"),
        "accessibility": row.get("accessibility")
    }
    flash(req, f"Welcome, {row['email']}", "success")
    
    # Redirect based on role with preserved language
    target = "/admin" if row["role"] == "admin" else "/crumbforest/roles"
    return RedirectResponse(f"{target}?lang={lang}", status_code=302)

@app.post("/logout", name="logout")
def logout(req: Request):
    req.session.pop("user", None)
    flash(req, "Logged out", "info")
    lang = req.session.get("lang", "de")
    return RedirectResponse(f"/{lang}/", status_code=302)

# --- Admin Dashboard ---
@app.get("/admin", name="admin_dashboard", response_class=HTMLResponse)
def admin_dashboard(req: Request, user = Depends(current_user)):
    if not user:
        return RedirectResponse(f"/{req.session.get('lang','de')}/login", status_code=302)
    if user.get("role") != "admin":
        return HTMLResponse("403 admin only", status_code=403)
    return req.app.state.render(req, "pages/admin.html", seo={"title": "Admin", "desc": ""})

# --- kleine API-Demo ---
@app.get("/api/hello", name="api_hello")
def api_hello(req: Request, lang: Optional[str] = None):
    lang = lang or req.session.get("lang") or "de"
    user = req.session.get("user", {}).get("email")
    msg = "Hallo Welt" if lang == "de" else "Hello World"
    return {"message": msg, "lang": lang, "user": user}

# --- Router mounten (ohne Kreisimport) ---
app.include_router(admin_posts_router, prefix="/admin")
app.include_router(admin_rag_router, prefix="/admin/rag", tags=["RAG"])
app.include_router(admin_logs_router, prefix="/admin", tags=["Admin Logs"])
app.include_router(admin_vectors_router, prefix="/admin", tags=["Admin Vectors"])
app.include_router(diary_rag_router, prefix="/api/diary", tags=["Diary RAG"])
app.include_router(document_rag_router, prefix="/api/documents", tags=["Documents RAG"])
app.include_router(chat_router, tags=["Chat"])
app.include_router(chat_page_router, tags=["Chat"])
app.include_router(roles_router, tags=["Roles"])

# Mount home router with lang prefix FIRST so it takes precedence
app.include_router(home_router, prefix="/{lang}", tags=["Home"])

# Mount home router at root
app.include_router(home_router, tags=["Home"])
