import io
import logging
import shutil
import zipfile
from datetime import datetime
from pathlib import Path

from fastapi import APIRouter, Depends, File, Form, Request, UploadFile
from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from config import BASE_DIR, DB_PATH, UPLOAD_DIR
from dependencies import get_current_user, get_db
from models.benutzer import Benutzer
from models.kategorie_option import KategorieOption
from models.kontakt import Kontakt
from services import kontakt_service
import search

router = APIRouter(prefix="/einstellungen")
templates = Jinja2Templates(directory="templates")
logger = logging.getLogger("kontaktwerk")


@router.get("", response_class=HTMLResponse)
async def index(request: Request, user=Depends(get_current_user)):
    return templates.TemplateResponse("pages/einstellungen/index.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
    })


@router.post("/app-name")
async def app_name_speichern(
    request: Request,
    app_name: str = Form(...),
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    opt = db.query(KategorieOption).filter(
        KategorieOption.gruppe == "app_einstellungen",
        KategorieOption.wert == "app_name",
    ).first()
    if opt:
        opt.label = app_name.strip()
    else:
        db.add(KategorieOption(
            gruppe="app_einstellungen", wert="app_name",
            label=app_name.strip(), position=0,
        ))
    db.commit()
    return RedirectResponse(url="/einstellungen", status_code=303)


@router.get("/import", response_class=HTMLResponse)
async def import_page(request: Request, user=Depends(get_current_user)):
    return templates.TemplateResponse("pages/einstellungen/import.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
        "bericht": None,
    })


@router.post("/import/kontakte", response_class=HTMLResponse)
async def import_kontakte(
    request: Request,
    datei: UploadFile = File(...),
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    from services.import_service import import_kontakte_excel

    content = await datei.read()
    bericht = import_kontakte_excel(db, io.BytesIO(content))

    return templates.TemplateResponse("pages/einstellungen/import.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
        "bericht": bericht,
    })


@router.post("/import/aktivitaeten", response_class=HTMLResponse)
async def import_aktivitaeten(
    request: Request,
    datei: UploadFile = File(...),
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    from services.import_service import import_aktivitaeten_excel

    content = await datei.read()
    bericht = import_aktivitaeten_excel(db, io.BytesIO(content))

    return templates.TemplateResponse("pages/einstellungen/import.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
        "bericht": bericht,
    })


# --- Backup ---

@router.get("/backup")
async def backup_download(user=Depends(get_current_user)):
    if not user.ist_admin:
        return RedirectResponse(url="/einstellungen", status_code=303)

    buf = io.BytesIO()
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
        # Datenbank
        if DB_PATH.exists():
            zf.write(DB_PATH, "kontaktwerk.db")

        # Uploads
        if UPLOAD_DIR.exists():
            for f in UPLOAD_DIR.rglob("*"):
                if f.is_file():
                    zf.write(f, f"uploads/{f.relative_to(UPLOAD_DIR)}")

        # Config
        config_path = BASE_DIR / "config.py"
        if config_path.exists():
            zf.write(config_path, "config.py")

    buf.seek(0)
    filename = f"kontaktwerk_backup_{timestamp}.zip"
    return StreamingResponse(
        buf,
        media_type="application/zip",
        headers={"Content-Disposition": f"attachment; filename={filename}"},
    )


@router.post("/backup/wiederherstellen")
async def backup_restore(
    request: Request,
    datei: UploadFile = File(...),
    user=Depends(get_current_user),
):
    if not user.ist_admin:
        return RedirectResponse(url="/einstellungen", status_code=303)

    content = await datei.read()
    buf = io.BytesIO(content)

    try:
        with zipfile.ZipFile(buf, "r") as zf:
            namen = zf.namelist()

            # Datenbank wiederherstellen
            if "kontaktwerk.db" in namen:
                # Backup der aktuellen DB
                if DB_PATH.exists():
                    shutil.copy2(DB_PATH, DB_PATH.with_suffix(".db.pre-restore"))
                with open(DB_PATH, "wb") as f:
                    f.write(zf.read("kontaktwerk.db"))

            # Uploads wiederherstellen
            for name in namen:
                if name.startswith("uploads/") and not name.endswith("/"):
                    ziel = UPLOAD_DIR / name[len("uploads/"):]
                    ziel.parent.mkdir(parents=True, exist_ok=True)
                    with open(ziel, "wb") as f:
                        f.write(zf.read(name))

        logger.info(f"Backup wiederhergestellt von {datei.filename} durch {user.kuerzel}")
    except zipfile.BadZipFile:
        logger.error(f"Ungueltige Backup-Datei: {datei.filename}")
        return RedirectResponse(url="/einstellungen", status_code=303)

    return RedirectResponse(url="/einstellungen", status_code=303)


@router.post("/reindex")
async def reindex(user=Depends(get_current_user), db: Session = Depends(get_db)):
    search.rebuild_index(db)
    return RedirectResponse(url="/einstellungen", status_code=303)


@router.get("/benutzer", response_class=HTMLResponse)
async def benutzer_liste(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    if not user.ist_admin:
        return RedirectResponse(url="/einstellungen", status_code=303)

    benutzer = db.query(Benutzer).order_by(Benutzer.kuerzel).all()
    return templates.TemplateResponse("pages/einstellungen/benutzer.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
        "benutzer": benutzer,
    })


@router.post("/benutzer/neu")
async def benutzer_erstellen(
    kuerzel: str = Form(...),
    name: str = Form(...),
    passwort: str = Form(...),
    ist_admin: bool = Form(False),
    user=Depends(get_current_user),
    db: Session = Depends(get_db),
):
    if not user.ist_admin:
        return RedirectResponse(url="/einstellungen", status_code=303)

    neuer_user = Benutzer(
        kuerzel=kuerzel.strip().upper(),
        name=name.strip(),
        ist_admin=ist_admin,
    )
    neuer_user.set_passwort(passwort)
    db.add(neuer_user)
    db.commit()
    return RedirectResponse(url="/einstellungen/benutzer", status_code=303)


# --- Blacklist ---

@router.get("/blacklist", response_class=HTMLResponse)
async def blacklist(request: Request, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakte = kontakt_service.blacklist_liste(db)
    return templates.TemplateResponse("pages/einstellungen/blacklist.html", {
        "request": request,
        "user": user,
        "active_page": "einstellungen",
        "kontakte": kontakte,
    })


@router.post("/blacklist/{kontakt_id}/entsperren")
async def blacklist_entsperren(kontakt_id: int, user=Depends(get_current_user), db: Session = Depends(get_db)):
    kontakt = db.query(Kontakt).filter(Kontakt.id == kontakt_id).first()
    if kontakt:
        kontakt.ist_blacklisted = False
        kontakt.blacklist_grund = None
        kontakt.blacklist_am = None
        kontakt.blacklist_von = None
        db.commit()
    return RedirectResponse(url="/einstellungen/blacklist", status_code=303)
