"""
Tarot spread definitions and management with card drawing.

Provides predefined spreads like Celtic Cross, Golden Dawn (3-card), etc.
with position meanings and automatic card drawing.

Usage:
    from tarot import Tarot

    # Draw cards for a spread
    reading = Tarot.deck.card.spread('Celtic Cross')
    print(reading)

    # Can also access spread with/without cards
    from tarot.card.spread import Spread, draw_spread

    spread = Spread('Celtic Cross')
    reading = draw_spread(spread)  # Returns list of (position, card) tuples
"""

import random
from dataclasses import dataclass
from typing import TYPE_CHECKING, Dict, List, Optional

if TYPE_CHECKING:
    from tarot.card import Card


@dataclass
class SpreadPosition:
    """Represents a position in a Tarot spread."""

    number: int
    name: str
    meaning: str
    reversed_meaning: Optional[str] = None

    def __str__(self) -> str:
        result = f"{self.number}. {self.name}: {self.meaning}"
        if self.reversed_meaning:
            result += f"\n   (Reversed: {self.reversed_meaning})"
        return result


@dataclass
class DrawnCard:
    """Represents a card drawn for a spread position."""

    position: SpreadPosition
    card: "Card"
    is_reversed: bool

    def __str__(self) -> str:
        """Format the drawn card with position and interpretation."""
        card_name = self.card.name
        if self.is_reversed:
            card_name += " (Reversed)"

        return (
            f"{self.position.number}. {self.position.name}\n"
            f"    └─ {card_name}\n"
            f"    └─ Position: {self.position.meaning}"
        )


class Spread:
    """Represents a Tarot spread with positions and meanings."""

    # Define all available spreads
    SPREADS: Dict[str, Dict] = {
        "three card": {
            "name": "3-Card Spread",
            "description": (
                "Simple 3-card spread for past, present, future "
                "or situation, action, outcome"
            ),
            "positions": [
                SpreadPosition(1, "First Position", "Past, Foundation, or Situation"),
                SpreadPosition(2, "Second Position", "Present, Action, or Influence"),
                SpreadPosition(3, "Third Position", "Future, Outcome, or Advice"),
            ],
        },
        "golden dawn": {
            "name": "Golden Dawn 3-Card",
            "description": "Three card spread used in Golden Dawn tradition",
            "positions": [
                SpreadPosition(1, "Supernal Triangle", "Spiritual/Divine aspect"),
                SpreadPosition(2, "Pillar of Severity", "Challenging/Active force"),
                SpreadPosition(3, "Pillar of Mercy", "Supportive/Passive force"),
            ],
        },
        "celtic cross": {
            "name": "Celtic Cross",
            "description": "Classic 10-card spread for in-depth reading",
            "positions": [
                SpreadPosition(1, "The Significator", "The main situation or person"),
                SpreadPosition(2, "The Cross", "The challenge or heart of the matter"),
                SpreadPosition(3, "Crowning Influence", "Conscious hopes/ideals"),
                SpreadPosition(4, "Beneath the Cross", "Unconscious or hidden aspects"),
                SpreadPosition(5, "Behind", "Past influences"),
                SpreadPosition(6, "Before", "Future influences"),
                SpreadPosition(7, "Self/Attitude", "How the querent sees themselves"),
                SpreadPosition(8, "Others/Environment", "External factors/opinions"),
                SpreadPosition(9, "Hopes and Fears", "What the querent hopes for or fears"),
                SpreadPosition(10, "Outcome", "Final outcome or resolution"),
            ],
        },
        "horseshoe": {
            "name": "Horseshoe",
            "description": "7-card spread in horseshoe formation for past, present, future insight",
            "positions": [
                SpreadPosition(1, "Distant Past", "Ancient influences and foundations"),
                SpreadPosition(2, "Recent Past", "Recent events and circumstances"),
                SpreadPosition(3, "Present Situation", "Current state of affairs"),
                SpreadPosition(4, "Immediate Future", "Near-term developments"),
                SpreadPosition(5, "Distant Future", "Long-term outcome"),
                SpreadPosition(6, "Inner Influence", "Self/thoughts/emotions"),
                SpreadPosition(7, "Outer Influence", "External forces and environment"),
            ],
        },
        "pentagram": {
            "name": "Pentagram",
            "description": "5-card spread based on Earth element pentagram",
            "positions": [
                SpreadPosition(1, "Spirit", "Core essence or spiritual truth"),
                SpreadPosition(2, "Fire", "Action and willpower"),
                SpreadPosition(3, "Water", "Emotions and intuition"),
                SpreadPosition(4, "Air", "Intellect and communication"),
                SpreadPosition(5, "Earth", "Physical manifestation and grounding"),
            ],
        },
        "tree of life": {
            "name": "Tree of Life",
            "description": "10-card spread mapping Sephiroth on the Tree of Life",
            "positions": [
                SpreadPosition(1, "Kether (Crown)", "Divine will and unity"),
                SpreadPosition(2, "Chokmah (Wisdom)", "Creative force and impulse"),
                SpreadPosition(3, "Binah (Understanding)", "Form and structure"),
                SpreadPosition(4, "Chesed (Mercy)", "Expansion and abundance"),
                SpreadPosition(5, "Gevurah (Severity)", "Reduction and discipline"),
                SpreadPosition(6, "Tiphareth (Beauty)", "Core self and integration"),
                SpreadPosition(7, "Netzach (Victory)", "Desire and passion"),
                SpreadPosition(8, "Hod (Splendor)", "Intellect and communication"),
                SpreadPosition(9, "Yesod (Foundation)", "Subconscious and dreams"),
                SpreadPosition(10, "Malkuth (Kingdom)", "Manifestation and physical reality"),
            ],
        },
        "relationship": {
            "name": "Relationship",
            "description": "5-card spread for relationship insight",
            "positions": [
                SpreadPosition(1, "You", "Your position, feelings, or role"),
                SpreadPosition(2, "Them", "Their position, feelings, or perspective"),
                SpreadPosition(3, "The Relationship", "The dynamic and connection"),
                SpreadPosition(4, "Challenge", "Current challenge or friction point"),
                SpreadPosition(5, "Outcome", "Where the relationship is heading"),
            ],
        },
        "yes or no": {
            "name": "Yes or No",
            "description": "1-card spread for simple yes/no answers",
            "positions": [
                SpreadPosition(
                    1, "Answer", "Major Arcana = Yes, Minor Arcana = No, Court Cards = Maybe"
                ),
            ],
        },
    }

    def __init__(self, spread_name: str) -> None:
        """
        Initialize a spread by name (case-insensitive).

        Args:
            spread_name: Name of the spread to use

        Raises:
            ValueError: If spread name not found
        """
        # Normalize name (case-insensitive, allow underscores or spaces)
        normalized_name = spread_name.lower().replace("_", " ")

        # Find matching spread
        spread_data = None
        for key, data in self.SPREADS.items():
            if key == normalized_name or data["name"].lower() == normalized_name:
                spread_data = data
                break

        if not spread_data:
            available = ", ".join(f"'{k}'" for k in self.SPREADS.keys())
            raise ValueError(f"Spread '{spread_name}' not found. Available spreads: {available}")

        self.name = spread_data["name"]
        self.description = spread_data["description"]
        self.positions: List[SpreadPosition] = spread_data["positions"]

    def __str__(self) -> str:
        """Return formatted spread information."""
        lines = [
            "═══════════════════════════════════════════",
            f"  {self.name}",
            "═══════════════════════════════════════════",
            "",
            f"{self.description}",
            "",
            f"Positions ({len(self.positions)} cards):",
            "",
        ]

        for pos in self.positions:
            lines.append(f"  {pos}")

        lines.append("")
        lines.append("═══════════════════════════════════════════")

        return "\n".join(lines)

    def __repr__(self) -> str:
        return f"Spread('{self.name}')"

    @classmethod
    def available_spreads(cls) -> str:
        """Return list of all available spreads."""
        lines = ["Available Tarot Spreads:", "═" * 50, ""]

        for key, data in cls.SPREADS.items():
            lines.append(f"  • {data['name']}")
            lines.append(f"    Name for API: '{key}'")
            lines.append(f"    Positions: {len(data['positions'])}")
            lines.append(f"    {data['description']}")
            lines.append("")

        return "\n".join(lines)

    def get_position(self, position_number: int) -> Optional[SpreadPosition]:
        """Get a specific position by number."""
        for pos in self.positions:
            if pos.number == position_number:
                return pos
        return None


