"""Settings API — email accounts stored in PostgreSQL."""

from __future__ import annotations

import smtplib
import json
from datetime import datetime
from email.mime.text import MIMEText
from typing import Any, Optional

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field

from app.db import execute, fetch_all, fetch_one
from app.services import agent_souls
from app.services.social_publish import PLATFORMS, get_integration, test_connection

settings_router = APIRouter(prefix="/api/settings", tags=["settings"])


class EmailAccountBody(BaseModel):
    label: str = Field(..., max_length=128)
    email_address: str = Field(..., max_length=255)
    provider: str = Field(default="custom", max_length=32)
    is_active: bool = False
    smtp_host: Optional[str] = None
    smtp_port: int = 587
    smtp_user: Optional[str] = None
    smtp_password: Optional[str] = None
    imap_host: Optional[str] = None
    imap_port: int = 993
    imap_user: Optional[str] = None
    imap_password: Optional[str] = None
    sync_enabled: bool = False


def _mask_account(row: dict[str, Any] | None) -> dict[str, Any] | None:
    if not row:
        return None
    out = dict(row)
    for k, v in list(out.items()):
        if hasattr(v, "isoformat"):
            out[k] = v.isoformat()
    out["smtp_password_set"] = bool(row.get("smtp_password"))
    out["imap_password_set"] = bool(row.get("imap_password"))
    out.pop("smtp_password", None)
    out.pop("imap_password", None)
    return out


def _deactivate_all() -> None:
    execute("UPDATE email_accounts SET is_active = FALSE, updated_at = NOW() WHERE is_active = TRUE")


def _test_smtp_config(
    smtp_host: str,
    smtp_port: int,
    smtp_user: str,
    smtp_pass: str,
    from_addr: str,
) -> tuple[bool, str]:
    if not smtp_host or not from_addr:
        return False, "SMTP host en from-adres zijn verplicht"
    try:
        msg = MIMEText("Foodlinkk SMTP test — Herman email settings OK.", "plain", "utf-8")
        msg["Subject"] = "Foodlinkk test email"
        msg["From"] = from_addr
        msg["To"] = from_addr
        with smtplib.SMTP(smtp_host, smtp_port, timeout=25) as server:
            server.ehlo()
            if smtp_port == 587:
                server.starttls()
            if smtp_user and smtp_pass:
                server.login(smtp_user, smtp_pass)
            server.sendmail(from_addr, [from_addr], msg.as_string())
        return True, f"Testmail verstuurd naar {from_addr}"
    except Exception as exc:
        return False, str(exc)


def _resolve_password(new: Optional[str], existing: Optional[str]) -> Optional[str]:
    if new is not None and new != "":
        return new
    return existing


SOCIAL_PLATFORM_FIELDS: dict[str, tuple[str, ...]] = {
    "twitter": ("api_key", "api_secret", "access_token", "access_secret"),
    "linkedin": ("access_token", "person_urn"),
    "instagram": ("access_token", "page_id"),
    "facebook": ("access_token", "page_id"),
    "tiktok": ("access_token", "open_id"),
    "pinterest": ("access_token", "board_id"),
}

SOCIAL_SECRET_FIELDS = {"api_secret", "access_secret", "access_token", "api_key"}


class SocialIntegrationBody(BaseModel):
    api_key: Optional[str] = None
    api_secret: Optional[str] = None
    access_token: Optional[str] = None
    access_secret: Optional[str] = None
    person_urn: Optional[str] = None
    page_id: Optional[str] = None
    open_id: Optional[str] = None
    board_id: Optional[str] = None
    is_active: Optional[bool] = None


def _mask_social_row(row: dict[str, Any] | None) -> dict[str, Any] | None:
    if not row:
        return None
    out = dict(row)
    for k, v in list(out.items()):
        if hasattr(v, "isoformat"):
            out[k] = v.isoformat()
    config = out.get("config") or {}
    if isinstance(config, str):
        try:
            config = json.loads(config)
        except Exception:
            config = {}
    if not isinstance(config, dict):
        config = {}
    masked = dict(config)
    for key in SOCIAL_SECRET_FIELDS:
        if key in config:
            masked[f"{key}_set"] = bool(config.get(key))
            masked.pop(key, None)
    out["config"] = masked
    return out


