"""Identity models for the Danube SDK."""

import json
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field


class Contact(BaseModel):
    """A contact from the user's identity.

    Contacts can come from either the key_people list (important contacts)
    or the general contacts list.
    """

    name: str = ""
    email: str = ""
    phone: Optional[str] = None
    relationship: Optional[str] = None
    company: Optional[str] = None
    notes: Optional[str] = None
    nickname: Optional[str] = None
    source: str = "contacts"  # "key_people" or "contacts"

    model_config = {"extra": "ignore"}

    @classmethod
    def from_api_response(
        cls, data: Dict[str, Any], source: str = "contacts"
    ) -> "Contact":
        """Create a Contact from API response data.

        Args:
            data: Raw API response dictionary.
            source: Where this contact came from ("key_people" or "contacts").

        Returns:
            Contact instance.
        """
        return cls(
            name=data.get("name", ""),
            email=data.get("email", ""),
            phone=data.get("phone"),
            relationship=data.get("relationship"),
            company=data.get("company"),
            notes=data.get("notes"),
            nickname=data.get("nickname"),
            source=source,
        )



class Identity(BaseModel):
    """User identity and profile information.

    Contains the user's profile data, important contacts (key_people),
    general contacts, and preferences.
    """

    profile: Dict[str, Any] = Field(default_factory=dict)
    key_people: List[Contact] = Field(default_factory=list)
    contacts: List[Contact] = Field(default_factory=list)
    preferences: Dict[str, Any] = Field(default_factory=dict)

    # Raw data access for advanced use cases
    raw: Dict[str, Any] = Field(default_factory=dict)

    model_config = {"extra": "ignore"}

    @classmethod
    def from_api_response(cls, data: Dict[str, Any]) -> "Identity":
        """Create an Identity from API response data.

        Args:
            data: Raw API response dictionary.

        Returns:
            Identity instance.
        """
        # API may return a string representation of the dict
        if isinstance(data, str):
            try:
                data = json.loads(data)
            except (json.JSONDecodeError, TypeError):
                return cls(profile={}, key_people=[], contacts=[], preferences={}, raw={"raw": data})

        if not isinstance(data, dict):
            return cls(profile={}, key_people=[], contacts=[], preferences={}, raw={})

        # Parse key_people (may be dicts or plain strings)
        key_people = []
        for p in data.get("key_people", []):
            if isinstance(p, dict):
                key_people.append(Contact.from_api_response(p, source="key_people"))
            elif isinstance(p, str):
                key_people.append(Contact(name=p, email="", source="key_people"))

        # Parse contacts (may be dicts or plain strings)
        contacts = []
        for c in data.get("contacts", []):
            if isinstance(c, dict):
                contacts.append(Contact.from_api_response(c, source="contacts"))
            elif isinstance(c, str):
                contacts.append(Contact(name=c, email="", source="contacts"))

        # Extract profile (attributes) - check v2 "about_me", then "attributes", then legacy "profile"
        profile = data.get("about_me", data.get("attributes", data.get("profile", {})))

        return cls(
            profile=profile,
            key_people=key_people,
            contacts=contacts,
            preferences=data.get("preferences", {}),
            raw=data,
        )

    def get_all_contacts(self) -> List[Contact]:
        """Get all contacts from both key_people and contacts lists.

        Returns:
            Combined list with key_people first.
        """
        return self.key_people + self.contacts

    @property
    def name(self) -> Optional[str]:
        """Get the user's name from profile."""
        return self.profile.get("name") or self.profile.get("full_name")

    @property
    def email(self) -> Optional[str]:
        """Get the user's email from profile."""
        return self.profile.get("email")

    @property
    def schema(self) -> Optional[Dict[str, Any]]:
        """Get the identity schema if present (v2 format).

        Returns:
            The _schema dict or None if not set.
        """
        return self.raw.get("_schema")

    @property
    def custom_sections(self) -> Dict[str, Any]:
        """Get custom (non-canonical) section data from the identity.

        Returns data for sections beyond the standard about_me, key_people,
        contacts, and preferences sections.

        Returns:
            Dict mapping section_id to section data.
        """
        schema = self.schema
        if not schema:
            return {}

        canonical = {"about_me", "key_people", "contacts", "preferences"}
        result = {}
        for section in schema.get("sections", []):
            sid = section.get("id", "")
            if sid not in canonical and sid in self.raw:
                result[sid] = self.raw[sid]
        return result
