"""SQLAlchemy ORM models for Luca's card database."""

from __future__ import annotations

from datetime import UTC, date, datetime

from sqlalchemy import JSON, Boolean, Date, DateTime, Float, ForeignKey, Integer, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


class Base(DeclarativeBase):
    pass


class Card(Base):
    __tablename__ = "cards"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    bank: Mapped[str] = mapped_column(String(50), nullable=False, index=True)
    name: Mapped[str] = mapped_column(String(100), nullable=False)
    full_name: Mapped[str] = mapped_column(String(200), nullable=False)
    network: Mapped[str] = mapped_column(String(20), nullable=False)  # Visa, Mastercard, Amex
    annual_fee: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    annual_fee_waived_first_year: Mapped[bool] = mapped_column(Boolean, default=False)
    product_family: Mapped[str | None] = mapped_column(String(50), nullable=True)
    is_business: Mapped[bool] = mapped_column(Boolean, default=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=True)
    is_secured: Mapped[bool] = mapped_column(Boolean, default=False)
    purchase_apr_min: Mapped[float | None] = mapped_column(Float, nullable=True)
    purchase_apr_max: Mapped[float | None] = mapped_column(Float, nullable=True)
    foreign_transaction_fee_pct: Mapped[float | None] = mapped_column(Float, nullable=True)
    late_fee: Mapped[int | None] = mapped_column(Integer, nullable=True)
    grace_period_days: Mapped[int | None] = mapped_column(Integer, nullable=True)
    cfpb_data: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(UTC))
    updated_at: Mapped[datetime] = mapped_column(
        DateTime, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC)
    )

    offers: Mapped[list[CardOffer]] = relationship(back_populates="card", cascade="all, delete")
    benefits: Mapped[list[CardBenefit]] = relationship(back_populates="card", cascade="all, delete")
    user_cards: Mapped[list[UserCard]] = relationship(back_populates="card")

    def __repr__(self) -> str:
        return f"<Card {self.bank} {self.name}>"


class CardOffer(Base):
    __tablename__ = "card_offers"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    card_id: Mapped[int] = mapped_column(ForeignKey("cards.id"), nullable=False, index=True)
    bonus_amount: Mapped[str] = mapped_column(String(100), nullable=False)  # e.g. "60,000 UR"
    bonus_value_usd: Mapped[int] = mapped_column(Integer, nullable=False)  # estimated $ value
    spend_requirement: Mapped[int] = mapped_column(Integer, nullable=False)  # in dollars
    spend_timeframe_months: Mapped[int] = mapped_column(Integer, nullable=False, default=3)
    source_url: Mapped[str | None] = mapped_column(Text, nullable=True)
    is_current: Mapped[bool] = mapped_column(Boolean, default=True)
    is_highest_known: Mapped[bool] = mapped_column(Boolean, default=False)
    first_seen: Mapped[date] = mapped_column(Date, default=date.today)
    last_seen: Mapped[date] = mapped_column(Date, default=date.today)

    card: Mapped[Card] = relationship(back_populates="offers")

    def __repr__(self) -> str:
        return f"<CardOffer {self.bonus_amount} for card_id={self.card_id}>"


class CardBenefit(Base):
    __tablename__ = "card_benefits"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    card_id: Mapped[int] = mapped_column(ForeignKey("cards.id"), nullable=False, index=True)
    category: Mapped[str] = mapped_column(String(50), nullable=False)  # dining, travel, grocery
    multiplier: Mapped[float] = mapped_column(Float, nullable=False, default=1.0)
    points_type: Mapped[str] = mapped_column(String(20), nullable=False)  # UR, MR, TYP, cashback
    annual_credit: Mapped[int | None] = mapped_column(Integer, nullable=True)
    credit_category: Mapped[str | None] = mapped_column(String(50), nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

    card: Mapped[Card] = relationship(back_populates="benefits")

    def __repr__(self) -> str:
        return f"<CardBenefit {self.category} {self.multiplier}x for card_id={self.card_id}>"


class BankRule(Base):
    __tablename__ = "bank_rules"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    bank: Mapped[str] = mapped_column(String(50), nullable=False, index=True)
    rule_name: Mapped[str] = mapped_column(String(100), nullable=False)
    description: Mapped[str] = mapped_column(Text, nullable=False)
    rule_type: Mapped[str] = mapped_column(String(30), nullable=False)  # velocity, eligibility
    parameters: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    def __repr__(self) -> str:
        return f"<BankRule {self.bank} {self.rule_name}>"


class UserCard(Base):
    __tablename__ = "user_cards"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    card_id: Mapped[int] = mapped_column(ForeignKey("cards.id"), nullable=False, index=True)
    opened_date: Mapped[date] = mapped_column(Date, nullable=False)
    closed_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    annual_fee_due: Mapped[date | None] = mapped_column(Date, nullable=True)
    credit_limit: Mapped[int | None] = mapped_column(Integer, nullable=True)
    bonus_earned: Mapped[bool] = mapped_column(Boolean, default=False)
    bonus_met_date: Mapped[date | None] = mapped_column(Date, nullable=True)
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)

    card: Mapped[Card] = relationship(back_populates="user_cards")

    def __repr__(self) -> str:
        return f"<UserCard card_id={self.card_id} opened={self.opened_date}>"