def _normalize_social_platform(platform: str) -> str:
    value = (platform or "").strip().lower()
    if value not in PLATFORMS:
        raise HTTPException(status_code=400, detail=f"Unsupported platform: {platform}")
    return value


@settings_router.get("/email")
def list_email_accounts() -> dict[str, Any]:
    try:
        rows = fetch_all("SELECT * FROM email_accounts ORDER BY is_active DESC, updated_at DESC")
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc
    return {"accounts": [_mask_account(r) for r in rows]}


@settings_router.post("/email")
def create_email_account(body: EmailAccountBody) -> dict[str, Any]:
    if body.is_active:
        _deactivate_all()
    try:
        row = fetch_one(
            """
            INSERT INTO email_accounts (
                label, email_address, provider, is_active,
                smtp_host, smtp_port, smtp_user, smtp_password,
                imap_host, imap_port, imap_user, imap_password, sync_enabled
            ) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
            RETURNING *
            """,
            (
                body.label,
                body.email_address,
                body.provider,
                body.is_active,
                body.smtp_host,
                body.smtp_port,
                body.smtp_user or body.email_address,
                body.smtp_password or "",
                body.imap_host,
                body.imap_port,
                body.imap_user or body.email_address,
                body.imap_password or "",
                body.sync_enabled,
            ),
        )
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc
    return {"ok": True, "account": _mask_account(row)}


@settings_router.put("/email/{account_id}")
def update_email_account(account_id: int, body: EmailAccountBody) -> dict[str, Any]:
    existing = fetch_one("SELECT * FROM email_accounts WHERE id = %s", (account_id,))
    if not existing:
        raise HTTPException(status_code=404, detail="Account not found")
    if body.is_active:
        _deactivate_all()
    smtp_pass = _resolve_password(body.smtp_password, existing.get("smtp_password"))
    imap_pass = _resolve_password(body.imap_password, existing.get("imap_password"))
    try:
        row = fetch_one(
            """
            UPDATE email_accounts SET
                label=%s, email_address=%s, provider=%s, is_active=%s,
                smtp_host=%s, smtp_port=%s, smtp_user=%s, smtp_password=%s,
                imap_host=%s, imap_port=%s, imap_user=%s, imap_password=%s,
                sync_enabled=%s, updated_at=NOW()
            WHERE id=%s RETURNING *
            """,
            (
                body.label,
                body.email_address,
                body.provider,
                body.is_active,
                body.smtp_host,
                body.smtp_port,
                body.smtp_user or body.email_address,
                smtp_pass,
                body.imap_host,
                body.imap_port,
                body.imap_user or body.email_address,
                imap_pass,
                body.sync_enabled,
                account_id,
            ),
        )
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc)) from exc
    return {"ok": True, "account": _mask_account(row)}


@settings_router.delete("/email/{account_id}")
def delete_email_account(account_id: int) -> dict[str, Any]:
    execute("DELETE FROM email_accounts WHERE id = %s", (account_id,))
    return {"ok": True}


@settings_router.post("/email/{account_id}/activate")
def activate_email_account(account_id: int) -> dict[str, Any]:
    existing = fetch_one("SELECT id FROM email_accounts WHERE id = %s", (account_id,))
    if not existing:
        raise HTTPException(status_code=404, detail="Account not found")
    _deactivate_all()
    row = fetch_one(
        "UPDATE email_accounts SET is_active=TRUE, updated_at=NOW() WHERE id=%s RETURNING *",
        (account_id,),
    )
    return {"ok": True, "account": _mask_account(row)}


@settings_router.post("/email/{account_id}/test")
def test_saved_email_account(account_id: int) -> dict[str, Any]:
    row = fetch_one("SELECT * FROM email_accounts WHERE id = %s", (account_id,))
    if not row:
        raise HTTPException(status_code=404, detail="Account not found")
    ok, message = _test_smtp_config(
        row.get("smtp_host") or "",
        int(row.get("smtp_port") or 587),
        row.get("smtp_user") or row.get("email_address") or "",
        row.get("smtp_password") or "",
        row.get("email_address") or row.get("smtp_user") or "",
    )
    status = "ok" if ok else "failed"
    execute(
        """
        UPDATE email_accounts SET last_test_at=NOW(), last_test_status=%s, last_test_message=%s, updated_at=NOW()
        WHERE id=%s
        """,
        (status, message[:500], account_id),
    )
    return {"ok": ok, "message": message}


