"""Integrations management routes."""

from __future__ import annotations

from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import HTMLResponse
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session

from app.core.db import get_db
from app.services.integrations import oauth as oauth_service
from app.services.integrations import service as integrations_service
from app.services.integrations.errors import IntegrationError

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


class ProviderConfigPayload(BaseModel):
    """Partial provider settings payload."""

    enabled: bool | None = None
    auth_mode: str | None = Field(default=None, min_length=1, max_length=64)
    credentials: dict[str, Any] | None = None
    settings: dict[str, Any] | None = None


class OAuthStartPayload(BaseModel):
    """OAuth start request."""

    open_browser: bool = True
    base_url: str | None = None


class DefaultsPayload(BaseModel):
    """Default provider selections."""

    default_task_provider: str | None = Field(default=None, min_length=1, max_length=64)
    default_notes_provider: str | None = Field(default=None, min_length=1, max_length=64)


def _html_message(title: str, body: str, *, success: bool) -> HTMLResponse:
    color = "#8fd9a0" if success else "#ff9b9b"
    html = (
        "<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'>"
        "<meta name='viewport' content='width=device-width,initial-scale=1'>"
        "<link rel='icon' type='image/png' href='/static/favicon.png'>"
        "<link rel='apple-touch-icon' href='/static/favicon.png'>"
        f"<title>{title}</title>"
        "<style>"
        "body{margin:0;background:#000;color:#f2f2f2;font-family:'SF Pro Text','Segoe UI',sans-serif;display:grid;place-items:center;min-height:100vh;padding:20px;}"
        ".card{max-width:620px;width:100%;border:1px solid rgba(255,255,255,.18);border-radius:18px;padding:22px;background:linear-gradient(180deg,rgba(18,18,18,.92),rgba(8,8,8,.95));}"
        f"h1{{margin:0 0 10px;font-size:1.2rem;color:{color};}}"
        "p{margin:0;line-height:1.5;color:rgba(255,255,255,.78)}"
        "</style></head><body>"
        f"<main class='card'><h1>{title}</h1><p>{body}</p></main>"
        "</body></html>"
    )
    return HTMLResponse(content=html)


def _to_http_error(exc: Exception) -> HTTPException:
    if isinstance(exc, LookupError):
        return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc))
    if isinstance(exc, IntegrationError):
        return HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc))
    return HTTPException(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        detail=str(exc) or "Integration request failed",
    )


@router.get("/status")
def integrations_status() -> dict[str, object]:
    """Return current integrations status payload."""
    return integrations_service.get_integrations_status().as_dict()


@router.post("/defaults")
def set_defaults(payload: DefaultsPayload, db: Session = Depends(get_db)) -> dict[str, object]:
    """Persist default task and notes providers."""
    try:
        result = integrations_service.set_default_providers(
            default_task_provider=payload.default_task_provider,
            default_notes_provider=payload.default_notes_provider,
            db=db,
        )
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    db.commit()
    return result.as_dict()


@router.post("/{provider_id}/save")
def save_provider(
    provider_id: str,
    payload: ProviderConfigPayload,
    db: Session = Depends(get_db),
) -> dict[str, object]:
    """Save one provider config independently."""
    try:
        result = integrations_service.save_provider_config(
            provider_id=provider_id,
            enabled=payload.enabled,
            credentials=payload.credentials,
            settings=payload.settings,
            auth_mode=payload.auth_mode,
            db=db,
        )
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    db.commit()
    return result.as_dict()


@router.post("/{provider_id}/enable")
def enable_provider(provider_id: str, db: Session = Depends(get_db)) -> dict[str, object]:
    """Enable one provider."""
    try:
        result = integrations_service.set_provider_enabled(provider_id, enabled=True, db=db)
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    db.commit()
    return result.as_dict()


@router.post("/{provider_id}/disable")
def disable_provider(provider_id: str, db: Session = Depends(get_db)) -> dict[str, object]:
    """Disable one provider."""
    try:
        result = integrations_service.set_provider_enabled(provider_id, enabled=False, db=db)
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    db.commit()
    return result.as_dict()


@router.post("/{provider_id}/disconnect")
def disconnect_provider(provider_id: str, db: Session = Depends(get_db)) -> dict[str, object]:
    """Remove one provider credentials and disable it."""
    try:
        result = integrations_service.disconnect_provider(provider_id, db=db)
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    db.commit()
    return result.as_dict()


@router.post("/{provider_id}/test")
def test_provider(provider_id: str, db: Session = Depends(get_db)) -> dict[str, object]:
    """Run provider connectivity check."""
    try:
        result = integrations_service.test_provider(provider_id, db=db)
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    return {"ok": bool(result.ok), "detail": result.detail, "provider": provider_id}


@router.post("/oauth/start/{provider_id}")
def oauth_start(
    provider_id: str,
    request: Request,
    payload: OAuthStartPayload | None = None,
) -> dict[str, object]:
    """Start OAuth flow for supported providers."""
    body = payload or OAuthStartPayload()
    base_url = body.base_url or str(request.base_url).rstrip("/")
    try:
        result = oauth_service.start_oauth(
            provider_id,
            base_url=base_url,
            open_browser=body.open_browser,
        )
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        raise _to_http_error(exc) from exc
    return {"ok": True, **result.as_dict()}


@router.get("/oauth/callback/{provider_id}", response_class=HTMLResponse)
def oauth_callback(
    provider_id: str,
    request: Request,
    code: str | None = None,
    state: str | None = None,
    error: str | None = None,
    error_description: str | None = None,
    db: Session = Depends(get_db),
) -> HTMLResponse:
    """OAuth callback endpoint for provider authorization code exchange."""
    if error:
        detail = str(error_description or error).strip()
        return _html_message("OAuth Connection Failed", detail or "Authorization failed.", success=False)

    try:
        result = oauth_service.complete_oauth_callback(
            provider_id=provider_id,
            state=state or "",
            code=code or "",
            db=db,
        )
    except Exception as exc:  # pragma: no cover - defensive runtime branch
        return _html_message("OAuth Connection Failed", str(exc), success=False)

    db.commit()
    detail = result.detail
    if result.settings_applied:
        applied = ", ".join(f"{key}={value}" for key, value in result.settings_applied.items())
        detail = f"{detail}. Applied defaults: {applied}."
    return _html_message("OAuth Connected", detail, success=True)
