"""
Site-admin router — restricted to users with role='site_admin'.
These endpoints are NOT tenant-scoped and operate across all accounts.
"""
from uuid import UUID

from fastapi import APIRouter, Depends, File, Query, Request, UploadFile
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.auth.schemas.requests import LoginRequest
from src.apps.auth.schemas.responses import UserResponse
from src.apps.auth.services.auth_service import AuthService
from src.apps.site_admin.models.lead import Lead
from src.apps.site_admin.models.cms_page import CmsPage
from src.apps.site_admin.models.blog_post import BlogPost
from src.apps.site_admin.models.platform_settings import PlatformSettings
from src.apps.tenants.schemas.requests import (
    AdminCreateTenantRequest,
    SendCredentialsRequest,
    UpdateTenantRequest,
)
from src.apps.tenants.schemas.responses import (
    AccountDetailResponse,
    AccountResponse,
    SignupListItemResponse,
)
from src.apps.tenants.services.tenant_service import TenantService
from src.apps.site_admin.schemas.enquiry import EnquiryListItemResponse, UpdateEnquiryStatusRequest, CreateEnquiryRequest
from src.apps.site_admin.schemas.payments import RecordPlatformPaymentRequest
from src.apps.site_admin.services.enquiry_service import EnquiryService
from src.apps.site_admin.services.payment_service import PaymentService
from src.core.dependencies import get_current_user
from src.core.exceptions import ForbiddenError
from src.core.schemas.response import paginated, success
from src.database.session import get_db

router = APIRouter(prefix="/site-admin", tags=["Site Admin"])


# ---------------------------------------------------------------------------
# Serializers
# ---------------------------------------------------------------------------

def _serialize_page(p) -> dict:
    return {
        "id": str(p.id),
        "name": p.name,
        "path": p.path,
        "headline": p.headline,
        "subhead": p.subhead,
        "seoTitle": p.seo_title,
        "seoDesc": p.seo_description,
        "status": p.status,
        "updatedAt": p.updated_at.isoformat(),
    }


def _serialize_post(p) -> dict:
    return {
        "id": str(p.id),
        "title": p.title,
        "slug": p.slug,
        "category": p.category,
        "excerpt": p.excerpt,
        "body": p.body,
        "cover_image_url": p.cover_image_url,
        "author": p.author,
        "seo_title": p.seo_title,
        "seo_description": p.seo_description,
        "meta_keywords": p.meta_keywords,
        "tags": p.tags,
        "featured": p.featured,
        "status": p.status,
        "date": p.published_at.isoformat()[:10] if p.published_at else p.created_at.isoformat()[:10],
        "published_at": p.published_at.isoformat() if p.published_at else None,
        "created_at": p.created_at.isoformat(),
        "updated_at": p.updated_at.isoformat(),
    }


def _serialize_settings(s) -> dict:
    return {
        "email": s.email or "",
        "phone": s.phone or "",
        "office": s.office or "",
        "hours": s.hours or "",
        "linkedin": s.linkedin or "",
        "twitter": s.twitter or "",
        "metaTitle": s.meta_title or "",
        "metaDesc": s.meta_description or "",
        "announcement": s.announcement or "",
    }


# ---------------------------------------------------------------------------
# Auth guard
# ---------------------------------------------------------------------------

async def require_site_admin(current_user=Depends(get_current_user)):
    """Dependency — allows only users whose role is 'site_admin'."""
    if current_user.role != "site_admin":
        raise ForbiddenError("Site admin access required")
    return current_user


# ---------------------------------------------------------------------------
# Auth
# ---------------------------------------------------------------------------

@router.post("/auth/login", response_model=dict)
async def site_admin_login(
    body: LoginRequest,
    request: Request,
    db: AsyncSession = Depends(get_db),
):
    """
    Login for site admin users.
    No tenant scoping — authenticates against the global user pool.
    """
    service = AuthService(db)
    # Pass tenant_id=None to skip tenant filtering
    access_token, refresh_token, user = await service.login(body.email, body.password, tenant_id=None)

    if user.role != "site_admin":
        raise ForbiddenError("Site admin access required")

    return success(
        data={
            "access_token": access_token,
            "refresh_token": refresh_token,
            "token_type": "bearer",
            "user": UserResponse.model_validate(user).model_dump(),
        },
        message="Login successful",
    )


# ---------------------------------------------------------------------------
# Dashboard KPIs
# ---------------------------------------------------------------------------

