from typing import Optional

from sqlmodel import Session, select

from app.models import Subscription
from app.models.base import _utcnow


class SubscriptionRepository:
    def __init__(self, session: Session):
        self.session = session

    def get_latest(self, user_id: str) -> Optional[Subscription]:
        """Get the most recent subscription for a user."""
        return self.session.exec(
            select(Subscription)
            .where(Subscription.user_id == user_id)
            .order_by(Subscription.expiry_date.desc())  # type: ignore
        ).first()

    def get_active(self, user_id: str) -> Optional[Subscription]:
        """Get active subscription for a user."""
        return self.session.exec(
            select(Subscription)
            .where(
                Subscription.user_id == user_id,
                Subscription.status.in_(["active", "grace_period", "pending_verification"]),  # type: ignore
            )
            .order_by(Subscription.expiry_date.desc())  # type: ignore
        ).first()

    def get_by_token(self, purchase_token: str) -> Optional[Subscription]:
        return self.session.exec(
            select(Subscription).where(Subscription.purchase_token == purchase_token)
        ).first()

    def upsert_by_token(
        self,
        user_id: str,
        order_id: str,
        product_id: str,
        purchase_token: str,
        status: str,
        payment_state: int,
        expiry_date: Optional[str],
    ) -> Subscription:
        """Create or update subscription by purchase_token."""
        existing = self.get_by_token(purchase_token)
        if existing:
            # Don't overwrite terminal statuses with pending
            if existing.status in ("expired", "revoked") and status == "pending_verification":
                status = existing.status
            existing.status = status
            existing.payment_state = payment_state
            existing.expiry_date = expiry_date
            existing.updated_at = _utcnow()
            self.session.commit()
            return existing
        else:
            sub = Subscription(
                user_id=user_id,
                order_id=order_id,
                product_id=product_id,
                purchase_token=purchase_token,
                status=status,
                payment_state=payment_state,
                expiry_date=expiry_date,
            )
            self.session.add(sub)
            self.session.commit()
            return sub

    def update_status_by_token(
        self, purchase_token: str, status: str, expiry_date: Optional[str]
    ) -> bool:
        """Update subscription status via webhook. Returns True if found."""
        sub = self.get_by_token(purchase_token)
        if not sub:
            return False
        sub.status = status
        sub.expiry_date = expiry_date
        sub.updated_at = _utcnow()
        self.session.commit()
        return True
