from typing import Annotated
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

from app.auth.deps import CurrentUser, current_user, require_admin
from app.db import get_session
from app.schemas.alert import AlertConfigCreate, AlertConfigOut, AlertConfigUpdate, AlertLogOut

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


def _row_to_cfg(r) -> AlertConfigOut:
    return AlertConfigOut(
        id=r[0], company_id=r[1], type=r[2], target=r[3], enabled=r[4], created_at=r[5],
        kind=r[6] if len(r) > 6 else "process",
    )


@router.get("", response_model=list[AlertConfigOut])
async def list_alerts(
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
    company_id: UUID | None = None,
) -> list[AlertConfigOut]:
    if company_id:
        rows = (
            await session.execute(
                text(
                    """
                    SELECT id::text, company_id::text, type, target, enabled,
                           created_at, kind
                    FROM alerts_config
                    WHERE company_id = :cid OR company_id IS NULL
                    ORDER BY kind, created_at DESC
                    """
                ),
                {"cid": str(company_id)},
            )
        ).all()
    else:
        rows = (
            await session.execute(
                text(
                    """
                    SELECT id::text, company_id::text, type, target, enabled,
                           created_at, kind
                    FROM alerts_config ORDER BY kind, created_at DESC
                    """
                )
            )
        ).all()
    return [_row_to_cfg(r) for r in rows]


@router.post("", response_model=AlertConfigOut, status_code=status.HTTP_201_CREATED)
async def create_alert(
    payload: AlertConfigCreate,
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> AlertConfigOut:
    if payload.type == "email" and "@" not in payload.target:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, "email target must contain @")
    if payload.type == "webhook" and not payload.target.startswith(("http://", "https://")):
        raise HTTPException(status.HTTP_400_BAD_REQUEST, "webhook target must be http(s) URL")
    row = (
        await session.execute(
            text(
                """
                INSERT INTO alerts_config (company_id, type, target, enabled, kind)
                VALUES (:cid, :ty, :tgt, :en, :kind)
                RETURNING id::text, company_id::text, type, target, enabled,
                          created_at, kind
                """
            ),
            {
                "cid": payload.company_id,
                "ty": payload.type,
                "tgt": payload.target,
                "en": payload.enabled,
                "kind": payload.kind,
            },
        )
    ).first()
    await session.commit()
    return _row_to_cfg(row)


@router.patch("/{alert_id}", response_model=AlertConfigOut)
async def update_alert(
    alert_id: UUID,
    payload: AlertConfigUpdate,
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> AlertConfigOut:
    fields = payload.model_dump(exclude_unset=True)
    if not fields:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, "nothing to update")
    sets = ", ".join(f"{k} = :{k}" for k in fields.keys())
    params = {**fields, "id": str(alert_id)}
    row = (
        await session.execute(
            text(
                f"""
                UPDATE alerts_config SET {sets} WHERE id = :id
                RETURNING id::text, company_id::text, type, target, enabled,
                          created_at, kind
                """
            ),
            params,
        )
    ).first()
    if not row:
        raise HTTPException(status.HTTP_404_NOT_FOUND)
    await session.commit()
    return _row_to_cfg(row)


@router.delete("/{alert_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_alert(
    alert_id: UUID,
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> None:
    await session.execute(
        text("DELETE FROM alerts_config WHERE id = :id"), {"id": str(alert_id)}
    )
    await session.commit()


@router.get("/log", response_model=list[AlertLogOut])
async def alert_log(
    session: Annotated[AsyncSession, Depends(get_session)],
    _user: Annotated[CurrentUser, Depends(current_user)],
    limit: int = Query(default=50, ge=1, le=500),
) -> list[AlertLogOut]:
    rows = (
        await session.execute(
            text(
                """
                SELECT id::text, process_id::text, alert_config_id::text,
                       status, response, created_at
                FROM alerts_log ORDER BY created_at DESC LIMIT :lim
                """
            ),
            {"lim": limit},
        )
    ).all()
    return [
        AlertLogOut(
            id=r[0], process_id=r[1], alert_config_id=r[2],
            status=r[3], response=r[4], created_at=r[5],
        )
        for r in rows
    ]
