"""
Subscription management API for GDPR-compliant cancellation and reactivation
"""

from fastapi import APIRouter, Depends, HTTPException, status, Query
from pydantic import BaseModel, Field
from datetime import datetime, timezone, timedelta
from uuid import UUID
import structlog
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from shared.auth.decorators import get_current_user_dep, require_admin_role_dep
from shared.routing import RouteBuilder
from app.core.database import get_db
from app.models.tenants import Subscription, Tenant
from app.services.subscription_limit_service import SubscriptionLimitService
from shared.clients.stripe_client import StripeProvider
from app.core.config import settings

logger = structlog.get_logger()
router = APIRouter()
route_builder = RouteBuilder('tenant')


class QuotaCheckResponse(BaseModel):
    """Response for quota limit checks"""
    allowed: bool
    message: str
    limit: int
    current_count: int
    max_allowed: int
    reason: str
    requested_amount: int
    available_amount: int


class SubscriptionCancellationRequest(BaseModel):
    """Request model for subscription cancellation"""
    tenant_id: str = Field(..., description="Tenant ID to cancel subscription for")
    reason: str = Field(default="", description="Optional cancellation reason")


class SubscriptionCancellationResponse(BaseModel):
    """Response for subscription cancellation"""
    success: bool
    message: str
    status: str
    cancellation_effective_date: str
    days_remaining: int
    read_only_mode_starts: str


class SubscriptionReactivationRequest(BaseModel):
    """Request model for subscription reactivation"""
    tenant_id: str = Field(..., description="Tenant ID to reactivate subscription for")
    plan: str = Field(default="starter", description="Plan to reactivate with")


class SubscriptionStatusResponse(BaseModel):
    """Response for subscription status check"""
    tenant_id: str
    status: str
    plan: str
    is_read_only: bool
    cancellation_effective_date: str | None
    days_until_inactive: int | None


class InvoiceResponse(BaseModel):
    """Response model for an invoice"""
    id: str
    date: str
    amount: float
    currency: str
    status: str
    description: str | None = None
    invoice_pdf: str | None = None
    hosted_invoice_url: str | None = None


@router.post("/api/v1/subscriptions/cancel", response_model=SubscriptionCancellationResponse)
async def cancel_subscription(
    request: SubscriptionCancellationRequest,
    current_user: dict = Depends(require_admin_role_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Cancel subscription - Downgrade to read-only mode

    Flow:
    1. Set status to 'pending_cancellation'
    2. Calculate cancellation_effective_date (end of billing period)
    3. User keeps access until effective date
    4. Background job converts to 'inactive' at effective date
    5. Gateway enforces read-only mode for 'pending_cancellation' and 'inactive' statuses
    """
    try:
        tenant_id = UUID(request.tenant_id)

        query = select(Subscription).where(Subscription.tenant_id == tenant_id)
        result = await db.execute(query)
        subscription = result.scalar_one_or_none()

        if not subscription:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Subscription not found"
            )

        if subscription.status in ['pending_cancellation', 'inactive']:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Subscription is already {subscription.status}"
            )

        cancellation_effective_date = subscription.next_billing_date or (
            datetime.now(timezone.utc) + timedelta(days=30)
        )

        subscription.status = 'pending_cancellation'
        subscription.cancelled_at = datetime.now(timezone.utc)
        subscription.cancellation_effective_date = cancellation_effective_date

        await db.commit()
        await db.refresh(subscription)

        days_remaining = (cancellation_effective_date - datetime.now(timezone.utc)).days

        logger.info(
            "subscription_cancelled",
            tenant_id=str(tenant_id),
            user_id=current_user.get("sub"),
            effective_date=cancellation_effective_date.isoformat(),
            reason=request.reason[:200] if request.reason else None
        )

        return SubscriptionCancellationResponse(
            success=True,
            message="Subscription cancelled successfully. You will have read-only access until the end of your billing period.",
            status="pending_cancellation",
            cancellation_effective_date=cancellation_effective_date.isoformat(),
            days_remaining=days_remaining,
            read_only_mode_starts=cancellation_effective_date.isoformat()
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error("subscription_cancellation_failed", error=str(e), tenant_id=request.tenant_id)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to cancel subscription"
        )


@router.post("/api/v1/subscriptions/reactivate")
async def reactivate_subscription(
    request: SubscriptionReactivationRequest,
    current_user: dict = Depends(require_admin_role_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Reactivate a cancelled or inactive subscription

    Can reactivate from:
    - pending_cancellation (before effective date)
    - inactive (after effective date)
    """
    try:
        tenant_id = UUID(request.tenant_id)

        query = select(Subscription).where(Subscription.tenant_id == tenant_id)
        result = await db.execute(query)
        subscription = result.scalar_one_or_none()

        if not subscription:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Subscription not found"
            )

        if subscription.status not in ['pending_cancellation', 'inactive']:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Cannot reactivate subscription with status: {subscription.status}"
            )

        subscription.status = 'active'
        subscription.plan = request.plan
        subscription.cancelled_at = None
        subscription.cancellation_effective_date = None

        if subscription.status == 'inactive':
            subscription.next_billing_date = datetime.now(timezone.utc) + timedelta(days=30)

        await db.commit()
        await db.refresh(subscription)

        logger.info(
            "subscription_reactivated",
            tenant_id=str(tenant_id),
            user_id=current_user.get("sub"),
            new_plan=request.plan
        )

        return {
            "success": True,
            "message": "Subscription reactivated successfully",
            "status": "active",
            "plan": subscription.plan,
            "next_billing_date": subscription.next_billing_date.isoformat() if subscription.next_billing_date else None
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.error("subscription_reactivation_failed", error=str(e), tenant_id=request.tenant_id)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to reactivate subscription"
        )


