"""Customers router."""

import uuid
from typing import Any

import httpx
import logfire
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import delete as sa_delete
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select, update

from app.auth.tenant import get_current_restaurant, get_tenant_session
from app.db.session import commit_write
from app.dependencies import get_restate_client, restate_proxy
from app.models.conversation import Conversation, Message
from app.models.customer import Customer, CustomerCreate, CustomerRead
from app.models.order import Order
from app.models.reservation import Reservation
from app.models.restaurant import Restaurant

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


@router.get("/", response_model=list[CustomerRead])
async def list_customers(
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> list[Any]:
    result = await session.execute(
        select(Customer).where(Customer.restaurant_id == restaurant.id).limit(200)
    )
    return list(result.scalars().all())


@router.put("/upsert", response_model=CustomerRead, status_code=status.HTTP_202_ACCEPTED)
async def upsert_customer(
    data: CustomerCreate,
    restaurant: Restaurant = Depends(get_current_restaurant),
    client: httpx.AsyncClient = Depends(get_restate_client),
) -> Any:
    customer_id = str(uuid.uuid4())
    payload = {**data.model_dump(mode="json"), "restaurant_id": restaurant.id}
    await restate_proxy(client, "CustomerObject", customer_id, "upsert", payload, mode="object")
    return CustomerRead(id=customer_id, restaurant_id=restaurant.id, **data.model_dump())


@router.post("/{customer_id}/record_visit", status_code=status.HTTP_202_ACCEPTED)
async def record_customer_visit(
    customer_id: str,
    restaurant: Restaurant = Depends(get_current_restaurant),
    client: httpx.AsyncClient = Depends(get_restate_client),
) -> dict[str, str]:
    await restate_proxy(
        client,
        "CustomerObject",
        customer_id,
        "record_visit",
        {"restaurant_id": restaurant.id},
        mode="object",
    )
    return {"status": "visit recorded"}


@router.delete("/{customer_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_customer(
    customer_id: str,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> None:
    """Delete a customer and scrub their personal data from related records.

    - Reservations: guest_email, guest_phone nullified, guest_name set to
      'Deleted customer', customer_id unlinked.
    - Conversations & their messages: hard-deleted.
    - Orders: customer_id unlinked.
    - Customer row: hard-deleted.
    """
    result = await session.execute(
        select(Customer).where(
            Customer.id == customer_id,
            Customer.restaurant_id == restaurant.id,
        )
    )
    customer = result.scalar_one_or_none()
    if customer is None:
        raise HTTPException(status_code=404, detail="Customer not found")

    # Scrub PII from reservations
    await session.execute(
        update(Reservation)
        .where(Reservation.customer_id == customer_id)  # type: ignore[arg-type]
        .values(
            customer_id=None,
            guest_email=None,
            guest_phone=None,
            guest_name="Deleted customer",
        )
    )

    # Unlink from orders
    await session.execute(
        update(Order).where(Order.customer_id == customer_id).values(customer_id=None)  # type: ignore[arg-type]
    )

    # Delete conversations and their messages
    conv_ids_result = await session.execute(
        select(Conversation.id).where(Conversation.customer_id == customer_id)
    )
    conv_ids = [row[0] for row in conv_ids_result.all()]
    if conv_ids:
        await session.execute(
            sa_delete(Message).where(Message.conversation_id.in_(conv_ids))  # type: ignore[union-attr]
        )
        await session.execute(
            sa_delete(Conversation).where(Conversation.id.in_(conv_ids))  # type: ignore[union-attr]
        )

    await session.delete(customer)
    await commit_write(session)

    logfire.info(
        "customer_deleted",
        customer_id=customer_id,
        restaurant_id=restaurant.id,
        conversations_deleted=len(conv_ids),
    )
