"""Tests for database models and seed data."""

from __future__ import annotations

from datetime import date

from sqlalchemy.orm import Session

from luca_assistant.db.models import BankRule, Card, CardBenefit, CardOffer, UserCard


class TestCardModel:
    def test_seed_creates_cards(self, db_session: Session) -> None:
        cards = db_session.query(Card).all()
        assert len(cards) >= 10  # Fallback seed has ~16, Offer Optimist has ~150

    def test_chase_cards_exist(self, db_session: Session) -> None:
        chase_cards = db_session.query(Card).filter(Card.bank == "Chase").all()
        names = {c.name for c in chase_cards}
        assert "Sapphire Preferred" in names
        assert "Sapphire Reserve" in names
        assert "Freedom Flex" in names

    def test_card_relationships(self, db_session: Session) -> None:
        csp = db_session.query(Card).filter(Card.name == "Sapphire Preferred").first()
        assert csp is not None
        assert csp.bank == "Chase"
        assert len(csp.offers) > 0
        assert len(csp.benefits) > 0

    def test_business_cards_flagged(self, db_session: Session) -> None:
        biz_cards = db_session.query(Card).filter(Card.is_business.is_(True)).all()
        assert len(biz_cards) >= 3  # Ink cards + Amex biz
        for card in biz_cards:
            assert card.is_business is True


class TestCardOfferModel:
    def test_offers_exist(self, db_session: Session) -> None:
        offers = db_session.query(CardOffer).all()
        assert len(offers) >= 10

    def test_offer_values_reasonable(self, db_session: Session) -> None:
        offers = db_session.query(CardOffer).filter(CardOffer.bonus_value_usd > 0).all()
        for offer in offers:
            assert offer.spend_requirement >= 0
            assert offer.spend_timeframe_months >= 0
            assert offer.bonus_value_usd > 0

    def test_offer_card_relationship(self, db_session: Session) -> None:
        offer = db_session.query(CardOffer).first()
        assert offer.card is not None
        assert offer.card.bank is not None


class TestCardBenefitModel:
    def test_benefits_exist(self, db_session: Session) -> None:
        benefits = db_session.query(CardBenefit).all()
        assert len(benefits) >= 20

    def test_multipliers_positive(self, db_session: Session) -> None:
        benefits = db_session.query(CardBenefit).all()
        for b in benefits:
            assert b.multiplier >= 1.0


class TestBankRuleModel:
    def test_rules_exist(self, db_session: Session) -> None:
        rules = db_session.query(BankRule).all()
        assert len(rules) >= 5

    def test_chase_524_rule(self, db_session: Session) -> None:
        rule = (
            db_session.query(BankRule)
            .filter(BankRule.bank == "Chase", BankRule.rule_name == "5/24")
            .first()
        )
        assert rule is not None
        assert rule.parameters["window_months"] == 24
        assert rule.parameters["max_cards"] == 4

    def test_amex_lifetime_rule(self, db_session: Session) -> None:
        rule = (
            db_session.query(BankRule)
            .filter(BankRule.bank == "Amex", BankRule.rule_name == "Lifetime Language")
            .first()
        )
        assert rule is not None


class TestUserCardModel:
    def test_add_user_card(self, db_session: Session) -> None:
        csp = db_session.query(Card).filter(Card.name == "Sapphire Preferred").first()
        uc = UserCard(
            card_id=csp.id,
            opened_date=date(2024, 6, 15),
            credit_limit=10000,
        )
        db_session.add(uc)
        db_session.commit()

        result = db_session.query(UserCard).filter(UserCard.card_id == csp.id).first()
        assert result is not None
        assert result.opened_date == date(2024, 6, 15)
        assert result.credit_limit == 10000
        assert result.closed_date is None

    def test_close_user_card(self, db_session: Session) -> None:
        csp = db_session.query(Card).filter(Card.name == "Sapphire Preferred").first()
        uc = UserCard(
            card_id=csp.id,
            opened_date=date(2023, 1, 1),
        )
        db_session.add(uc)
        db_session.commit()

        uc.closed_date = date(2024, 1, 1)
        db_session.commit()

        result = db_session.query(UserCard).filter(UserCard.card_id == csp.id).first()
        assert result.closed_date == date(2024, 1, 1)