def draw_spread(spread: Spread, deck: Optional[List] = None) -> List[DrawnCard]:
    """
    Draw cards for all positions in a spread.

    Ensures all drawn cards are unique (no duplicates in a single spread).

    Args:
        spread: The Spread object with positions defined
        deck: Optional list of Card objects. If None, uses Tarot.deck.cards

    Returns:
        List of DrawnCard objects (one per position) with random cards and reversals

    Raises:
        ValueError: If spread has more positions than cards in the deck
    """

    # Load deck if not provided
    if deck is None:
        from tarot.deck import Deck

        deck_instance = Deck()
        deck = deck_instance.cards

    # Validate that we have enough cards to draw from without duplicates
    num_positions = len(spread.positions)
    if num_positions > len(deck):
        raise ValueError(f"Cannot draw {num_positions} unique cards from deck of {len(deck)} cards")

    # Draw unique cards using random.sample (no replacements)
    drawn_deck = random.sample(deck, num_positions)

    drawn_cards = []
    for position, card in zip(spread.positions, drawn_deck):
        # Random reversal (50% chance)
        is_reversed = random.choice([True, False])
        drawn_cards.append(DrawnCard(position, card, is_reversed))

    return drawn_cards


class SpreadReading:
    """Represents a complete tarot reading with cards drawn for a spread."""

    def __init__(self, spread: Spread, drawn_cards: List[DrawnCard]) -> None:
        """
        Initialize a reading with a spread and drawn cards.

        Args:
            spread: The Spread object
            drawn_cards: List of DrawnCard objects
        """
        self.spread = spread
        self.drawn_cards = drawn_cards

    def __str__(self) -> str:
        """Return formatted reading with all cards and interpretations."""
        lines = [
            "╔═══════════════════════════════════════════╗",
            f"║  {self.spread.name:40}║",
            "╚═══════════════════════════════════════════╝",
            "",
            f"{self.spread.description}",
            "",
            "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━",
            "",
        ]

        for drawn in self.drawn_cards:
            card = drawn.card
            card_name = card.name
            if drawn.is_reversed:
                card_name += " ◄ REVERSED"

            lines.append(f"Position {drawn.position.number}: {drawn.position.name}")
            lines.append(f"  Card: {card_name}")
            lines.append(f"  Meaning: {drawn.position.meaning}")

            # Add card details if available
            if hasattr(card, "number"):
                lines.append(f"  Card #: {card.number}")
            if hasattr(card, "arcana"):
                lines.append(f"  Arcana: {card.arcana}")
            if hasattr(card, "suit") and card.suit:
                lines.append(f"  Suit: {card.suit.name}")

            lines.append("")

        lines.append("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

        return "\n".join(lines)

    def __repr__(self) -> str:
        return f"SpreadReading({self.spread.name}, {len(self.drawn_cards)} cards)"
