"""Contact database models."""

from __future__ import annotations

from enum import StrEnum

from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import Mapped, mapped_column, relationship

from python.orm.richie.base import RichieBase, TableBase


class RelationshipType(StrEnum):
    """Relationship types with default closeness weights.

    Default weight is an integer 1-10 where 10 = closest relationship.
    Users can override this per-relationship in the UI.
    """

    SPOUSE = "spouse"
    PARTNER = "partner"
    PARENT = "parent"
    CHILD = "child"
    SIBLING = "sibling"
    BEST_FRIEND = "best_friend"
    GRANDPARENT = "grandparent"
    GRANDCHILD = "grandchild"
    AUNT_UNCLE = "aunt_uncle"
    NIECE_NEPHEW = "niece_nephew"
    COUSIN = "cousin"
    IN_LAW = "in_law"
    CLOSE_FRIEND = "close_friend"
    FRIEND = "friend"
    MENTOR = "mentor"
    MENTEE = "mentee"
    BUSINESS_PARTNER = "business_partner"
    COLLEAGUE = "colleague"
    MANAGER = "manager"
    DIRECT_REPORT = "direct_report"
    CLIENT = "client"
    ACQUAINTANCE = "acquaintance"
    NEIGHBOR = "neighbor"
    EX = "ex"
    OTHER = "other"

    @property
    def default_weight(self) -> int:
        """Return the default closeness weight (1-10) for this relationship type."""
        weights = {
            RelationshipType.SPOUSE: 10,
            RelationshipType.PARTNER: 10,
            RelationshipType.PARENT: 9,
            RelationshipType.CHILD: 9,
            RelationshipType.SIBLING: 9,
            RelationshipType.BEST_FRIEND: 8,
            RelationshipType.GRANDPARENT: 7,
            RelationshipType.GRANDCHILD: 7,
            RelationshipType.AUNT_UNCLE: 7,
            RelationshipType.NIECE_NEPHEW: 7,
            RelationshipType.COUSIN: 7,
            RelationshipType.IN_LAW: 7,
            RelationshipType.CLOSE_FRIEND: 6,
            RelationshipType.FRIEND: 6,
            RelationshipType.MENTOR: 5,
            RelationshipType.MENTEE: 5,
            RelationshipType.BUSINESS_PARTNER: 5,
            RelationshipType.COLLEAGUE: 4,
            RelationshipType.MANAGER: 4,
            RelationshipType.DIRECT_REPORT: 4,
            RelationshipType.CLIENT: 4,
            RelationshipType.ACQUAINTANCE: 3,
            RelationshipType.NEIGHBOR: 3,
            RelationshipType.EX: 2,
            RelationshipType.OTHER: 2,
        }
        return weights.get(self, 5)

    @property
    def display_name(self) -> str:
        """Return a human-readable display name."""
        return self.value.replace("_", " ").title()


class ContactNeed(RichieBase):
    """Association table: Contact <-> Need."""

    __tablename__ = "contact_need"

    contact_id: Mapped[int] = mapped_column(
        ForeignKey("main.contact.id", ondelete="CASCADE"),
        primary_key=True,
    )
    need_id: Mapped[int] = mapped_column(
        ForeignKey("main.need.id", ondelete="CASCADE"),
        primary_key=True,
    )


class ContactRelationship(RichieBase):
    """Association table: Contact <-> Contact with relationship type and weight."""

    __tablename__ = "contact_relationship"

    contact_id: Mapped[int] = mapped_column(
        ForeignKey("main.contact.id", ondelete="CASCADE"),
        primary_key=True,
    )
    related_contact_id: Mapped[int] = mapped_column(
        ForeignKey("main.contact.id", ondelete="CASCADE"),
        primary_key=True,
    )
    relationship_type: Mapped[str] = mapped_column(String(100))
    closeness_weight: Mapped[int] = mapped_column(default=5)


class Contact(TableBase):
    """Contact model."""

    __tablename__ = "contact"

    name: Mapped[str]

    age: Mapped[int | None]
    bio: Mapped[str | None]
    current_job: Mapped[str | None]
    gender: Mapped[str | None]
    goals: Mapped[str | None]
    legal_name: Mapped[str | None]
    profile_pic: Mapped[str | None]
    safe_conversation_starters: Mapped[str | None]
    self_sufficiency_score: Mapped[int | None]
    social_structure_style: Mapped[str | None]
    ssn: Mapped[str | None]
    suffix: Mapped[str | None]
    timezone: Mapped[str | None]
    topics_to_avoid: Mapped[str | None]

    needs: Mapped[list[Need]] = relationship(
        "Need",
        secondary=ContactNeed.__table__,
        back_populates="contacts",
    )

    related_to: Mapped[list[ContactRelationship]] = relationship(
        "ContactRelationship",
        foreign_keys=[ContactRelationship.contact_id],
        cascade="all, delete-orphan",
    )
    related_from: Mapped[list[ContactRelationship]] = relationship(
        "ContactRelationship",
        foreign_keys=[ContactRelationship.related_contact_id],
        cascade="all, delete-orphan",
    )


class Need(TableBase):
    """Need/accommodation model (e.g., light sensitive, ADHD)."""

    __tablename__ = "need"

    name: Mapped[str]
    description: Mapped[str | None]

    contacts: Mapped[list[Contact]] = relationship(
        "Contact",
        secondary=ContactNeed.__table__,
        back_populates="needs",
    )
