"""
Admin endpoints for Yield payouts (ledger).

Premium constraints:
- No placeholder payouts
- No currency mixing
- Idempotent generation per (user, currency, period)
"""

from __future__ import annotations

from datetime import datetime
from decimal import Decimal

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy import and_, func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_current_user, get_db
from app.models.user import User
from app.models.yield_domain import YieldPayout, YieldTransaction
from app.services.telemetry import track_event
from app.services.yield_payouts import generate_payouts_for_period


router = APIRouter(prefix="/yield", tags=["yield-admin"])


class PayoutGenerateRequest(BaseModel):
    period_start: datetime
    period_end: datetime


class GeneratedPayout(BaseModel):
    id: int
    user_id: int
    amount: Decimal
    currency: str
    period_start: datetime
    period_end: datetime
    transaction_count: int
    status: str
    created_at: datetime


class PayoutGenerateResponse(BaseModel):
    created: list[GeneratedPayout]
    skipped_existing: int = 0


class PayoutCompleteRequest(BaseModel):
    payment_method: str | None = Field(default=None, max_length=50)
    payment_reference: str | None = Field(default=None, max_length=200)


class PayoutCompleteResponse(BaseModel):
    payout_id: int
    transactions_marked_paid: int
    completed_at: datetime


def _require_admin(current_user: User) -> None:
    if not current_user.is_admin:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required")


@router.post("/payouts/generate", response_model=PayoutGenerateResponse)
async def generate_payouts(
    payload: PayoutGenerateRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """
    Create YieldPayout rows for confirmed, unpaid transactions in the period.

    This does NOT mark payouts as completed. It only assigns transactions to a payout via payout_id.
    Completion is a separate step once payment is executed.
    """
    _require_admin(current_user)

    if payload.period_end <= payload.period_start:
        raise HTTPException(status_code=400, detail="period_end must be after period_start")

    created_count, skipped_existing = await generate_payouts_for_period(
        db,
        period_start=payload.period_start,
        period_end=payload.period_end,
    )

    payouts = (
        await db.execute(
            select(YieldPayout)
            .where(
                and_(
                    YieldPayout.period_start == payload.period_start,
                    YieldPayout.period_end == payload.period_end,
                )
            )
            .order_by(YieldPayout.created_at.desc())
        )
    ).scalars().all()

    created = [
        GeneratedPayout(
            id=p.id,
            user_id=p.user_id,
            amount=p.amount,
            currency=p.currency,
            period_start=p.period_start,
            period_end=p.period_end,
            transaction_count=p.transaction_count,
            status=p.status,
            created_at=p.created_at,
        )
        for p in payouts
    ]

    # created_count is still returned implicitly via list length; we keep it for logs later
    _ = created_count
    return PayoutGenerateResponse(created=created, skipped_existing=skipped_existing)


@router.post("/payouts/{payout_id}/complete", response_model=PayoutCompleteResponse)
async def complete_payout(
    payout_id: int,
    payload: PayoutCompleteRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """
    Mark a payout as completed and mark assigned transactions as paid.
    """
    _require_admin(current_user)

    payout = (
        await db.execute(select(YieldPayout).where(YieldPayout.id == payout_id))
    ).scalar_one_or_none()
    if not payout:
        raise HTTPException(status_code=404, detail="Payout not found")

    if payout.status == "completed":
        raise HTTPException(status_code=400, detail="Payout already completed")

    payout.status = "completed"
    payout.completed_at = datetime.utcnow()
    payout.payment_method = payload.payment_method
    payout.payment_reference = payload.payment_reference

    txs = (
        await db.execute(
            select(YieldTransaction).where(YieldTransaction.payout_id == payout.id)
        )
    ).scalars().all()

    marked = 0
    for tx in txs:
        if tx.status != "paid":
            tx.status = "paid"
            tx.paid_at = payout.completed_at
            marked += 1

    await track_event(
        db,
        event_name="payout_paid",
        request=None,
        user_id=payout.user_id,
        is_authenticated=None,
        source="admin",
        domain=None,
        yield_domain_id=None,
        metadata={
            "payout_id": payout.id,
            "currency": payout.currency,
            "amount": float(payout.amount),
            "transaction_count": payout.transaction_count,
            "payment_method": payout.payment_method,
        },
    )

    await db.commit()

    return PayoutCompleteResponse(
        payout_id=payout.id,
        transactions_marked_paid=marked,
        completed_at=payout.completed_at,
    )

