from datetime import date, datetime
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel, ConfigDict

from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.models import Subscription, Customer, Product, SubscriptionStatus, BillingCycle
from app.api.auth import get_current_user

router = APIRouter(prefix="/api/subscriptions", tags=["subscriptions"])


# ── Pydantic models ──────────────────────────────────────────────────────────

class SubscriptionBase(BaseModel):
    customer_id: int
    product_id: int
    start_date: date
    end_date: date | None = None
    billing_cycle: str = "monthly"
    status: str = "active"
    auto_renew: bool = False
    next_invoice_date: date | None = None


class SubscriptionCreate(SubscriptionBase):
    pass


class SubscriptionUpdate(BaseModel):
    customer_id: int | None = None
    product_id: int | None = None
    start_date: date | None = None
    end_date: date | None = None
    billing_cycle: str | None = None
    status: str | None = None
    auto_renew: bool | None = None
    next_invoice_date: date | None = None


class SubscriptionResponse(SubscriptionBase):
    id: int
    created_at: datetime
    customer_name: str | None = None
    product_name: str | None = None
    last_invoice_id: int | None = None

    model_config = ConfigDict(from_attributes=True)


class PaginatedSubscriptions(BaseModel):
    items: list[SubscriptionResponse]
    total: int
    page: int
    page_size: int


# ── Helpers ───────────────────────────────────────────────────────────────────

def _subscription_to_response(sub: Subscription) -> SubscriptionResponse:
    return SubscriptionResponse(
        id=sub.id,
        customer_id=sub.customer_id,
        product_id=sub.product_id,
        start_date=sub.start_date,
        end_date=sub.end_date,
        billing_cycle=sub.billing_cycle.value if sub.billing_cycle else "monthly",
        status=sub.status.value if sub.status else "active",
        auto_renew=sub.auto_renew,
        next_invoice_date=sub.next_invoice_date,
        created_at=sub.created_at,
        customer_name=sub.customer.name if sub.customer else None,
        product_name=sub.product.name if sub.product else None,
        last_invoice_id=sub.last_invoice_id,
    )


# ── Endpoints ─────────────────────────────────────────────────────────────────

@router.get("", response_model=PaginatedSubscriptions)
def list_subscriptions(
    current_user: Annotated[dict, Depends(get_current_user)],
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    customer_id: int | None = Query(None),
    status_filter: str | None = Query(None, alias="status"),
    product_id: int | None = Query(None),
    db=Depends(get_db),
):
    """List all subscriptions with pagination and filtering."""
    query = db.query(Subscription).join(Customer).join(Product)

    if customer_id is not None:
        query = query.filter(Subscription.customer_id == customer_id)

    if status_filter:
        query = query.filter(Subscription.status == status_filter)

    if product_id is not None:
        query = query.filter(Subscription.product_id == product_id)

    total = query.count()
    items = (
        query.order_by(Subscription.id.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
        .all()
    )

    return PaginatedSubscriptions(
        items=[_subscription_to_response(s) for s in items],
        total=total,
        page=page,
        page_size=page_size,
    )


@router.post("", response_model=SubscriptionResponse, status_code=status.HTTP_201_CREATED)
def create_subscription(
    data: SubscriptionCreate,
    current_user: Annotated[dict, Depends(get_current_user)],
    db=Depends(get_db),
):
    """Create a new subscription."""
    # Validate customer exists
    customer = db.get(Customer, data.customer_id)
    if not customer:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")

    # Validate product exists
    product = db.get(Product, data.product_id)
    if not product:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Product not found")

    sub = Subscription(
        customer_id=data.customer_id,
        product_id=data.product_id,
        start_date=data.start_date,
        end_date=data.end_date,
        billing_cycle=BillingCycle(data.billing_cycle) if data.billing_cycle else BillingCycle.monthly,
        status=SubscriptionStatus(data.status) if data.status else SubscriptionStatus.active,
        auto_renew=data.auto_renew,
        next_invoice_date=data.next_invoice_date,
    )
    db.add(sub)
    db.commit()
    db.refresh(sub)
    return _subscription_to_response(sub)


@router.get("/{subscription_id}", response_model=SubscriptionResponse)
def get_subscription(
    subscription_id: int,
    current_user: Annotated[dict, Depends(get_current_user)],
    db=Depends(get_db),
):
    """Get a single subscription by ID with customer and product names."""
    sub = (
        db.query(Subscription)
        .join(Customer)
        .join(Product)
        .filter(Subscription.id == subscription_id)
        .first()
    )
    if not sub:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Subscription not found")
    return _subscription_to_response(sub)


@router.put("/{subscription_id}", response_model=SubscriptionResponse)
def update_subscription(
    subscription_id: int,
    data: SubscriptionUpdate,
    current_user: Annotated[dict, Depends(get_current_user)],
    db=Depends(get_db),
):
    """Update an existing subscription."""
    sub = db.get(Subscription, subscription_id)
    if not sub:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Subscription not found")

    update_data = data.model_dump(exclude_unset=True)

    # Validate customer_id if provided
    if "customer_id" in update_data:
        customer = db.get(Customer, update_data["customer_id"])
        if not customer:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")

    # Validate product_id if provided
    if "product_id" in update_data:
        product = db.get(Product, update_data["product_id"])
        if not product:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Product not found")

    # Convert enum fields
    if "billing_cycle" in update_data and update_data["billing_cycle"]:
        update_data["billing_cycle"] = BillingCycle(update_data["billing_cycle"])
    if "status" in update_data and update_data["status"]:
        update_data["status"] = SubscriptionStatus(update_data["status"])

    for field, value in update_data.items():
        setattr(sub, field, value)

    db.commit()
    db.refresh(sub)
    return _subscription_to_response(sub)


@router.delete("/{subscription_id}", status_code=status.HTTP_204_NO_CONTENT)
def cancel_subscription(
    subscription_id: int,
    current_user: Annotated[dict, Depends(get_current_user)],
    db: Session = Depends(get_db),
):
    """Cancel a subscription (soft delete - sets status to cancelled)."""
    sub = db.get(Subscription, subscription_id)
    if not sub:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Subscription not found")

    sub.status = SubscriptionStatus.cancelled
    db.commit()