"""Tests for card query skills."""

from __future__ import annotations

from sqlalchemy.orm import Session

from luca_assistant.skills.card_query import (
    compare_card_benefits,
    find_highest_offers,
    get_bank_rules,
    query_card_details,
)
from luca_assistant.skills.card_update import update_card_benefit


class TestQueryCardDetails:
    def test_find_by_name(self, db_session: Session) -> None:
        result = query_card_details("Sapphire Preferred")
        assert "error" not in result
        assert result["bank"] == "Chase"
        assert result["annual_fee"] == 95

    def test_find_by_partial_name(self, db_session: Session) -> None:
        result = query_card_details("Platinum", bank="Amex")
        assert "error" not in result
        # "Platinum" matches multiple Amex cards (Platinum, Delta Platinum, etc.)
        if "cards" in result:
            banks = {c["bank"] for c in result["cards"]}
            assert "Amex" in banks
        else:
            assert result["bank"] == "Amex"

    def test_includes_current_offers(self, db_session: Session) -> None:
        result = query_card_details("Sapphire Preferred")
        assert len(result["current_offers"]) > 0
        offer = result["current_offers"][0]
        assert "bonus" in offer
        assert offer["value_usd"] > 0

    def test_includes_benefits(self, db_session: Session) -> None:
        result = query_card_details("Sapphire Preferred")
        assert len(result["benefits"]) > 0
        categories = {b["category"] for b in result["benefits"]}
        assert "dining" in categories

    def test_card_not_found(self, db_session: Session) -> None:
        result = query_card_details("Nonexistent Card XYZ")
        assert "error" in result

    def test_bank_filter(self, db_session: Session) -> None:
        result = query_card_details("Gold", bank="Amex")
        assert "error" not in result
        # "Gold" matches Gold, Business Gold, Delta Gold
        if "cards" in result:
            assert all(c["bank"] == "Amex" for c in result["cards"])
        else:
            assert result["bank"] == "Amex"

    def test_multiple_matches_returns_list(self, db_session: Session) -> None:
        result = query_card_details("Freedom")
        assert "cards" in result
        assert len(result["cards"]) >= 2


class TestFindHighestOffers:
    def test_returns_offers_sorted(self, db_session: Session) -> None:
        result = find_highest_offers()
        assert len(result["offers"]) > 0
        # Should be sorted by value descending
        values = [o["bonus_value_usd"] for o in result["offers"]]
        assert values == sorted(values, reverse=True)

    def test_filter_by_bank(self, db_session: Session) -> None:
        result = find_highest_offers(bank="Chase")
        for offer in result["offers"]:
            assert offer["bank"] == "Chase"

    def test_filter_by_min_bonus(self, db_session: Session) -> None:
        result = find_highest_offers(min_bonus_usd=1000)
        for offer in result["offers"]:
            assert offer["bonus_value_usd"] >= 1000

    def test_filter_business_only(self, db_session: Session) -> None:
        result = find_highest_offers(is_business=True)
        for offer in result["offers"]:
            assert offer["is_business"] is True

    def test_limit_results(self, db_session: Session) -> None:
        result = find_highest_offers(limit=3)
        assert len(result["offers"]) <= 3


class TestCompareCardBenefits:
    def test_compare_two_cards(self, db_session: Session) -> None:
        result = compare_card_benefits(["Sapphire Preferred", "Sapphire Reserve"])
        assert len(result["comparison"]) == 2
        names = {c["name"] for c in result["comparison"] if "name" in c}
        assert "Sapphire Preferred" in names
        assert "Sapphire Reserve" in names

    def test_compare_includes_offers(self, db_session: Session) -> None:
        result = compare_card_benefits(["Sapphire Preferred"])
        card = result["comparison"][0]
        assert card["current_offer"] is not None
        assert card["current_offer"]["value_usd"] > 0

    def test_unknown_card_in_comparison(self, db_session: Session) -> None:
        result = compare_card_benefits(["Sapphire Preferred", "Fake Card"])
        assert len(result["comparison"]) == 2
        assert "error" in result["comparison"][1]


class TestMultiplierHint:
    def test_hint_absent_when_multipliers_exist(self, db_session: Session) -> None:
        result = query_card_details("Sapphire Preferred")
        assert "multiplier_hint" not in result

    def test_hint_present_when_no_multipliers(self, db_session: Session) -> None:
        # Bilt has multipliers from curated seed, but Robinhood Gold does not
        result = query_card_details("Gold Card", bank="Robinhood")
        if "error" not in result:
            assert "multiplier_hint" in result
            assert "doctorofcredit.com" in result["multiplier_hint"]
            assert "thepointsguy.com" in result["multiplier_hint"]


class TestGetBankRules:
    def test_chase_rules(self, db_session: Session) -> None:
        result = get_bank_rules("Chase")
        assert "rules" in result
        rule_names = {r["name"] for r in result["rules"]}
        assert "5/24" in rule_names
        assert "One Sapphire Rule" in rule_names

    def test_amex_rules(self, db_session: Session) -> None:
        result = get_bank_rules("Amex")
        rule_names = {r["name"] for r in result["rules"]}
        assert "Lifetime Language" in rule_names

    def test_unknown_bank(self, db_session: Session) -> None:
        result = get_bank_rules("Unknown Bank")
        assert "error" in result


class TestUpdateCardBenefit:
    def test_create_new_benefit(self, db_session: Session) -> None:
        result = update_card_benefit(
            card_name="Sapphire Reserve",
            category="test_category",
            multiplier=5.0,
            points_type="UR",
            notes="Test note",
        )
        assert result["status"] == "ok"
        assert result["action"] == "created"
        assert result["multiplier"] == 5.0

    def test_update_existing_benefit(self, db_session: Session) -> None:
        # Sapphire Preferred has "dining" at 3x from curated seed
        result = update_card_benefit(
            card_name="Sapphire Preferred",
            category="dining",
            multiplier=4.0,
            points_type="UR",
        )
        assert result["status"] == "ok"
        assert result["action"] == "updated"

        # Verify the update persisted
        detail = query_card_details("Sapphire Preferred")
        dining = next(b for b in detail["benefits"] if b["category"] == "dining")
        assert dining["multiplier"] == 4.0

    def test_card_not_found(self, db_session: Session) -> None:
        result = update_card_benefit(
            card_name="Nonexistent Card",
            category="dining",
            multiplier=3.0,
            points_type="UR",
        )
        assert "error" in result
