"""Auth-Router: Magic-Link-Login und Nutzerverwaltung."""
import logging
import os
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, Request, status


def _staging_mode() -> bool:
    """STAGING_MODE Env-Flag (vgl. services.license_service)."""
    return os.environ.get("STAGING_MODE", "").lower() in ("1", "true", "yes")
from models import (
    MagicLinkRequest,
    MagicLinkResponse,
    VerifyTokenRequest,
    TokenResponse,
    UserMeResponse,
)
from auth import (
    create_token,
    get_current_user,
    generate_magic_token,
)
from database import db_dependency
from config import TIMEZONE, MAGIC_LINK_EXPIRE_MINUTES, MAGIC_LINK_BASE_URL
from email_utils.sender import send_email
from email_utils.templates import magic_link_login_email
from email_utils.rate_limiter import magic_link_limiter
import aiosqlite

logger = logging.getLogger("osint.auth")

router = APIRouter(prefix="/api/auth", tags=["auth"])


@router.post("/magic-link", response_model=MagicLinkResponse)
async def request_magic_link(
    data: MagicLinkRequest,
    request: Request,
    db: aiosqlite.Connection = Depends(db_dependency),
):
    """Magic Link anfordern. Sendet E-Mail mit Link."""
    email = data.email.lower().strip()
    ip = request.client.host if request.client else "unknown"

    # Rate-Limit prüfen
    allowed, reason = magic_link_limiter.check(email, ip)
    if not allowed:
        logger.warning(f"Rate-Limit für {email} von {ip}: {reason}")
        return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")

    # Nutzer suchen
    cursor = await db.execute(
        """SELECT u.id, u.email, u.username, u.role, u.organization_id, u.is_active,
                  o.is_active as org_active, o.slug as org_slug
           FROM users u
           JOIN organizations o ON o.id = u.organization_id
           WHERE LOWER(u.email) = ?""",
        (email,),
    )
    user = await cursor.fetchone()

    if not user:
        magic_link_limiter.record(email, ip)
        return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")

    if not user["is_active"]:
        magic_link_limiter.record(email, ip)
        return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")

    if not user["org_active"]:
        magic_link_limiter.record(email, ip)
        return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")

    # Lizenz prüfen
    from services.license_service import check_license
    lic = await check_license(db, user["organization_id"])
    if lic.get("status") == "org_disabled":
        magic_link_limiter.record(email, ip)
        return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")

    # Token generieren
    token = generate_magic_token()
    expires_at = (datetime.now(TIMEZONE) + timedelta(minutes=MAGIC_LINK_EXPIRE_MINUTES)).strftime('%Y-%m-%d %H:%M:%S')

    # Alte ungenutzte Magic Links für diese E-Mail invalidieren
    await db.execute(
        "UPDATE magic_links SET is_used = 1 WHERE email = ? AND is_used = 0",
        (email,),
    )

    # Neuen Magic Link speichern
    await db.execute(
        """INSERT INTO magic_links (email, token, code, purpose, user_id, expires_at, ip_address)
           VALUES (?, ?, '', 'login', ?, ?, ?)""",
        (email, token, user["id"], expires_at, ip),
    )
    await db.commit()

    # E-Mail senden -- Sprache aus Org-Settings des Users
    link = f"{MAGIC_LINK_BASE_URL}/?token={token}"
    from services.org_settings import get_org_language
    org_lang_iso = await get_org_language(db, user["organization_id"])
    subject, html = magic_link_login_email(user["email"].split("@")[0], link, lang=org_lang_iso)
    await send_email(email, subject, html)

    magic_link_limiter.record(email, ip)
    return MagicLinkResponse(message="Wenn ein Konto existiert, wurde eine E-Mail gesendet.")


@router.post("/verify", response_model=TokenResponse)
async def verify_magic_link(
    data: VerifyTokenRequest,
    db: aiosqlite.Connection = Depends(db_dependency),
):
    """Magic Link verifizieren (Token aus URL)."""
    cursor = await db.execute(
        """SELECT ml.*, u.username, u.email, u.role, u.organization_id, u.is_active,
                  o.slug as org_slug, o.is_active as org_active
           FROM magic_links ml
           JOIN users u ON u.id = ml.user_id
           JOIN organizations o ON o.id = u.organization_id
           WHERE ml.token = ? AND ml.is_used = 0""",
        (data.token,),
    )
    ml = await cursor.fetchone()

    if not ml:
        raise HTTPException(status_code=400, detail="Ungültiger oder bereits verwendeter Link")

    # Ablauf prüfen
    now = datetime.now(TIMEZONE)
    expires = datetime.fromisoformat(ml["expires_at"])
    if expires.tzinfo is None:
        expires = expires.replace(tzinfo=TIMEZONE)
    if now > expires:
        raise HTTPException(status_code=400, detail="Link abgelaufen. Bitte neuen Link anfordern.")

    if not ml["is_active"] or not ml["org_active"]:
        raise HTTPException(status_code=403, detail="Konto oder Organisation deaktiviert")

    # Magic Link als verwendet markieren
    await db.execute("UPDATE magic_links SET is_used = 1 WHERE id = ?", (ml["id"],))

    # Letzten Login aktualisieren
    await db.execute(
        "UPDATE users SET last_login_at = ? WHERE id = ?",
        (now.isoformat(), ml["user_id"]),
    )
    await db.commit()

    # Global-Admin-Flag aus DB lesen
    ga_cursor = await db.execute(
        "SELECT is_global_admin FROM users WHERE id = ?", (ml["user_id"],)
    )
    ga_row = await ga_cursor.fetchone()
    _is_global_admin = bool(ga_row["is_global_admin"]) if ga_row else False

    # JWT erstellen
    token = create_token(
        user_id=ml["user_id"],
        username=ml["username"],
        email=ml["email"],
        role=ml["role"],
        tenant_id=ml["organization_id"],
        org_slug=ml["org_slug"],
        is_global_admin=_is_global_admin,
    )

    return TokenResponse(
        access_token=token,
        username=ml["username"],
    )


