"""
PLG segmentation and decision queue admin endpoints.
"""

from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

from fastapi import APIRouter, Body, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from ...auth_security import AdminContext, require_admin
from ...db import get_session
from ...models import Account, AccountLifecycle
from ...services.admin_audit import log_admin_action
from ...services.plg_segments_service import PLGSegmentsService

router = APIRouter(prefix="/admin/plg", tags=["Admin PLG"])


class LifecycleOverridePayload(BaseModel):
    lifecycle_stage_override: Optional[str] = None
    health_score_override: Optional[int] = Field(default=None, ge=0, le=100)
    tags: Optional[List[str]] = None


class NotePayload(BaseModel):
    note: str


@router.get("/segments")
async def list_segments(
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
    page: int = Query(1, ge=1),
    limit: int = Query(50, ge=1, le=200),
    search: Optional[str] = Query(None),
    tier: Optional[str] = Query(None),
    lifecycle_stage: Optional[str] = Query(None),
    min_health: Optional[int] = Query(None, ge=0, le=100),
    max_health: Optional[int] = Query(None, ge=0, le=100),
    has_sfdc: Optional[bool] = Query(None),
    has_automation: Optional[bool] = Query(None),
    has_byo: Optional[bool] = Query(None),
) -> Dict[str, Any]:
    service = PLGSegmentsService(db)
    payload = await service.list_segments(
        page=page,
        limit=limit,
        search=search,
        tier=tier,
        lifecycle_stage=lifecycle_stage,
        min_health=min_health,
        max_health=max_health,
        has_sfdc=has_sfdc,
        has_automation=has_automation,
        has_byo=has_byo,
    )

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_list_segments",
        db=db,
        details={"page": page, "limit": limit, "tier": tier, "stage": lifecycle_stage},
    )

    return payload


@router.get("/segments/{account_id}")
async def get_segment_detail(
    account_id: str,
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
) -> Dict[str, Any]:
    service = PLGSegmentsService(db)
    detail = await service.get_segment_detail(account_id)
    if detail is None:
        raise HTTPException(404, f"Account {account_id} not found")

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_view_segment",
        db=db,
        target_account_id=account_id,
    )

    return detail


@router.get("/decision-queue")
async def get_decision_queue(
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
    days: int = Query(30, ge=1, le=365),
    limit: int = Query(50, ge=1, le=200),
) -> Dict[str, Any]:
    service = PLGSegmentsService(db)
    payload = await service.get_decision_queue(days=days, limit=limit)

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_decision_queue",
        db=db,
        details={"days": days, "limit": limit},
    )

    return payload


@router.get("/renewals")
async def get_renewals(
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
    days_ahead: int = Query(90, ge=1, le=365),
    limit: int = Query(100, ge=1, le=500),
) -> Dict[str, Any]:
    service = PLGSegmentsService(db)
    payload = await service.get_renewal_forecast(days_ahead=days_ahead, limit=limit)

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_renewals",
        db=db,
        details={"days_ahead": days_ahead, "limit": limit},
    )

    return payload


@router.patch("/segments/{account_id}/override")
async def update_lifecycle_override(
    account_id: str,
    payload: LifecycleOverridePayload = Body(...),
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
) -> Dict[str, Any]:
    account_exists = await db.scalar(select(Account.id).where(Account.id == account_id))
    if not account_exists:
        raise HTTPException(404, f"Account {account_id} not found")

    lifecycle = await db.get(AccountLifecycle, account_id)
    if not lifecycle:
        lifecycle = AccountLifecycle(account_id=account_id)

    update_data = payload.dict(exclude_unset=True)
    for key, value in update_data.items():
        setattr(lifecycle, key, value)

    lifecycle.updated_by = admin_ctx.email or admin_ctx.user_id
    lifecycle.updated_at = datetime.now(timezone.utc)

    db.add(lifecycle)
    await db.commit()
    await db.refresh(lifecycle)

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_update_override",
        db=db,
        target_account_id=account_id,
        details=update_data,
    )

    return {
        "account_id": account_id,
        "lifecycle_stage_override": lifecycle.lifecycle_stage_override,
        "health_score_override": lifecycle.health_score_override,
        "tags": lifecycle.tags or [],
        "updated_by": lifecycle.updated_by,
        "updated_at": lifecycle.updated_at.isoformat() if lifecycle.updated_at else None,
    }


@router.post("/segments/{account_id}/notes")
async def add_segment_note(
    account_id: str,
    payload: NotePayload = Body(...),
    admin_ctx: AdminContext = Depends(require_admin),
    db: AsyncSession = Depends(get_session),
) -> Dict[str, Any]:
    note_text = (payload.note or "").strip()
    if not note_text:
        raise HTTPException(400, "Note cannot be empty")

    account_exists = await db.scalar(select(Account.id).where(Account.id == account_id))
    if not account_exists:
        raise HTTPException(404, f"Account {account_id} not found")

    lifecycle = await db.get(AccountLifecycle, account_id)
    if not lifecycle:
        lifecycle = AccountLifecycle(account_id=account_id)

    timestamp = datetime.now(timezone.utc).isoformat()
    entry = f"[{timestamp}] {admin_ctx.email or admin_ctx.user_id}: {note_text}"
    lifecycle.notes = f"{lifecycle.notes}\n{entry}" if lifecycle.notes else entry
    lifecycle.updated_by = admin_ctx.email or admin_ctx.user_id
    lifecycle.updated_at = datetime.now(timezone.utc)

    db.add(lifecycle)
    await db.commit()
    await db.refresh(lifecycle)

    await log_admin_action(
        admin_user_id=admin_ctx.user_id,
        admin_email=admin_ctx.email or "unknown",
        action="plg_add_note",
        db=db,
        target_account_id=account_id,
        details={"note": note_text},
    )

    return {
        "account_id": account_id,
        "notes": lifecycle.notes,
        "updated_by": lifecycle.updated_by,
        "updated_at": lifecycle.updated_at.isoformat() if lifecycle.updated_at else None,
    }
