from __future__ import annotations

from uuid import UUID

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

from src.core.app_url import resolve_checkout_redirect_urls
from src.core.database import get_db
from src.core.exceptions import ForbiddenError
from src.domain.auth.models import User
from src.domain.auth.router import get_current_user
from src.domain.billing.repository import StripeCustomerRepository, SubscriptionRepository
from src.domain.billing.service import BillingService
from src.domain.billing.catalog_service import BillingCatalogService
from src.domain.admin.repository import PlanPriceVersionRepository, SubscriptionPlanRepository
from src.domain.billing.repository import (
    InvoiceRepository,
    StripeEventRepository,
    UsageCreditPackageRepository,
    UsageCreditPurchaseRepository,
    UsageLedgerRepository,
    WorkspaceCreditLedgerRepository,
)
from src.domain.runtime_ai.catalog import DISPLAY_SCALE, list_price_rows
from src.domain.runtime_ai.schemas import (
    RuntimeAiBalanceResponse,
    RuntimeAiCheckoutRequest,
    RuntimeAiPackagePublic,
    RuntimeAiPriceRow,
)
from src.domain.runtime_ai.service import RuntimeAiService
from src.domain.workspaces.facades import WorkspaceFacadeImpl
from src.domain.workspaces.repository import MembershipRepository, WorkspaceRepository
from src.integrations.stripe_client import StripeClientImpl
from src.config import get_settings
from src.domain.billing.schemas import CheckoutSessionResponse

router = APIRouter(prefix="/api/runtime-ai", tags=["runtime-ai"])


def _stripe():
    settings = get_settings()
    return StripeClientImpl() if settings.stripe_secret_key else None


def _billing_service(db: AsyncSession) -> BillingService:
    return BillingService(
        customer_repo=StripeCustomerRepository(db),
        subscription_repo=SubscriptionRepository(db),
        invoice_repo=InvoiceRepository(db),
        event_repo=StripeEventRepository(db),
        usage_repo=UsageLedgerRepository(db),
        purchase_repo=UsageCreditPurchaseRepository(db),
        ledger_repo=WorkspaceCreditLedgerRepository(db),
        catalog=BillingCatalogService(
            plan_repo=SubscriptionPlanRepository(db),
            package_repo=UsageCreditPackageRepository(db),
            price_version_repo=PlanPriceVersionRepository(db),
        ),
        stripe_client=_stripe(),
        workspace_repo=WorkspaceRepository(db),
    )


def _runtime_ai(db: AsyncSession) -> RuntimeAiService:
    billing = _billing_service(db)
    return RuntimeAiService(db=db, stripe_client=_stripe(), ensure_customer=billing.ensure_customer)


@router.get("/prices", response_model=list[RuntimeAiPriceRow])
async def list_prices(_: User = Depends(get_current_user)) -> list[RuntimeAiPriceRow]:
    return [RuntimeAiPriceRow.model_validate(row) for row in list_price_rows()]


@router.get("/balance", response_model=RuntimeAiBalanceResponse)
async def get_balance(
    workspace_id: UUID = Query(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> RuntimeAiBalanceResponse:
    facade = WorkspaceFacadeImpl(WorkspaceRepository(db), MembershipRepository(db))
    if not await facade.check_permission(workspace_id, user.id, "invoices.read"):
        raise ForbiddenError("Workspace billing access required")
    svc = _runtime_ai(db)
    millicredits = await svc.balance_millicredits(workspace_id)
    packages = [
        RuntimeAiPackagePublic(
            slug=p.slug,
            name=p.name,
            description=p.description,
            credits=p.credits,
            price_minor=p.price_minor,
            currency=p.currency,
            stripe_ready=bool(p.stripe_price_id),
        )
        for p in await svc.list_packages()
    ]
    return RuntimeAiBalanceResponse(
        millicredits=millicredits,
        credits=millicredits / DISPLAY_SCALE,
        packages=packages,
    )


@router.post("/checkout-session", response_model=CheckoutSessionResponse)
async def create_checkout(
    request: Request,
    body: RuntimeAiCheckoutRequest,
    workspace_id: UUID = Query(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> CheckoutSessionResponse:
    facade = WorkspaceFacadeImpl(WorkspaceRepository(db), MembershipRepository(db))
    if not await facade.check_permission(workspace_id, user.id, "billing.manage"):
        raise ForbiddenError("Workspace billing access required")
    success_url, cancel_url = resolve_checkout_redirect_urls(request, body.success_url, body.cancel_url)
    summary = await facade.get_workspace_summary(workspace_id)
    svc = _runtime_ai(db)
    result = await svc.start_checkout(
        workspace_id=workspace_id,
        user_id=user.id,
        email=user.email,
        workspace_name=summary.name if summary else "",
        package_slug=body.package_slug,
        success_url=success_url,
        cancel_url=cancel_url,
        idempotency_key=body.idempotency_key or request.headers.get("Idempotency-Key"),
    )
    return CheckoutSessionResponse(
        checkout_url=result["checkout_url"],
        session_id=result["session_id"],
        workspace_id=result.get("workspace_id"),
    )
