from typing import List, Optional
from uuid import UUID

from fastapi import APIRouter, Depends, Query, Request
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.memorials.schemas.requests import CreateMemorialRequest
from src.apps.records.schemas.requests import (
    CreateBurialInfoRequest,
    CreateFamilyContactRequest,
    CreateRecordRequest,
    UpdateFamilyContactRequest,
    UpdateRecordRequest,
)
from src.apps.records.schemas.responses import (
    AuditLogEntryResponse,
    BurialInfoResponse,
    FamilyContactResponse,
    RecordResponse,
    RecordSummaryResponse,
)
from src.apps.records.services.record_service import RecordService
from src.apps.site_admin.services.audit_service import AuditService
from src.core.constants import UserRole
from src.core.dependencies import require_min_role, require_roles
from src.core.schemas.response import paginated, success
from src.database.session import get_db

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


def serialize_record_for_list(r) -> dict:
    base = RecordSummaryResponse.model_validate(r).model_dump()
    base['plot_ref'] = r.plot.plot_ref if r.plot else None
    base['section_code'] = r.plot.section.code if r.plot and r.plot.section else None
    base['date_interred'] = (
        r.burial_info.interment_date.isoformat()
        if r.burial_info and r.burial_info.interment_date
        else None
    )
    return base


@router.get("", response_model=dict)
async def list_records(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    search: Optional[str] = Query(None),
    section: Optional[str] = Query(None),
    record_type: Optional[str] = Query(None),
    is_veteran: Optional[bool] = Query(None),
    current_user=Depends(require_min_role(UserRole.VIEW_ONLY)),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    records, total = await service.list_records(
        tenant_id=current_user.tenant_id,
        search=search,
        section=section,
        record_type=record_type,
        page=page,
        page_size=page_size,
    )
    return paginated(
        items=[serialize_record_for_list(r) for r in records],
        total=total,
        page=page,
        page_size=page_size,
    )


@router.post("", response_model=dict, status_code=201)
async def create_record(
    body: CreateRecordRequest,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    record = await service.create(
        tenant_id=current_user.tenant_id,
        data=body.model_dump(exclude_none=True),
        current_user=current_user,
        request=request,
    )
    return success(
        data=RecordResponse.model_validate(record).model_dump(),
        message="Record created",
    )


@router.get("/export-csv")
async def export_records_csv(
    search: Optional[str] = Query(None),
    section: Optional[str] = Query(None),
    record_type: Optional[str] = Query(None),
    record_ids: Optional[List[UUID]] = Query(None),
    current_user=Depends(require_min_role(UserRole.VIEW_ONLY)),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    generator = service.export_csv(
        tenant_id=current_user.tenant_id,
        record_ids=record_ids,
        search=search,
        section=section,
        record_type=record_type,
    )
    return StreamingResponse(
        generator,
        media_type="text/csv",
        headers={"Content-Disposition": "attachment; filename=records.csv"},
    )


@router.get("/{record_id}/audit", response_model=dict)
async def get_record_audit(
    record_id: UUID,
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR, UserRole.VIEW_ONLY)),
    db: AsyncSession = Depends(get_db),
):
    logs, total = await AuditService.get_record_audit(
        db, current_user.tenant_id, record_id, page, page_size
    )
    return paginated(
        items=[AuditLogEntryResponse.from_enriched(entry).model_dump() for entry in logs],
        total=total,
        page=page,
        page_size=page_size,
    )


@router.get("/{record_id}", response_model=dict)
async def get_record(
    record_id: UUID,
    current_user=Depends(require_min_role(UserRole.VIEW_ONLY)),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    record = await service.get_by_id(record_id, current_user.tenant_id)
    data = RecordResponse.model_validate(record).model_dump()
    data["plot_ref"] = record.plot.plot_ref if record.plot else None
    data["section_code"] = record.plot.section.code if record.plot and record.plot.section else None
    data["date_interred"] = (
        record.burial_info.interment_date.isoformat()
        if record.burial_info and record.burial_info.interment_date
        else None
    )
    return success(data=data)


@router.put("/{record_id}", response_model=dict)
async def update_record(
    record_id: UUID,
    body: UpdateRecordRequest,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    record = await service.update(
        record_id=record_id,
        tenant_id=current_user.tenant_id,
        data=body.model_dump(exclude_none=True),
        current_user=current_user,
        request=request,
    )
    data = RecordResponse.model_validate(record).model_dump()
    data["plot_ref"] = record.plot.plot_ref if record.plot else None
    data["section_code"] = record.plot.section.code if record.plot and record.plot.section else None
    data["date_interred"] = (
        record.burial_info.interment_date.isoformat()
        if record.burial_info and record.burial_info.interment_date
        else None
    )
    return success(
        data=data,
        message="Record updated",
    )


@router.delete("/{record_id}", status_code=204)
async def delete_record(
    record_id: UUID,
    request: Request,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    await service.soft_delete(
        record_id,
        current_user.tenant_id,
        current_user=current_user,
        request=request,
    )


# --- Burial Info sub-resource ---

@router.put("/{record_id}/burial-info", response_model=dict)
async def upsert_burial_info(
    record_id: UUID,
    body: CreateBurialInfoRequest,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    burial = await service.upsert_burial_info(
        record_id=record_id,
        tenant_id=current_user.tenant_id,
        data=body.model_dump(exclude_none=True),
        current_user=current_user,
        request=request,
    )
    return success(
        data=BurialInfoResponse.model_validate(burial).model_dump(),
        message="Burial info saved",
    )


# --- Family Contacts sub-resource ---

@router.post("/{record_id}/contacts", response_model=dict, status_code=201)
async def add_family_contact(
    record_id: UUID,
    body: CreateFamilyContactRequest,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    contact = await service.add_family_contact(
        record_id=record_id,
        tenant_id=current_user.tenant_id,
        data=body.model_dump(exclude_none=True),
        current_user=current_user,
        request=request,
    )
    return success(
        data=FamilyContactResponse.model_validate(contact).model_dump(),
        message="Contact added",
    )


@router.delete("/{record_id}/contacts/{contact_id}", status_code=204)
async def delete_family_contact(
    record_id: UUID,
    contact_id: UUID,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    await service.delete_family_contact(
        contact_id,
        current_user.tenant_id,
        current_user=current_user,
        request=request,
    )


@router.patch("/{record_id}/contacts/{contact_id}", response_model=dict)
async def update_family_contact(
    record_id: UUID,
    contact_id: UUID,
    body: UpdateFamilyContactRequest,
    request: Request,
    current_user=Depends(
        require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER, UserRole.STAFF)
    ),
    db: AsyncSession = Depends(get_db),
):
    service = RecordService(db)
    contact = await service.update_family_contact(
        contact_id=contact_id,
        tenant_id=current_user.tenant_id,
        record_id=record_id,
        data=body.model_dump(exclude_none=True),
        current_user=current_user,
        request=request,
    )
    return success(
        data=FamilyContactResponse.model_validate(contact).model_dump(),
        message="Contact updated",
    )


# --- Memorial sub-resource ---

@router.post("/{record_id}/memorial", response_model=dict, status_code=201)
async def create_memorial_for_record(
    record_id: UUID,
    body: CreateMemorialRequest,
    request: Request,
    current_user=Depends(require_min_role(UserRole.STAFF)),
    db: AsyncSession = Depends(get_db),
):
    from src.apps.memorials.services.memorial_service import MemorialService
    from src.apps.memorials.schemas.responses import MemorialResponse
    memorial = await MemorialService.create_for_record(
        db=db,
        record_id=record_id,
        tenant_id=current_user.tenant_id,
        data=body,
        current_user=current_user,
        request=request,
    )
    return success(
        data=MemorialResponse.model_validate(memorial).model_dump(),
        message="Memorial created",
    )