@router.get("/api/v1/subscriptions/{tenant_id}/status", response_model=SubscriptionStatusResponse)
async def get_subscription_status(
    tenant_id: str,
    current_user: dict = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Get current subscription status including read-only mode info
    """
    try:
        query = select(Subscription).where(Subscription.tenant_id == UUID(tenant_id))
        result = await db.execute(query)
        subscription = result.scalar_one_or_none()

        if not subscription:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Subscription not found"
            )

        is_read_only = subscription.status in ['pending_cancellation', 'inactive']
        days_until_inactive = None

        if subscription.status == 'pending_cancellation' and subscription.cancellation_effective_date:
            days_until_inactive = (subscription.cancellation_effective_date - datetime.now(timezone.utc)).days

        return SubscriptionStatusResponse(
            tenant_id=str(tenant_id),
            status=subscription.status,
            plan=subscription.plan,
            is_read_only=is_read_only,
            cancellation_effective_date=subscription.cancellation_effective_date.isoformat() if subscription.cancellation_effective_date else None,
            days_until_inactive=days_until_inactive
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error("get_subscription_status_failed", error=str(e), tenant_id=tenant_id)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to get subscription status"
        )


@router.get("/api/v1/subscriptions/{tenant_id}/invoices", response_model=list[InvoiceResponse])
async def get_tenant_invoices(
    tenant_id: str,
    current_user: dict = Depends(get_current_user_dep),
    db: AsyncSession = Depends(get_db)
):
    """
    Get invoice history for a tenant from Stripe
    """
    try:
        # Verify tenant exists
        query = select(Tenant).where(Tenant.id == UUID(tenant_id))
        result = await db.execute(query)
        tenant = result.scalar_one_or_none()

        if not tenant:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Tenant not found"
            )

        # Check if tenant has a Stripe customer ID
        if not tenant.stripe_customer_id:
            logger.info("no_stripe_customer_id", tenant_id=tenant_id)
            return []

        # Initialize Stripe provider
        stripe_provider = StripeProvider(
            api_key=settings.STRIPE_SECRET_KEY,
            webhook_secret=settings.STRIPE_WEBHOOK_SECRET
        )

        # Fetch invoices from Stripe
        stripe_invoices = await stripe_provider.get_invoices(tenant.stripe_customer_id)

        # Transform to response format
        invoices = []
        for invoice in stripe_invoices:
            invoices.append(InvoiceResponse(
                id=invoice.id,
                date=invoice.created_at.strftime('%Y-%m-%d'),
                amount=invoice.amount,
                currency=invoice.currency.upper(),
                status=invoice.status,
                description=invoice.description,
                invoice_pdf=invoice.invoice_pdf,
                hosted_invoice_url=invoice.hosted_invoice_url
            ))

        logger.info("invoices_retrieved", tenant_id=tenant_id, count=len(invoices))
        return invoices

    except HTTPException:
        raise
    except Exception as e:
        logger.error("get_invoices_failed", error=str(e), tenant_id=tenant_id)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve invoices"
        )
