"""Notifications and support endpoints."""

from datetime import datetime, timezone
from typing import Dict, Literal, Optional

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

from ..database import get_session
from ..models import AdminConfig
from ..security import require_roles
from ..utils import log_action

router = APIRouter()

TEMPLATE_PREFIX = "email_template_"
SLACK_CONFIG_KEY = "notification_slack_alerts"


class SlackWebhookSettings(BaseModel):
    """Payload for configuring the Slack webhook used for high severity alerts."""

    webhook_url: str = Field(..., min_length=10)
    channel: str = Field(default="#alerts", min_length=1, max_length=80)
    is_enabled: bool = True
    severity_threshold: Literal["info", "warning", "critical"] = "critical"
    username: Optional[str] = None
    icon_emoji: Optional[str] = None

    def validate_url(self) -> None:
        if not self.webhook_url.startswith("https://"):
            raise HTTPException(status_code=400, detail="URL Slack invalide")


class SlackWebhookState(SlackWebhookSettings):
    updated_at: Optional[str] = None
    last_test_at: Optional[str] = None
    last_test_status: Optional[str] = None
    last_test_message: Optional[str] = None


class SlackTestPayload(BaseModel):
    message: Optional[str] = None
    severity: Literal["info", "warning", "critical"] = "critical"


class SlackTestResponse(BaseModel):
    status: str
    tested_at: str
    severity: Literal["info", "warning", "critical"]
    preview: str


def _get_slack_config(session) -> Optional[AdminConfig]:
    return session.query(AdminConfig).filter(AdminConfig.key == SLACK_CONFIG_KEY).first()


def _normalise_slack_state(raw: Optional[Dict]) -> SlackWebhookState:
    if not raw:
        raise HTTPException(status_code=404, detail="Webhook Slack non configuré")
    kwargs = {
        "webhook_url": raw.get("webhook_url", ""),
        "channel": raw.get("channel", "#alerts"),
        "is_enabled": raw.get("is_enabled", False),
        "severity_threshold": raw.get("severity_threshold", "critical"),
        "username": raw.get("username"),
        "icon_emoji": raw.get("icon_emoji"),
        "updated_at": raw.get("updated_at"),
        "last_test_at": raw.get("last_test_at"),
        "last_test_status": raw.get("last_test_status"),
        "last_test_message": raw.get("last_test_message"),
    }
    if not kwargs["webhook_url"]:
        raise HTTPException(status_code=404, detail="Webhook Slack non configuré")
    return SlackWebhookState(**kwargs)


@router.get("/templates")
def list_templates(session=Depends(get_session), _admin=Depends(require_roles("super-admin", "analyst"))):
    rows = session.query(AdminConfig).filter(AdminConfig.key.like(f"{TEMPLATE_PREFIX}%")).all()
    return {row.key[len(TEMPLATE_PREFIX):]: row.value for row in rows}


@router.put("/templates/{name}")
def update_template(name: str, payload: Dict, session=Depends(get_session), _admin=Depends(require_roles("super-admin"))):
    key = f"{TEMPLATE_PREFIX}{name}"
    config = session.query(AdminConfig).filter(AdminConfig.key == key).first()
    if config:
        config.value = payload
    else:
        config = AdminConfig(key=key, value=payload)
        session.add(config)
    log_action(session, _admin.email, "notification_template", target=name, metadata=payload)
    session.commit()
    return {"template": name, "value": payload}


@router.get("/webhooks/slack", response_model=SlackWebhookState)
def get_slack_webhook(session=Depends(get_session), _admin=Depends(require_roles("super-admin", "analyst"))):
    config = _get_slack_config(session)
    if not config:
        raise HTTPException(status_code=404, detail="Webhook Slack non configuré")
    return _normalise_slack_state(config.value)


@router.put("/webhooks/slack", response_model=SlackWebhookState)
def configure_slack_webhook(
    payload: SlackWebhookSettings,
    session=Depends(get_session),
    _admin=Depends(require_roles("super-admin")),
):
    payload.validate_url()
    now = datetime.now(timezone.utc).isoformat()

    config = _get_slack_config(session)
    base_value = dict(config.value) if config and config.value else {}
    merged = {
        **base_value,
        **payload.model_dump(),
        "updated_at": now,
    }
    if config:
        config.value = merged
    else:
        config = AdminConfig(key=SLACK_CONFIG_KEY, value=merged)
        session.add(config)

    log_action(session, _admin.email, "notification_slack_config", metadata=payload.model_dump())
    session.commit()
    return _normalise_slack_state(config.value)  # type: ignore[arg-type]


@router.post("/webhooks/slack/test", response_model=SlackTestResponse)
def test_slack_webhook(
    payload: SlackTestPayload,
    session=Depends(get_session),
    _admin=Depends(require_roles("super-admin")),
):
    config = _get_slack_config(session)
    if not config or not config.value or not config.value.get("webhook_url"):
        raise HTTPException(status_code=400, detail="Webhook Slack non configuré")
    state = _normalise_slack_state(config.value)
    if not state.is_enabled:
        raise HTTPException(status_code=400, detail="Webhook Slack désactivé")

    message = payload.message or "Test d'alerte critique Web Sentinel"
    tested_at = datetime.now(timezone.utc).isoformat()
    log_action(
        session,
        _admin.email,
        "notification_slack_test",
        metadata={
            "severity": payload.severity,
            "message": message,
            "channel": state.channel,
        },
    )

    updated_value = state.model_dump()
    updated_value.update(
        {
            "last_test_at": tested_at,
            "last_test_status": "simulated",
            "last_test_message": message,
        }
    )
    if config:
        config.value = updated_value
        session.add(config)
    session.commit()

    return SlackTestResponse(status="simulated", tested_at=tested_at, severity=payload.severity, preview=message)


@router.post("/support/ticket", status_code=202)
def create_support_ticket(payload: Dict, session=Depends(get_session), _admin=Depends(require_roles("support", "super-admin"))):
    if "email" not in payload or "subject" not in payload:
        raise HTTPException(status_code=400, detail="email et subject requis")
    log_action(session, _admin.email, "support_ticket", metadata=payload)
    session.commit()
    return {"message": "Ticket enregistré"}