@router.get("/me", response_model=UserMeResponse)
async def get_me(
    current_user: dict = Depends(get_current_user),
    db: aiosqlite.Connection = Depends(db_dependency),
):
    """Aktuellen Nutzer mit Org-Info abfragen."""
    # Org-Name laden
    org_name = ""
    if current_user.get("tenant_id"):
        cursor = await db.execute(
            "SELECT name FROM organizations WHERE id = ?",
            (current_user["tenant_id"],),
        )
        org = await cursor.fetchone()
        if org:
            org_name = org["name"]

    # Lizenzstatus laden
    license_info = {}
    if current_user.get("tenant_id"):
        from services.license_service import check_license
        license_info = await check_license(db, current_user["tenant_id"])

    # Guthaben-Daten aus der Lizenzpruefung uebernehmen. check_license() hat den
    # Periodenwechsel bereits nachgeholt, ein zweiter Griff in die Tabelle wuerde
    # nur dieselben Werte noch einmal lesen.
    credits_total = None
    credits_remaining = None
    credits_percent_used = None
    credits_period = None
    unlimited_budget = bool(license_info.get("unlimited_budget", False))
    if current_user.get("tenant_id") and license_info.get("credits_available"):
        # Verfuegbar ist Kontingent plus Uebertrag, danach richtet sich auch der
        # Hard-Stop. Die Anzeige muss dieselbe Bezugsgroesse nutzen.
        credits_total = int(license_info["credits_available"])
        credits_used = license_info.get("credits_used") or 0
        credits_period = license_info.get("credits_period")
        credits_remaining = max(0, int(credits_total - credits_used))
        credits_percent_used = round((credits_used / credits_total) * 100, 1) if credits_total > 0 else 0

    # Org-Switcher fuer Global-Admins -- auch auf Staging aktiv, damit eng_demo
    # und andere Sprach-/Demo-Mandanten via Dropdown erreichbar sind. (Vorherige
    # STAGING_MODE-Suppression wurde 2026-05-13 zurueckgenommen.)
    is_global_admin_response = current_user.get("is_global_admin", False)

    # Org-Sprache fuer Frontend-i18n
    output_language_iso = "de"
    if current_user.get("tenant_id"):
        from services.org_settings import get_org_language
        output_language_iso = await get_org_language(db, current_user["tenant_id"])

    return UserMeResponse(
        id=current_user["id"],
        username=current_user["username"],
        email=current_user.get("email", ""),
        credits_total=credits_total,
        credits_remaining=credits_remaining,
        credits_percent_used=credits_percent_used,
        role=current_user["role"],
        org_name=org_name,
        org_slug=current_user.get("org_slug", ""),
        tenant_id=current_user.get("tenant_id"),
        license_status=license_info.get("status", "unknown"),
        license_type=license_info.get("license_type", ""),
        read_only=license_info.get("read_only", False),
        read_only_reason=license_info.get("read_only_reason"),
        unlimited_budget=unlimited_budget,
        is_global_admin=is_global_admin_response,
        output_language=output_language_iso,
        credits_period=credits_period,
    )


# --- Global Admin: Org-Wechsel (herausnehmbar) ---

from models import SwitchOrgRequest, OrgListItem


@router.get("/organizations")
async def list_all_organizations(
    current_user: dict = Depends(get_current_user),
    db: aiosqlite.Connection = Depends(db_dependency),
):
    """Alle Organisationen auflisten (nur fuer Global Admin)."""
    if not current_user.get("is_global_admin"):
        raise HTTPException(status_code=403, detail="Keine Berechtigung")

    cursor = await db.execute(
        "SELECT id, name, slug, is_active FROM organizations ORDER BY name"
    )
    rows = await cursor.fetchall()
    return [dict(row) for row in rows]


@router.post("/switch-org")
async def switch_organization(
    data: SwitchOrgRequest,
    current_user: dict = Depends(get_current_user),
    db: aiosqlite.Connection = Depends(db_dependency),
):
    """Organisation wechseln (nur fuer Global Admin). Gibt neues JWT zurueck."""
    if not current_user.get("is_global_admin"):
        raise HTTPException(status_code=403, detail="Keine Berechtigung")

    # Ziel-Org pruefen
    cursor = await db.execute(
        "SELECT id, name, slug FROM organizations WHERE id = ?", (data.organization_id,)
    )
    org = await cursor.fetchone()
    if not org:
        raise HTTPException(status_code=404, detail="Organisation nicht gefunden")

    # Neues JWT mit anderem tenant_id ausstellen
    token = create_token(
        user_id=current_user["id"],
        username=current_user["username"],
        email=current_user["email"],
        role=current_user["role"],
        tenant_id=org["id"],
        org_slug=org["slug"],
        is_global_admin=True,
    )

    return {
        "access_token": token,
        "token_type": "bearer",
        "org_name": org["name"],
        "org_slug": org["slug"],
    }