@settings_router.post("/email/test")
def test_email_config(body: EmailAccountBody) -> dict[str, Any]:
    """Test SMTP without saving (form preview)."""
    if not body.smtp_password:
        raise HTTPException(status_code=400, detail="SMTP wachtwoord is verplicht voor test zonder opgeslagen account")
    ok, message = _test_smtp_config(
        body.smtp_host or "",
        body.smtp_port,
        body.smtp_user or body.email_address,
        body.smtp_password,
        body.email_address,
    )
    return {"ok": ok, "message": message}


@settings_router.get("/social")
def list_social_integrations() -> dict[str, Any]:
    rows = fetch_all("SELECT * FROM social_integrations ORDER BY platform")
    return {"items": [_mask_social_row(r) for r in rows], "platforms": list(PLATFORMS)}


@settings_router.put("/social/{platform}")
def save_social_integration(platform: str, body: SocialIntegrationBody) -> dict[str, Any]:
    platform = _normalize_social_platform(platform)
    allowed_fields = set(SOCIAL_PLATFORM_FIELDS[platform])
    incoming = body.model_dump(exclude_none=True)
    existing = fetch_one("SELECT * FROM social_integrations WHERE platform = %s", (platform,))

    existing_config = {}
    if existing:
        existing_config = existing.get("config") or {}
        if isinstance(existing_config, str):
            try:
                existing_config = json.loads(existing_config)
            except Exception:
                existing_config = {}
        if not isinstance(existing_config, dict):
            existing_config = {}

    config = dict(existing_config)
    for field in allowed_fields:
        if field not in incoming:
            continue
        value = incoming.get(field)
        if field in SOCIAL_SECRET_FIELDS:
            if value is not None and value != "":
                config[field] = value
        else:
            config[field] = value

    is_active = body.is_active
    if is_active is None:
        is_active = bool(existing.get("is_active")) if existing else True

    row = fetch_one(
        """
        INSERT INTO social_integrations (platform, config, is_active, updated_at)
        VALUES (%s, %s::jsonb, %s, NOW())
        ON CONFLICT (platform) DO UPDATE SET
            config = EXCLUDED.config,
            is_active = EXCLUDED.is_active,
            updated_at = NOW()
        RETURNING *
        """,
        (platform, json.dumps(config), is_active),
    )
    return {"ok": True, "integration": _mask_social_row(row)}


@settings_router.post("/social/{platform}/test")
def test_social_integration(platform: str) -> dict[str, Any]:
    platform = _normalize_social_platform(platform)
    integration = get_integration(platform)
    if not integration:
        raise HTTPException(status_code=404, detail="Integration not configured")
    result = test_connection(platform, integration)
    status = "ok" if result.get("ok") else "failed"
    message = (result.get("message") or result.get("error") or "")[:500]
    try:
        execute(
            """
            UPDATE social_integrations
            SET last_test_at=NOW(), last_test_status=%s, last_test_message=%s, updated_at=NOW()
            WHERE platform=%s
            """,
            (status, message, platform),
        )
    except Exception:
        pass
    return {"platform": platform, **result}


class PermissionBody(BaseModel):
    granted: bool


@settings_router.get("/permissions")
def list_permissions() -> dict[str, Any]:
    items = agent_souls.list_permissions()
    granted = sum(1 for i in items if i.get("granted"))
    return {"items": items, "granted_count": granted, "total": len(items)}


@settings_router.put("/permissions/{module_key}")
def update_permission(module_key: str, body: PermissionBody) -> dict[str, Any]:
    row = agent_souls.update_permission(module_key, body.granted)
    if not row:
        raise HTTPException(404, "Module not found")
    return {"permission": row}


@settings_router.post("/permissions/grant-all")
def grant_all_permissions() -> dict[str, Any]:
    n = agent_souls.grant_all_permissions()
    return {"ok": True, "granted_count": n, "message": f"Herman heeft nu {n} module-rechten"}


# ── LLM providers ──────────────────────────────────────────────────────────

from app.services import llm_router


