import hashlib
import secrets
from datetime import datetime, timezone
from uuid import UUID

from fastapi import APIRouter, Depends, Request
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.config import settings
from app.core.database import get_db
from app.core.dependencies import CurrentUser, get_client_ip, require_role
from app.models import Company
from app.models.audit_log import AuditLog
from app.models.department import Department
from app.models.user import User, UserRole
from app.schemas.company import (
    CompanyOut,
    CompanyUpdate,
    DepartmentCreate,
    DepartmentOut,
    DepartmentUpdate,
    PublicStampTokenRotated,
    PublicStampTokenStatus,
)

router = APIRouter(prefix="/companies", tags=["Companies"])

_admin_roles = (UserRole.COMPANY_ADMIN, UserRole.SUPER_ADMIN)


def _public_stamp_url(token: str) -> str:
    return f"{settings.frontend_url.rstrip('/')}/stamp?t={token}"


@router.get("/me", response_model=CompanyOut)
async def get_my_company(current_user: CurrentUser, db: AsyncSession = Depends(get_db)):
    company = await db.get(Company, current_user.company_id)
    return CompanyOut.model_validate(company)


@router.post("/me/run-reminders")
async def run_reminders_now(
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    """Erinnerungs-Jobs (offene Anträge, Resturlaub-Verfall, AU fehlt) sofort für die
    eigene Firma ausführen. Gleiche Logik wie der tägliche Scheduler."""
    from app.services.scheduler_service import run_all_reminders
    result = await run_all_reminders(db, company_id=current_user.company_id)
    await db.commit()
    return {"sent": result}


@router.post("/me/run-retention-purge")
async def run_retention_purge_now(
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    """Löscht Zeiterfassung/Auszahlungen der eigenen Firma, die älter als die
    konfigurierte Aufbewahrungsfrist (company.settings.retention_lohn_years,
    Default 10 Jahre) sind. Technische Tabellen (audit_logs/sessions) laufen
    nur im globalen Scheduler-Job, nicht firmenscoped."""
    from app.services.retention_service import run_retention_purge
    result = await run_retention_purge(db, company_id=current_user.company_id)
    await db.commit()
    return {"deleted": result}


@router.patch("/me", response_model=CompanyOut)
async def update_my_company(
    data: CompanyUpdate,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    company = await db.get(Company, current_user.company_id)
    update_data = data.model_dump(exclude_none=True)
    # settings ist ein CompanySettingsUpdate-Objekt → als dict ins JSONB mergen
    if "settings" in update_data and isinstance(update_data["settings"], dict):
        existing = dict(company.settings or {})
        existing.update(update_data.pop("settings"))
        update_data["settings"] = existing
    for field, value in update_data.items():
        setattr(company, field, value)
    return CompanyOut.model_validate(company)


# ── Öffentliches QR-Stempel-Token ────────────────────────────────────────────

@router.get("/me/public-stamp-token", response_model=PublicStampTokenStatus)
async def get_public_stamp_token_status(
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    company = await db.get(Company, current_user.company_id)
    return PublicStampTokenStatus(
        enabled=company.public_stamp_enabled,
        configured=company.public_stamp_token_hash is not None,
        created_at=company.public_stamp_token_created_at,
    )


@router.post("/me/public-stamp-token/rotate", response_model=PublicStampTokenRotated)
async def rotate_public_stamp_token(
    request: Request,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    company = await db.get(Company, current_user.company_id)
    token = secrets.token_urlsafe(32)
    company.public_stamp_token_hash = hashlib.sha256(token.encode("utf-8")).hexdigest()
    company.public_stamp_token_created_at = datetime.now(timezone.utc)

    db.add(AuditLog(
        company_id=company.id,
        user_id=current_user.id,
        action="public_stamp_token_rotated",
        entity_type="company",
        entity_id=company.id,
        ip=get_client_ip(request),
    ))
    await db.commit()
    return PublicStampTokenRotated(
        token=token,
        public_url=_public_stamp_url(token),
        created_at=company.public_stamp_token_created_at,
    )


@router.delete("/me/public-stamp-token", status_code=204)
async def delete_public_stamp_token(
    request: Request,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    company = await db.get(Company, current_user.company_id)
    if company.public_stamp_token_hash is None:
        return
    company.public_stamp_token_hash = None
    company.public_stamp_token_created_at = None

    db.add(AuditLog(
        company_id=company.id,
        user_id=current_user.id,
        action="public_stamp_token_revoked",
        entity_type="company",
        entity_id=company.id,
        ip=get_client_ip(request),
    ))
    await db.commit()


# ── Departments ──────────────────────────────────────────────────────────────

@router.get("/me/departments", response_model=list[DepartmentOut])
async def list_departments(current_user: CurrentUser, db: AsyncSession = Depends(get_db)):
    depts = await db.scalars(
        select(Department).where(Department.company_id == current_user.company_id)
    )
    return [DepartmentOut.model_validate(d) for d in depts.all()]


@router.post("/me/departments", response_model=DepartmentOut, status_code=201)
async def create_department(
    data: DepartmentCreate,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    dept = Department(company_id=current_user.company_id, **data.model_dump())
    db.add(dept)
    await db.flush()
    return DepartmentOut.model_validate(dept)


@router.patch("/me/departments/{dept_id}", response_model=DepartmentOut)
async def update_department(
    dept_id: UUID,
    data: DepartmentUpdate,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    dept = await db.get(Department, dept_id)
    if not dept or dept.company_id != current_user.company_id:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="Department not found")
    for field, value in data.model_dump(exclude_none=True).items():
        setattr(dept, field, value)
    return DepartmentOut.model_validate(dept)


@router.delete("/me/departments/{dept_id}", status_code=204)
async def delete_department(
    dept_id: UUID,
    current_user: User = require_role(*_admin_roles),
    db: AsyncSession = Depends(get_db),
):
    dept = await db.get(Department, dept_id)
    if not dept or dept.company_id != current_user.company_id:
        from fastapi import HTTPException
        raise HTTPException(status_code=404, detail="Department not found")
    await db.delete(dept)