@router.get("/dashboard/kpis", response_model=dict)
async def get_kpis(
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """High-level KPI snapshot for the site admin dashboard."""
    from src.apps.tenants.models.account import Account
    from src.apps.auth.models.user import User
    from src.apps.records.models.record import Record

    total_tenants_result = await db.execute(select(func.count(Account.id)))
    total_tenants = total_tenants_result.scalar_one()

    active_tenants_result = await db.execute(
        select(func.count(Account.id)).where(Account.status == "active")
    )
    active_tenants = active_tenants_result.scalar_one()

    total_users_result = await db.execute(select(func.count(User.id)))
    total_users = total_users_result.scalar_one()

    total_records_result = await db.execute(
        select(func.count(Record.id)).where(Record.deleted_at.is_(None))
    )
    total_records = total_records_result.scalar_one()

    total_leads_result = await db.execute(select(func.count(Lead.id)))
    total_leads = total_leads_result.scalar_one()

    pages_result = await db.execute(
        select(func.count(CmsPage.id)).where(CmsPage.status == "Published")
    )
    published_pages = pages_result.scalar_one()

    posts_result = await db.execute(
        select(func.count(BlogPost.id)).where(BlogPost.deleted_at.is_(None))
    )
    blog_posts = posts_result.scalar_one()

    return success(
        data={
            "total_tenants": total_tenants,
            "active_tenants": active_tenants,
            "total_users": total_users,
            "total_records": total_records,
            "total_leads": total_leads,
            "published_pages": published_pages,
            "blog_posts": blog_posts,
        }
    )


# ---------------------------------------------------------------------------
# Tenant management
# ---------------------------------------------------------------------------

@router.get("/signups/kpis", response_model=dict)
async def get_signup_kpis(
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """KPI counts by status for the sign-ups dashboard strip cards."""
    service = TenantService(db)
    kpis = await service.get_signup_kpis()
    return success(data=kpis)


@router.get("/signups", response_model=dict)
async def list_signups(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=500),
    status: str = Query(None),
    plan: str = Query(None),
    q: str = Query(None),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Paginated list of all sign-up accounts."""
    service = TenantService(db)
    items, total = await service.list_signups(skip=skip, limit=limit, status=status, plan=plan, q=q)

    response_items = []
    for item in items:
        account = item["account"]
        response_items.append(
            SignupListItemResponse(
                id=account.id,
                subdomain=account.subdomain,
                name=account.organization_name,
                cemetery_type=account.cemetery_type,
                plan=account.plan,
                status=account.status,
                contact={
                    "name": item["contact_name"],
                    "email": item["contact_email"],
                    "phone": item["contact_phone"],
                    "title": "",
                },
                size=account.size,
                signup_source=account.signup_source,
                account_manager=account.account_manager,
                feature_flags=account.feature_flags,
                credentials_sent_at=account.credentials_sent_at,
                activated_at=account.activated_at,
                created_at=account.created_at,
            ).model_dump()
        )

    return paginated(
        items=response_items,
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


@router.get("/tenants", response_model=dict)
async def list_tenants(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    service = TenantService(db)
    accounts, total = await service.list_all(skip=skip, limit=limit)
    return paginated(
        items=[AccountResponse.model_validate(a).model_dump() for a in accounts],
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


@router.post("/tenants", response_model=dict, status_code=201)
async def create_tenant(
    body: AdminCreateTenantRequest,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Create a tenant account on behalf of a customer (admin wizard)."""
    service = TenantService(db)
    account, admin_user, temp_password = await service.admin_create(body.model_dump())
    return success(
        data={
            "account": AccountDetailResponse.model_validate(account).model_dump(),
            "admin_user": UserResponse.model_validate(admin_user).model_dump(),
            "temp_password": temp_password,
        },
        message="Tenant created",
    )


@router.get("/tenants/{tenant_id}", response_model=dict)
async def get_tenant(
    tenant_id: UUID,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    service = TenantService(db)
    account = await service.get_by_id(tenant_id)
    from src.core.exceptions import NotFoundError as _NotFoundError
    if not account:
        raise _NotFoundError("Tenant not found")
    return success(data=AccountDetailResponse.model_validate(account).model_dump())


@router.post("/tenants/{tenant_id}/send-credentials", response_model=dict)
async def send_credentials(
    tenant_id: UUID,
    body: SendCredentialsRequest,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Record credential-send timestamp and trigger welcome email job."""
    service = TenantService(db)
    account = await service.send_credentials(tenant_id, body.credentials_sent_at)
    return success(
        data={"credentials_sent_at": account.credentials_sent_at.isoformat() if account.credentials_sent_at else None},
        message="Credentials recorded",
    )


@router.patch("/tenants/{tenant_id}", response_model=dict)
async def update_tenant(
    tenant_id: UUID,
    body: UpdateTenantRequest,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    service = TenantService(db)
    account = await service.update(tenant_id, body.model_dump(exclude_none=True))
    return success(
        data=AccountDetailResponse.model_validate(account).model_dump(),
        message="Tenant updated",
    )


# ---------------------------------------------------------------------------
# Leads
# ---------------------------------------------------------------------------

@router.get("/leads", response_model=dict)
async def list_leads(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    status: str = Query(None),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from sqlalchemy import and_

    conditions = []
    if status:
        conditions.append(Lead.status == status)

    where_clause = and_(*conditions) if conditions else True

    count_result = await db.execute(
        select(func.count(Lead.id)).where(where_clause)
        if conditions
        else select(func.count(Lead.id))
    )
    total = count_result.scalar_one()

    query = select(Lead).order_by(Lead.created_at.desc()).offset(skip).limit(limit)
    if conditions:
        query = query.where(where_clause)

    result = await db.execute(query)
    leads = result.scalars().all()

    def _serialize_lead(lead: Lead) -> dict:
        return {
            "id": str(lead.id),
            "organization": lead.organization,
            "contact_name": lead.contact_name,
            "email": lead.email,
            "phone": lead.phone,
            "cemetery_type": lead.cemetery_type,
            "size_estimate": lead.size_estimate,
            "plan_interest": lead.plan_interest,
            "source": lead.source,
            "status": lead.status,
            "notes": lead.notes,
            "created_at": lead.created_at.isoformat(),
        }

    return paginated(
        items=[_serialize_lead(lead) for lead in leads],
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


# ---------------------------------------------------------------------------
# Enquiries
# ---------------------------------------------------------------------------

@router.get("/enquiries", response_model=dict)
async def list_enquiries(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=500),
    type: str = Query(None),
    status: str = Query(None),
    q: str = Query(None),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Paginated list of all website enquiries with optional type/status/search filters."""
    service = EnquiryService(db)
    items, total = await service.list(
        skip=skip,
        limit=limit,
        type_filter=type,
        status_filter=status,
        q=q,
    )
    return paginated(
        items=[EnquiryListItemResponse.model_validate(e).model_dump() for e in items],
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


@router.get("/enquiries/new-count", response_model=dict)
async def get_enquiry_new_count(
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Count of new (unactioned) enquiries — used by topbar bell badge."""
    service = EnquiryService(db)
    count = await service.count_new()
    return success(data={"count": count})


@router.post("/enquiries", response_model=dict, status_code=201)
async def create_enquiry(
    body: CreateEnquiryRequest,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Manually create a new enquiry from the site-admin panel."""
    service = EnquiryService(db)
    enquiry = await service.create(body.model_dump())
    return success(
        data=EnquiryListItemResponse.model_validate(enquiry).model_dump(),
        message="Enquiry created",
    )


@router.patch("/enquiries/{enquiry_id}", response_model=dict)
async def update_enquiry_status(
    enquiry_id: UUID,
    body: UpdateEnquiryStatusRequest,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    """Update the status of a website enquiry."""
    service = EnquiryService(db)
    enquiry = await service.update_status(enquiry_id, body.status)
    return success(
        data=EnquiryListItemResponse.model_validate(enquiry).model_dump(),
        message="Status updated",
    )


# ---------------------------------------------------------------------------
# CMS Pages
# ---------------------------------------------------------------------------

@router.get("/pages", response_model=dict)
async def list_pages(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    count_result = await db.execute(select(func.count(CmsPage.id)))
    total = count_result.scalar_one()
    result = await db.execute(
        select(CmsPage).order_by(CmsPage.name.asc()).offset(skip).limit(limit)
    )
    items = result.scalars().all()
    return paginated(
        items=[_serialize_page(p) for p in items],
        total=total,
        page=(skip // limit) + 1 if limit else 1,
        page_size=limit,
    )


@router.get("/pages/{page_id}", response_model=dict)
async def get_page(
    page_id: UUID,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(CmsPage).where(CmsPage.id == page_id))
    page = result.scalar_one_or_none()
    if not page:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Page not found")
    return success(data=_serialize_page(page))


@router.patch("/pages/{page_id}", response_model=dict)
async def update_page(
    page_id: UUID,
    body: dict,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(CmsPage).where(CmsPage.id == page_id))
    page = result.scalar_one_or_none()
    if not page:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Page not found")
    mapping = {
        "headline": "headline",
        "subhead": "subhead",
        "seoTitle": "seo_title",
        "seoDesc": "seo_description",
        "status": "status",
    }
    for key, col in mapping.items():
        if key in body:
            setattr(page, col, body[key])
    await db.flush()
    await db.refresh(page)
    return success(data=_serialize_page(page), message="Page updated")


# ---------------------------------------------------------------------------
# Blog Posts
# ---------------------------------------------------------------------------

@router.get("/posts", response_model=dict)
async def list_posts(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    status: str = Query(None),
    q: str = Query(None),
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from sqlalchemy import and_, or_

    conditions = [BlogPost.deleted_at.is_(None)]
    if status:
        conditions.append(BlogPost.status == status)
    if q:
        term = f"%{q.lower()}%"
        conditions.append(or_(
            func.lower(BlogPost.title).like(term),
            func.lower(BlogPost.excerpt).like(term),
        ))

    where = and_(*conditions)
    count_result = await db.execute(select(func.count(BlogPost.id)).where(where))
    total = count_result.scalar_one()
    query = select(BlogPost).where(where).order_by(BlogPost.created_at.desc()).offset(skip).limit(limit)
    result = await db.execute(query)
    items = result.scalars().all()
    return paginated(
        items=[_serialize_post(p) for p in items],
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


@router.get("/posts/{post_id}", response_model=dict)
async def get_post(
    post_id: UUID,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(
        select(BlogPost).where(BlogPost.id == post_id, BlogPost.deleted_at.is_(None))
    )
    post = result.scalar_one_or_none()
    if not post:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Post not found")
    return success(data=_serialize_post(post))


@router.post("/posts", response_model=dict, status_code=201)
async def create_post(
    body: dict,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from datetime import datetime, timezone
    import re
    from fastapi import HTTPException

    status = body.get("status", "Draft")
    published_at = None
    if status == "Published":
        published_at = datetime.now(timezone.utc)
    # Draft and Unpublished both have no published_at

    slug = body.get("slug", "")
    if not slug:
        title = body.get("title", "")
        slug = re.sub(r"[^a-z0-9]+", "-", title.lower()).strip("-")

    # Validate slug format
    if len(slug) < 2 or not re.match(r"^[a-z0-9][a-z0-9-]*[a-z0-9]$", slug):
        raise HTTPException(status_code=422, detail="Invalid slug format")

    # Check slug uniqueness
    existing = await db.execute(
        select(BlogPost).where(BlogPost.slug == slug, BlogPost.deleted_at.is_(None))
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=409, detail="This slug is already in use.")

    post = BlogPost(
        title=body.get("title", ""),
        slug=slug,
        category=body.get("category"),
        excerpt=body.get("excerpt"),
        body=body.get("body"),
        cover_image_url=body.get("cover_image_url"),
        author=body.get("author"),
        seo_title=body.get("seo_title"),
        seo_description=body.get("seo_description"),
        meta_keywords=body.get("meta_keywords"),
        tags=body.get("tags"),
        featured=body.get("featured", False),
        status=status,
        published_at=published_at,
    )
    db.add(post)
    await db.flush()
    await db.refresh(post)
    return success(data=_serialize_post(post))


@router.patch("/posts/{post_id}", response_model=dict)
async def update_post(
    post_id: UUID,
    body: dict,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from datetime import datetime, timezone
    from fastapi import HTTPException

    result = await db.execute(
        select(BlogPost).where(BlogPost.id == post_id, BlogPost.deleted_at.is_(None))
    )
    post = result.scalar_one_or_none()
    if not post:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Post not found")

    # Handle slug uniqueness (exclude self)
    if "slug" in body and body["slug"] != post.slug:
        slug = body["slug"]
        existing = await db.execute(
            select(BlogPost).where(
                BlogPost.slug == slug,
                BlogPost.id != post_id,
                BlogPost.deleted_at.is_(None),
            )
        )
        if existing.scalar_one_or_none():
            raise HTTPException(status_code=409, detail="This slug is already in use.")

    for field in ["title", "slug", "category", "excerpt", "body", "cover_image_url",
                  "author", "seo_title", "seo_description", "meta_keywords", "tags", "featured", "status"]:
        if field in body:
            setattr(post, field, body[field])

    if body.get("status") == "Published" and not post.published_at:
        post.published_at = datetime.now(timezone.utc)
    elif body.get("status") in ("Draft", "Unpublished"):
        post.published_at = None

    await db.flush()
    await db.refresh(post)
    return success(data=_serialize_post(post), message="Post updated")


@router.delete("/posts/{post_id}", status_code=204)
async def delete_post(
    post_id: UUID,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from datetime import datetime, timezone

    result = await db.execute(
        select(BlogPost).where(BlogPost.id == post_id, BlogPost.deleted_at.is_(None))
    )
    post = result.scalar_one_or_none()
    if not post:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Post not found")
    post.deleted_at = datetime.now(timezone.utc)
    await db.flush()


@router.patch("/posts/{post_id}/publish", response_model=dict)
async def toggle_publish(
    post_id: UUID,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    from datetime import datetime, timezone

    result = await db.execute(
        select(BlogPost).where(BlogPost.id == post_id, BlogPost.deleted_at.is_(None))
    )
    post = result.scalar_one_or_none()
    if not post:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("Post not found")

    if post.status == "Published":
        post.status = "Unpublished"
        post.published_at = None
    else:
        post.status = "Published"
        post.published_at = datetime.now(timezone.utc)

    await db.flush()
    await db.refresh(post)
    return success(data=_serialize_post(post), message="Publish status toggled")


@router.post("/posts/images", response_model=dict, status_code=201)
async def upload_post_image(
    request: Request,
    file: UploadFile = File(...),
    current_user=Depends(require_site_admin),
):
    import uuid as _uuid
    import boto3
    import botocore.exceptions
    from fastapi import HTTPException
    from src.core.config import settings as _settings

    ALLOWED_TYPES = {"image/jpeg", "image/png", "image/webp"}
    MAX_SIZE = 5 * 1024 * 1024  # 5 MB

    if file.content_type not in ALLOWED_TYPES:
        raise HTTPException(status_code=422, detail="Only JPG, PNG, and WebP are accepted.")

    content = await file.read()
    if len(content) > MAX_SIZE:
        raise HTTPException(status_code=422, detail="Image must be ≤ 5 MB.")

    if not _settings.AWS_ACCESS_KEY_ID or not _settings.S3_DOCUMENTS_BUCKET:
        raise HTTPException(status_code=501, detail="S3 storage is not configured.")

    ext = file.content_type.split("/")[-1].replace("jpeg", "jpg")
    key = f"blog_images/{_uuid.uuid4()}.{ext}"

    bucket = _settings.S3_DOCUMENTS_BUCKET
    region = _settings.S3_DOCUMENTS_REGION or "us-east-1"

    s3 = boto3.client(
        "s3",
        aws_access_key_id=_settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=_settings.AWS_SECRET_ACCESS_KEY,
        region_name=region,
    )
    try:
        import asyncio as _asyncio
        await _asyncio.to_thread(
            s3.put_object,
            Bucket=bucket,
            Key=key,
            Body=content,
            ContentType=file.content_type,
        )
    except botocore.exceptions.ClientError as e:
        code = e.response.get("Error", {}).get("Code", "")
        if code == "NoSuchBucket":
            raise HTTPException(status_code=503, detail=f"S3 bucket '{bucket}' does not exist.")
        raise HTTPException(status_code=503, detail=f"S3 upload failed: {code}")

    proxy_url = str(request.base_url).rstrip("/") + f"/api/public/images/{key}"
    return success(data={"url": proxy_url})


# ---------------------------------------------------------------------------
# Platform Settings (single-row table)
# ---------------------------------------------------------------------------

DEFAULT_SETTINGS = {
    "email": "hello@indelis.com",
    "phone": "1-800-555-0100",
    "office": "Ottawa, ON, Canada",
    "hours": "Mon–Fri, 9 am – 5 pm ET",
    "linkedin": "",
    "twitter": "",
    "metaTitle": "INDELIS — Cemetery Management Software",
    "metaDesc": "",
    "announcement": "",
}


@router.get("/settings", response_model=dict)
async def get_platform_settings(
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(PlatformSettings).limit(1))
    settings = result.scalar_one_or_none()
    if not settings:
        return success(data=DEFAULT_SETTINGS)
    return success(data=_serialize_settings(settings))


@router.patch("/settings", response_model=dict)
async def update_platform_settings(
    body: dict,
    current_user=Depends(require_site_admin),
    db: AsyncSession = Depends(get_db),
):
    result = await db.execute(select(PlatformSettings).limit(1))
    settings = result.scalar_one_or_none()
    if not settings:
        settings = PlatformSettings()
        db.add(settings)

    field_map = {
        "email": "email",
        "phone": "phone",
        "office": "office",
        "hours": "hours",
        "linkedin": "linkedin",
        "twitter": "twitter",
        "metaTitle": "meta_title",
        "metaDesc": "meta_description",
        "announcement": "announcement",
    }
    for key, col in field_map.items():
        if key in body:
            setattr(settings, col, body[key])
    await db.flush()
    await db.refresh(settings)
    return success(data=_serialize_settings(settings), message="Settings saved")


# ---------------------------------------------------------------------------
# Platform Payments
# Note: /payments/kpis and /payments/export-csv must be registered BEFORE
# any parameterised /payments/{id} route to avoid FastAPI routing conflicts.
# ---------------------------------------------------------------------------

def _get_payment_service(db: AsyncSession = Depends(get_db)) -> PaymentService:
    return PaymentService(db)


@router.get("/payments/kpis", response_model=dict)
async def get_payment_kpis(
    current_user=Depends(require_site_admin),
    service: PaymentService = Depends(_get_payment_service),
):
    """KPI totals: total_received, this_month, this_month_label, mrr, payment_count."""
    kpis = await service.get_kpis()
    return success(data=kpis)


@router.get("/payments/export-csv")
async def export_payments_csv(
    plan: str = Query(None, pattern="^(starter|professional|enterprise)$"),
    source: str = Query(None, pattern="^(portal|admin)$"),
    q: str = Query(None),
    current_user=Depends(require_site_admin),
    service: PaymentService = Depends(_get_payment_service),
):
    """Streaming CSV export of filtered payments."""
    from fastapi.responses import StreamingResponse

    async def _gen():
        async for chunk in service.export_csv(plan=plan, source=source, q=q):
            yield chunk

    return StreamingResponse(
        _gen(),
        media_type="text/csv",
        headers={"Content-Disposition": 'attachment; filename="indelis-payments.csv"'},
    )


@router.get("/payments", response_model=dict)
async def list_payments(
    plan: str = Query(None, pattern="^(starter|professional|enterprise)$"),
    source: str = Query(None, pattern="^(portal|admin)$"),
    q: str = Query(None),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    current_user=Depends(require_site_admin),
    service: PaymentService = Depends(_get_payment_service),
):
    """Paginated + filtered list of platform payments, newest first."""
    items, total = await service.list_payments(
        plan=plan, source=source, q=q, page=page, page_size=page_size
    )
    pages = max(1, -(-total // page_size))
    return {
        "success": True,
        "data": items,
        "total": total,
        "page": page,
        "page_size": page_size,
        "pages": pages,
    }


@router.post("/payments", response_model=dict, status_code=201)
async def record_payment(
    body: RecordPlatformPaymentRequest,
    current_user=Depends(require_site_admin),
    service: PaymentService = Depends(_get_payment_service),
):
    """Manually record a platform payment (admin-created)."""
    payment = await service.record_payment(payload=body.model_dump())
    return success(data={"id": str(payment.id)}, message="Payment recorded")


@router.get("/payments/{payment_id}/invoice-pdf")
async def get_invoice_pdf(
    payment_id: UUID,
    current_user=Depends(require_site_admin),
    service: PaymentService = Depends(_get_payment_service),
):
    """Generate and stream an invoice PDF for a single payment."""
    from fastapi.responses import Response as FastAPIResponse

    payment, account = await service.get_payment_with_account(payment_id)

    # Fetch trial end date if the payment is in a trial (pending status)
    trial_ends_at = None
    if payment.status == "pending":
        from src.apps.tenants.models.subscription import Subscription
        sub_stmt = (
            select(Subscription)
            .where(
                Subscription.account_id == payment.account_id,
                Subscription.current_period_end.isnot(None),
            )
            .order_by(Subscription.created_at.desc())
            .limit(1)
        )
        sub = (await service.db.execute(sub_stmt)).scalar_one_or_none()
        if sub and sub.current_period_end:
            trial_ends_at = sub.current_period_end.date()

    pdf_bytes = service.generate_invoice_pdf(payment, account, trial_ends_at=trial_ends_at)
    invoice_no = payment.invoice_no or str(payment.id)[:8].upper()
    filename = f"indelis-invoice-{invoice_no}.pdf"
    return FastAPIResponse(
        content=pdf_bytes,
        media_type="application/pdf",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )
