"""Portfolio skills — manage user's card portfolio and check eligibility rules."""

from __future__ import annotations

from datetime import date, timedelta

from sqlalchemy import or_

from luca_assistant.db.engine import get_session
from luca_assistant.db.models import Card, UserCard


def get_user_portfolio() -> dict:
    """List all cards in the user's portfolio."""
    session = get_session()
    try:
        user_cards = (
            session.query(UserCard, Card).join(Card).order_by(UserCard.opened_date.desc()).all()
        )

        if not user_cards:
            return {
                "portfolio": [],
                "message": "No cards in portfolio yet. Use luca_add_user_card to add cards.",
            }

        cards = []
        for uc, card in user_cards:
            cards.append(
                {
                    "bank": card.bank,
                    "name": card.name,
                    "opened_date": str(uc.opened_date),
                    "closed_date": str(uc.closed_date) if uc.closed_date else None,
                    "is_open": uc.closed_date is None,
                    "annual_fee": card.annual_fee,
                    "annual_fee_due": str(uc.annual_fee_due) if uc.annual_fee_due else None,
                    "credit_limit": uc.credit_limit,
                    "bonus_earned": uc.bonus_earned,
                    "bonus_met_date": str(uc.bonus_met_date) if uc.bonus_met_date else None,
                    "notes": uc.notes,
                }
            )

        return {"portfolio": cards, "total_open": sum(1 for c in cards if c["is_open"])}
    finally:
        session.close()


def check_chase_524_status() -> dict:
    """Check how many cards count toward 5/24."""
    session = get_session()
    try:
        cutoff = date.today() - timedelta(days=730)  # ~24 months

        user_cards = (
            session.query(UserCard, Card)
            .join(Card)
            .filter(UserCard.opened_date >= cutoff)
            .order_by(UserCard.opened_date.desc())
            .all()
        )

        # All new cards count toward 5/24 (including biz cards from other issuers,
        # but NOT Chase biz cards — they don't report to personal credit)
        counting_cards = []
        non_counting_cards = []

        for uc, card in user_cards:
            entry = {
                "bank": card.bank,
                "name": card.name,
                "opened_date": str(uc.opened_date),
                "is_business": card.is_business,
            }
            # Chase business cards don't count toward 5/24
            if card.is_business and card.bank == "Chase":
                non_counting_cards.append(entry)
            else:
                counting_cards.append(entry)

        count = len(counting_cards)
        slots_remaining = max(0, 5 - count)

        # Find next card to fall off
        next_falloff = None
        if counting_cards:
            oldest = counting_cards[-1]
            falloff_date = date.fromisoformat(oldest["opened_date"]) + timedelta(days=730)
            next_falloff = {
                "card": f"{oldest['bank']} {oldest['name']}",
                "falls_off": str(falloff_date),
            }

        return {
            "count_524": count,
            "slots_remaining": slots_remaining,
            "is_under_524": count < 5,
            "counting_cards": counting_cards,
            "non_counting_cards": non_counting_cards,
            "next_falloff": next_falloff,
        }
    finally:
        session.close()


def add_user_card(
    card_name: str,
    opened_date: str,
    bank: str | None = None,
    credit_limit: int | None = None,
    bonus_earned: bool = False,
    bonus_met_date: str | None = None,
    notes: str | None = None,
) -> dict:
    """Add a card to the user's portfolio."""
    session = get_session()
    try:
        query = session.query(Card).filter(
            or_(
                Card.name.ilike(f"%{card_name}%"),
                Card.full_name.ilike(f"%{card_name}%"),
            )
        )
        if bank:
            query = query.filter(Card.bank.ilike(f"%{bank}%"))

        card = query.first()
        if not card:
            return {"error": f"Card not found: '{card_name}'. Check the name or add bank filter."}

        parsed_date = date.fromisoformat(opened_date)
        # Safe annual-fee due date: handle Feb 29 → Feb 28 in non-leap years
        try:
            af_due = parsed_date.replace(year=parsed_date.year + 1)
        except ValueError:
            af_due = date(parsed_date.year + 1, parsed_date.month, 28)

        user_card = UserCard(
            card_id=card.id,
            opened_date=parsed_date,
            annual_fee_due=af_due if card.annual_fee > 0 else None,
            credit_limit=credit_limit,
            bonus_earned=bonus_earned,
            bonus_met_date=date.fromisoformat(bonus_met_date) if bonus_met_date else None,
            notes=notes,
        )
        session.add(user_card)
        session.commit()

        return {
            "success": True,
            "card": f"{card.bank} {card.name}",
            "opened_date": str(parsed_date),
            "annual_fee_due": str(af_due) if card.annual_fee > 0 else None,
        }
    except Exception as e:
        session.rollback()
        return {"error": str(e)}
    finally:
        session.close()


def close_user_card(card_name: str, closed_date: str, bank: str | None = None) -> dict:
    """Mark a user's card as closed."""
    session = get_session()
    try:
        query = (
            session.query(UserCard)
            .join(Card)
            .filter(
                or_(
                    Card.name.ilike(f"%{card_name}%"),
                    Card.full_name.ilike(f"%{card_name}%"),
                ),
                UserCard.closed_date.is_(None),
            )
        )
        if bank:
            query = query.filter(Card.bank.ilike(f"%{bank}%"))

        user_card = query.first()
        if not user_card:
            return {"error": f"No open card found matching '{card_name}' in portfolio"}

        user_card.closed_date = date.fromisoformat(closed_date)
        session.commit()

        card = session.get(Card, user_card.card_id)
        return {
            "success": True,
            "card": f"{card.bank} {card.name}",
            "closed_date": closed_date,
        }
    except Exception as e:
        session.rollback()
        return {"error": str(e)}
    finally:
        session.close()
