"""
Miscellaneous utilities for Tarot, including personality typing and other tools.

This module contains specialized utilities that don't fit into other categories.
"""

from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
    from tarot.deck.deck import CourtCard


class MBTIType(Enum):
    """16 MBTI personality types."""

    ISTJ = "ISTJ"
    ISFJ = "ISFJ"
    INFJ = "INFJ"
    INTJ = "INTJ"
    ISTP = "ISTP"
    ISFP = "ISFP"
    INFP = "INFP"
    INTP = "INTP"
    ESTP = "ESTP"
    ESFP = "ESFP"
    ENFP = "ENFP"
    ENTP = "ENTP"
    ESTJ = "ESTJ"
    ESFJ = "ESFJ"
    ENFJ = "ENFJ"
    ENTJ = "ENTJ"


@dataclass
class Personality:
    """
    MBTI Personality Type mapped to a specific Tarot Court Card.

    This class creates a direct 1-to-1 relationship between each of the 16 MBTI
    personality types and their corresponding Tarot court cards. Based on the
    comprehensive system developed by Dante DiMatteo at 78 Revelations Per Minute:
    https://78revelationsaminute.wordpress.com/2015/07/08/personality-types-the-tarot-court-cards-and-the-myers-briggs-type-indicator/

    The mapping is based on:
    - SUITS correspond to Jung's 4 cognitive functions:
      * Wands: Intuition (N)
      * Cups: Feeling (F)
      * Swords: Thinking (T)
      * Pentacles: Sensation (S)

    - RANKS correspond to MBTI traits:
      * Kings (E + J): Extraverted Judgers
      * Queens (I + J): Introverted Judgers
      * Princes (E + P): Extraverted Perceivers
      * Princesses (I + P): Introverted Perceivers

    Attributes:
        mbti_type: The MBTI personality type (e.g., ENFP)
        court_card: The single CourtCard object representing this personality
        description: Brief description of the personality archetype
    """

    mbti_type: MBTIType
    court_card: Optional["CourtCard"] = None
    description: str = ""

    # Direct MBTI-to-CourtCard mapping (1-to-1 relationship)
    # Format: MBTI_TYPE -> (Rank, Suit)
    _MBTI_TO_CARD_MAPPING = {
        # KINGS (E + J) - Extraverted Judgers
        "ENTJ": ("Knight", "Wands"),  # Fiery, forceful leadership
        "ENFJ": ("Knight", "Cups"),  # Sensitive, mission-driven
        "ESTJ": ("Knight", "Swords"),  # Practical, pragmatic
        "ESFJ": ("Knight", "Pentacles"),  # Sociable, consensus-seeking
        # QUEENS (I + J) - Introverted Judgers
        "INTJ": ("Queen", "Wands"),  # Analytical, self-motivated
        "INFJ": ("Queen", "Cups"),  # Sensitive, interconnected
        "ISTJ": ("Queen", "Swords"),  # Pragmatic, duty-fulfiller
        "ISFJ": ("Queen", "Pentacles"),  # Caring, earth-mother type
        # PRINCES (E + P) - Extraverted Perceivers
        "ENTP": ("Prince", "Wands"),  # Visionary, quick-study
        "ENFP": ("Prince", "Cups"),  # Inspiring, intuitive
        "ESTP": ("Prince", "Swords"),  # Action-oriented, risk-taker
        "ESFP": ("Prince", "Pentacles"),  # Aesthete, sensualist
        # PRINCESSES (I + P) - Introverted Perceivers
        "INTP": ("Princess", "Wands"),  # Thinker par excellence
        "INFP": ("Princess", "Cups"),  # Idealistic, devoted
        "ISTP": ("Princess", "Swords"),  # Observer, mechanic
        "ISFP": ("Princess", "Pentacles"),  # Aesthete, free spirit
    }

    @classmethod
    def from_mbti(cls, mbti_type: str, deck: Optional[object] = None) -> "Personality":
        """
        Create a Personality from an MBTI type string.

        Args:
            mbti_type: MBTI type as string (e.g., "ENFP", "ISTJ")
            deck: Optional Tarot Deck to fetch the court card from. If not provided,
                 court card will be fetched dynamically when accessed.

        Returns:
            Personality object with associated court card

        Raises:
            ValueError: If mbti_type is not a valid MBTI type

        Example:
            >>> from tarot import Tarot
            >>> personality = Personality.from_mbti("ENFP", Tarot.deck)
            >>> print(personality.mbti_type.value)
            ENFP
            >>> print(f"{personality.court_card.court_rank} of {personality.court_card.suit.name}")
            Prince of Cups
        """
        mbti_type = mbti_type.upper()

        # Validate MBTI type
        try:
            mbti_enum = MBTIType[mbti_type]
        except KeyError:
            raise ValueError(
                f"Invalid MBTI type: {mbti_type}. Must be one of: "
                f"{', '.join([t.value for t in MBTIType])}"
            )

        # Get the rank and suit for this MBTI type
        rank, suit = cls._MBTI_TO_CARD_MAPPING.get(mbti_type, (None, None))
        if not rank or not suit:
            raise ValueError(f"No court card mapping found for MBTI type {mbti_type}")

        # Get court card from deck if provided
        court_card = None
        if deck is not None:
            # Import here to avoid circular imports
            from tarot import Tarot

            # Use provided deck or default to Tarot
            d = deck if hasattr(deck, "card") else Tarot.deck

            cards = d.card.filter(type="Court", court_rank=rank, suit=suit)
            if cards:
                court_card = cards[0]

        # Get description
        descriptions = {
            "ENTJ": "The Commander - Strategic, ambitious, leader of Wands",
            "ENFJ": "The Protagonist - Inspiring, empathetic, leader of Cups",
            "ESTJ": "The Supervisor - Practical, decisive, leader of Swords",
            "ESFJ": "The Consul - Sociable, cooperative, leader of Pentacles",
            "INTJ": "The Architect - Strategic, logical, sage of Wands",
            "INFJ": "The Advocate - Insightful, idealistic, sage of Cups",
            "ISTJ": "The Logistician - Practical, reliable, sage of Swords",
            "ISFJ": "The Defender - Caring, conscientious, sage of Pentacles",
            "ENTP": "The Debater - Innovative, quick-witted, explorer of Wands",
            "ENFP": "The Campaigner - Enthusiastic, social, explorer of Cups",
            "ESTP": "The Entrepreneur - Energetic, bold, explorer of Swords",
            "ESFP": "The Entertainer - Spontaneous, outgoing, explorer of Pentacles",
            "INTP": "The Logician - Analytical, curious, seeker of Wands",
            "INFP": "The Mediator - Idealistic, authentic, seeker of Cups",
            "ISTP": "The Virtuoso - Practical, observant, seeker of Swords",
            "ISFP": "The Adventurer - Sensitive, spontaneous, seeker of Pentacles",
        }

        return cls(
            mbti_type=mbti_enum, court_card=court_card, description=descriptions.get(mbti_type, "")
        )

    def __str__(self) -> str:
        """Return string representation of personality with court card."""
        if self.court_card:
            card_str = f"{self.court_card.court_rank} of {self.court_card.suit.name}"
        else:
            card_str = "No court card loaded"

        return f"{self.mbti_type.value} - {self.description}\n  Court Card: {card_str}"

    def __repr__(self) -> str:
        """Return detailed representation."""
        card_name = (
            f"{self.court_card.court_rank} of {self.court_card.suit.name}"
            if self.court_card
            else "None"
        )
        return f"Personality(mbti_type={self.mbti_type.value}, court_card={card_name})"
