"""
Profile schema definition and validation for MarkiTect user profiles.

This module defines the JSON schema structure for user profiles and provides
validation functionality to ensure profile data integrity.
"""

import json
from datetime import datetime
from typing import Dict, Any, Optional, List
from dataclasses import dataclass, asdict, field
from jsonschema import validate, ValidationError


@dataclass
class ContactInfo:
    """Contact information structure."""
    email: Optional[str] = None
    phone: Optional[str] = None
    website: Optional[str] = None
    linkedin: Optional[str] = None
    github: Optional[str] = None
    twitter: Optional[str] = None


@dataclass
class Address:
    """Address structure."""
    street: Optional[str] = None
    city: Optional[str] = None
    state: Optional[str] = None
    postal_code: Optional[str] = None
    country: Optional[str] = None


@dataclass
class Organization:
    """Organization/company information."""
    name: Optional[str] = None
    position: Optional[str] = None
    department: Optional[str] = None
    website: Optional[str] = None
    address: Optional[Address] = field(default_factory=Address)


@dataclass
class ProfileData:
    """
    Complete user profile data structure.

    This dataclass defines all the fields that can be stored in a user profile
    for template auto-filling purposes.
    """
    # Basic personal information
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    full_name: Optional[str] = None
    preferred_name: Optional[str] = None
    title: Optional[str] = None  # Mr., Ms., Dr., etc.

    # Contact information
    contact: ContactInfo = field(default_factory=ContactInfo)

    # Address information
    address: Address = field(default_factory=Address)

    # Professional information
    organization: Organization = field(default_factory=Organization)
    profession: Optional[str] = None
    bio: Optional[str] = None

    # Additional fields for template filling
    custom_fields: Dict[str, Any] = field(default_factory=dict)

    # Metadata
    created_at: Optional[str] = None
    updated_at: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert profile data to dictionary."""
        return asdict(self)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'ProfileData':
        """Create ProfileData from dictionary."""
        # Handle nested structures
        if 'contact' in data and isinstance(data['contact'], dict):
            data['contact'] = ContactInfo(**data['contact'])

        if 'address' in data and isinstance(data['address'], dict):
            data['address'] = Address(**data['address'])

        if 'organization' in data and isinstance(data['organization'], dict):
            org_data = data['organization'].copy()
            if 'address' in org_data and isinstance(org_data['address'], dict):
                org_data['address'] = Address(**org_data['address'])
            data['organization'] = Organization(**org_data)

        return cls(**data)


class ProfileSchema:
    """
    JSON Schema validation for user profiles.

    Provides schema definition and validation methods to ensure
    profile data integrity and consistency.
    """

    # JSON Schema definition for profile validation
    SCHEMA = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "MarkiTect User Profile",
        "type": "object",
        "properties": {
            "first_name": {
                "type": ["string", "null"],
                "maxLength": 100,
                "description": "User's first name"
            },
            "last_name": {
                "type": ["string", "null"],
                "maxLength": 100,
                "description": "User's last name"
            },
            "full_name": {
                "type": ["string", "null"],
                "maxLength": 200,
                "description": "User's full name"
            },
            "preferred_name": {
                "type": ["string", "null"],
                "maxLength": 100,
                "description": "User's preferred name"
            },
            "title": {
                "type": ["string", "null"],
                "maxLength": 20,
                "description": "Title (Mr., Ms., Dr., etc.)"
            },
            "contact": {
                "type": "object",
                "properties": {
                    "email": {
                        "type": ["string", "null"],
                        "format": "email",
                        "description": "Email address"
                    },
                    "phone": {
                        "type": ["string", "null"],
                        "maxLength": 50,
                        "description": "Phone number"
                    },
                    "website": {
                        "type": ["string", "null"],
                        "format": "uri",
                        "description": "Personal website URL"
                    },
                    "linkedin": {
                        "type": ["string", "null"],
                        "description": "LinkedIn profile URL"
                    },
                    "github": {
                        "type": ["string", "null"],
                        "description": "GitHub profile URL"
                    },
                    "twitter": {
                        "type": ["string", "null"],
                        "description": "Twitter handle or URL"
                    }
                },
                "additionalProperties": False
            },
            "address": {
                "type": "object",
                "properties": {
                    "street": {
                        "type": ["string", "null"],
                        "maxLength": 200,
                        "description": "Street address"
                    },
                    "city": {
                        "type": ["string", "null"],
                        "maxLength": 100,
                        "description": "City"
                    },
                    "state": {
                        "type": ["string", "null"],
                        "maxLength": 100,
                        "description": "State or province"
                    },
                    "postal_code": {
                        "type": ["string", "null"],
                        "maxLength": 20,
                        "description": "Postal or ZIP code"
                    },
                    "country": {
                        "type": ["string", "null"],
                        "maxLength": 100,
                        "description": "Country"
                    }
                },
                "additionalProperties": False
            },
            "organization": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": ["string", "null"],
                        "maxLength": 200,
                        "description": "Organization name"
                    },
                    "position": {
                        "type": ["string", "null"],
                        "maxLength": 100,
                        "description": "Job position/title"
                    },
                    "department": {
                        "type": ["string", "null"],
                        "maxLength": 100,
                        "description": "Department"
                    },
                    "website": {
                        "type": ["string", "null"],
                        "format": "uri",
                        "description": "Organization website"
                    },
                    "address": {
                        "$ref": "#/properties/address"
                    }
                },
                "additionalProperties": False
            },
            "profession": {
                "type": ["string", "null"],
                "maxLength": 100,
                "description": "Professional role or occupation"
            },
            "bio": {
                "type": ["string", "null"],
                "maxLength": 2000,
                "description": "Professional biography"
            },
            "custom_fields": {
                "type": "object",
                "description": "Additional custom fields for template filling",
                "additionalProperties": True
            },
            "created_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Profile creation timestamp"
            },
            "updated_at": {
                "type": ["string", "null"],
                "format": "date-time",
                "description": "Profile last update timestamp"
            }
        },
        "additionalProperties": False
    }

    @classmethod
    def validate(cls, data: Dict[str, Any]) -> None:
        """
        Validate profile data against the schema.

        Args:
            data: Profile data dictionary to validate

        Raises:
            ValidationError: If data doesn't match schema
        """
        validate(instance=data, schema=cls.SCHEMA)

    @classmethod
    def is_valid(cls, data: Dict[str, Any]) -> bool:
        """
        Check if profile data is valid.

        Args:
            data: Profile data dictionary to check

        Returns:
            True if valid, False otherwise
        """
        try:
            cls.validate(data)
            return True
        except ValidationError:
            return False

    @classmethod
    def get_field_description(cls, field_path: str) -> Optional[str]:
        """
        Get description for a specific field.

        Args:
            field_path: Dot-separated field path (e.g., 'contact.email')

        Returns:
            Field description or None if not found
        """
        parts = field_path.split('.')
        current = cls.SCHEMA['properties']

        try:
            for part in parts:
                if part in current:
                    current = current[part]
                    if 'properties' in current:
                        current = current['properties']
                    else:
                        return current.get('description')
            return current.get('description')
        except (KeyError, TypeError):
            return None

    @classmethod
    def get_all_fields(cls) -> List[str]:
        """
        Get list of all available field paths.

        Returns:
            List of dot-separated field paths
        """
        fields = []

        def extract_fields(schema_dict: Dict[str, Any], prefix: str = '') -> None:
            if 'properties' not in schema_dict:
                return

            for field_name, field_def in schema_dict['properties'].items():
                field_path = f"{prefix}.{field_name}" if prefix else field_name
                fields.append(field_path)

                if field_def.get('type') == 'object' and 'properties' in field_def:
                    extract_fields(field_def, field_path)

        extract_fields(cls.SCHEMA)
        return sorted(fields)

    @classmethod
    def create_empty_profile(self) -> ProfileData:
        """
        Create an empty profile with default structure.

        Returns:
            Empty ProfileData instance
        """
        now = datetime.now().isoformat()
        return ProfileData(
            created_at=now,
            updated_at=now
        )