# @File: backend/routers/bizmail_admin.py
# @Desc: Admin-facing Bizmail360 endpoints — plan CRUD, full list of
#        every client's subscription, force-activate / suspend / cancel,
#        audit log, and a SmarterMail integration test wrapper.
from __future__ import annotations

import logging
from typing import List, Optional

from core.database import get_db
from dependencies.auth import get_admin_user
from fastapi import APIRouter, Depends, HTTPException, Query, status
from models.bizmail import BizmailAuditLog, BizmailPlan
from schemas.auth import UserResponse
from schemas.bizmail import (
    BizmailAuditLogOut,
    BizmailIntegrationTestResult,
    BizmailPlanCreate,
    BizmailPlanOut,
    BizmailPlanUpdate,
    BizmailSubscriptionActionResult,
    BizmailSubscriptionDetail,
)
from services.bizmail.client import probe_connection
from services.bizmail.plans import get_plan, get_plan_by_slug, list_plans
from services.bizmail.subscriptions import (
    activate_subscription,
    cancel_subscription,
    get_subscription,
    list_all_subscriptions,
    plan_for_subscription,
    resume_subscription,
    suspend_subscription,
)
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/admin/bizmail", tags=["bizmail-admin"])


# ---------- Plans ----------
@router.get("/plans", response_model=List[BizmailPlanOut])
async def admin_list_plans(
    include_inactive: bool = Query(True),
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    plans = await list_plans(db, include_inactive=include_inactive)
    return [BizmailPlanOut.model_validate(p) for p in plans]


@router.post(
    "/plans", response_model=BizmailPlanOut, status_code=status.HTTP_201_CREATED
)
async def admin_create_plan(
    payload: BizmailPlanCreate,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    existing = await get_plan_by_slug(db, payload.slug)
    if existing is not None:
        raise HTTPException(status_code=409, detail="Slug already in use.")
    row = BizmailPlan(**payload.model_dump())
    db.add(row)
    await db.commit()
    await db.refresh(row)
    return BizmailPlanOut.model_validate(row)


@router.put("/plans/{plan_id}", response_model=BizmailPlanOut)
async def admin_update_plan(
    plan_id: int,
    payload: BizmailPlanUpdate,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    row = await get_plan(db, plan_id)
    if row is None:
        raise HTTPException(status_code=404, detail="Plan not found.")
    data = payload.model_dump(exclude_unset=True)
    for key, value in data.items():
        setattr(row, key, value)
    await db.commit()
    await db.refresh(row)
    return BizmailPlanOut.model_validate(row)


@router.delete("/plans/{plan_id}", status_code=status.HTTP_204_NO_CONTENT)
async def admin_delete_plan(
    plan_id: int,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    row = await get_plan(db, plan_id)
    if row is None:
        raise HTTPException(status_code=404, detail="Plan not found.")
    # Soft-delete by flipping is_active so existing subscriptions stay valid.
    row.is_active = False
    await db.commit()
    return None


# ---------- Subscriptions ----------
async def _detail(db: AsyncSession, sub) -> BizmailSubscriptionDetail:
    plan = await plan_for_subscription(db, sub)
    detail = BizmailSubscriptionDetail.model_validate(sub)
    if plan is not None:
        detail.plan = BizmailPlanOut.model_validate(plan)
        detail.mailbox_quota = plan.mailbox_quota
        detail.aliases_included = plan.aliases_included
        detail.storage_mb_per_mailbox = plan.storage_mb_per_mailbox
    return detail


@router.get("/subscriptions", response_model=List[BizmailSubscriptionDetail])
async def admin_list_subscriptions(
    status_filter: Optional[str] = Query(None, alias="status"),
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    subs = await list_all_subscriptions(db, status=status_filter)
    return [await _detail(db, s) for s in subs]


@router.post(
    "/subscriptions/{sub_id}/activate",
    response_model=BizmailSubscriptionActionResult,
)
async def admin_activate_subscription(
    sub_id: int,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    sub = await get_subscription(db, sub_id)
    if sub is None:
        raise HTTPException(status_code=404, detail="Subscription not found.")
    plan = await plan_for_subscription(db, sub)
    if plan is None:
        raise HTTPException(status_code=404, detail="Plan not found.")
    try:
        sub, _ = await activate_subscription(
            db, sub, plan=plan, actor_email=current_user.email
        )
    except Exception as exc:  # noqa: BLE001
        raise HTTPException(status_code=502, detail=str(exc)) from exc
    return BizmailSubscriptionActionResult(
        subscription=await _detail(db, sub),
        message="Subscription activated.",
    )


@router.post(
    "/subscriptions/{sub_id}/suspend",
    response_model=BizmailSubscriptionActionResult,
)
async def admin_suspend_subscription(
    sub_id: int,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    sub = await get_subscription(db, sub_id)
    if sub is None:
        raise HTTPException(status_code=404, detail="Subscription not found.")
    sub = await suspend_subscription(db, sub, actor_email=current_user.email)
    return BizmailSubscriptionActionResult(
        subscription=await _detail(db, sub), message="Subscription suspended."
    )


@router.post(
    "/subscriptions/{sub_id}/resume",
    response_model=BizmailSubscriptionActionResult,
)
async def admin_resume_subscription(
    sub_id: int,
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    sub = await get_subscription(db, sub_id)
    if sub is None:
        raise HTTPException(status_code=404, detail="Subscription not found.")
    sub = await resume_subscription(db, sub, actor_email=current_user.email)
    return BizmailSubscriptionActionResult(
        subscription=await _detail(db, sub), message="Subscription resumed."
    )


@router.post(
    "/subscriptions/{sub_id}/cancel",
    response_model=BizmailSubscriptionActionResult,
)
async def admin_cancel_subscription(
    sub_id: int,
    delete_remote: bool = Query(True),
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    sub = await get_subscription(db, sub_id)
    if sub is None:
        raise HTTPException(status_code=404, detail="Subscription not found.")
    sub = await cancel_subscription(
        db, sub, actor_email=current_user.email, delete_remote=delete_remote
    )
    return BizmailSubscriptionActionResult(
        subscription=await _detail(db, sub), message="Subscription cancelled."
    )


# ---------- Audit log ----------
@router.get("/audit-log", response_model=List[BizmailAuditLogOut])
async def admin_audit_log(
    subscription_id: Optional[int] = Query(None),
    limit: int = Query(200, ge=1, le=1000),
    current_user: UserResponse = Depends(get_admin_user),
    db: AsyncSession = Depends(get_db),
):
    stmt = select(BizmailAuditLog)
    if subscription_id is not None:
        stmt = stmt.where(BizmailAuditLog.subscription_id == subscription_id)
    stmt = stmt.order_by(BizmailAuditLog.created_at.desc()).limit(limit)
    rows = (await db.execute(stmt)).scalars().all()
    return [BizmailAuditLogOut.model_validate(r) for r in rows]


# ---------- Integration test ----------
@router.post("/integration/test", response_model=BizmailIntegrationTestResult)
async def admin_test_integration(
    current_user: UserResponse = Depends(get_admin_user),
):
    """Run a live SmarterMail login to verify the saved credentials."""
    result = await probe_connection()
    return BizmailIntegrationTestResult(
        ok=bool(result.get("ok")),
        message=str(result.get("message") or ""),
        latency_ms=result.get("latency_ms"),
    )