class LlmProviderBody(BaseModel):
    label: str = Field(..., max_length=128)
    provider_type: str = Field(default="deepseek", max_length=48)
    api_base_url: Optional[str] = None
    api_key: Optional[str] = None
    model: str = Field(default="deepseek-chat", max_length=128)
    is_active: bool = True
    is_default: bool = False
    extra_config: dict[str, Any] = Field(default_factory=dict)


@settings_router.get("/llm/presets")
def llm_presets() -> dict[str, Any]:
    return {"presets": llm_router.list_presets()}


@settings_router.get("/llm")
def llm_list() -> dict[str, Any]:
    items = llm_router.list_providers()
    default = next((i for i in items if i.get("is_default")), items[0] if items else None)
    return {"providers": items, "default": default, "presets": llm_router.list_presets()}


@settings_router.post("/llm")
def llm_create(body: LlmProviderBody) -> dict[str, Any]:
    preset = llm_router.LLM_PRESETS.get(body.provider_type, {})
    base_url = (body.api_base_url or preset.get("api_base_url") or "").strip() or None
    model = body.model or (preset.get("models") or ["deepseek-chat"])[0]
    if body.is_default:
        execute("UPDATE llm_providers SET is_default = FALSE, updated_at = NOW()")
    row = fetch_one(
        """INSERT INTO llm_providers (
            label, provider_type, api_base_url, api_key, model,
            is_active, is_default, extra_config, updated_at
        ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s::jsonb, NOW())
        RETURNING *""",
        (
            body.label,
            body.provider_type,
            base_url,
            body.api_key or "",
            model,
            body.is_active,
            body.is_default,
            json.dumps(body.extra_config or {}),
        ),
    )
    return {"provider": llm_router._mask_provider(row)}


@settings_router.put("/llm/{provider_id}")
def llm_update(provider_id: int, body: LlmProviderBody) -> dict[str, Any]:
    existing = fetch_one("SELECT * FROM llm_providers WHERE id = %s", (provider_id,))
    if not existing:
        raise HTTPException(404, "Provider niet gevonden")
    preset = llm_router.LLM_PRESETS.get(body.provider_type, {})
    base_url = (body.api_base_url or preset.get("api_base_url") or existing.get("api_base_url") or "").strip() or None
    api_key = body.api_key if body.api_key else existing.get("api_key") or ""
    if body.is_default:
        execute("UPDATE llm_providers SET is_default = FALSE, updated_at = NOW()")
    row = fetch_one(
        """UPDATE llm_providers SET
            label = %s, provider_type = %s, api_base_url = %s, api_key = %s, model = %s,
            is_active = %s, is_default = %s, extra_config = %s::jsonb, updated_at = NOW()
        WHERE id = %s RETURNING *""",
        (
            body.label,
            body.provider_type,
            base_url,
            api_key,
            body.model,
            body.is_active,
            body.is_default,
            json.dumps(body.extra_config or {}),
            provider_id,
        ),
    )
    return {"provider": llm_router._mask_provider(row)}


@settings_router.delete("/llm/{provider_id}")
def llm_delete(provider_id: int) -> dict[str, Any]:
    row = fetch_one("SELECT is_default FROM llm_providers WHERE id = %s", (provider_id,))
    if not row:
        raise HTTPException(404, "Provider niet gevonden")
    execute("DELETE FROM llm_providers WHERE id = %s", (provider_id,))
    if row.get("is_default"):
        execute(
            """UPDATE llm_providers SET is_default = TRUE, updated_at = NOW()
               WHERE id = (SELECT id FROM llm_providers ORDER BY id LIMIT 1)"""
        )
    return {"ok": True}


@settings_router.post("/llm/{provider_id}/activate")
def llm_activate(provider_id: int) -> dict[str, Any]:
    llm_router.set_default(provider_id)
    row = fetch_one("SELECT * FROM llm_providers WHERE id = %s", (provider_id,))
    return {"ok": True, "provider": llm_router._mask_provider(row)}


@settings_router.post("/llm/{provider_id}/test")
async def llm_test(provider_id: int) -> dict[str, Any]:
    ok, msg = await llm_router.test_provider(provider_id)
    if not ok:
        raise HTTPException(502, msg)
    return {"ok": True, "message": msg}

