"""Implicit Memory Schemas

This module defines the Pydantic schemas for the implicit memory system API.
"""

import datetime
from enum import Enum
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator


class FrequencyPattern(str, Enum):
    """Frequency patterns for habits."""
    DAILY = "daily"
    WEEKLY = "weekly"
    MONTHLY = "monthly"
    SEASONAL = "seasonal"
    OCCASIONAL = "occasional"
    EVENT_TRIGGERED = "event_triggered"


# Request Schemas

class TimeRange(BaseModel):
    """Time range for analysis."""
    start_date: datetime.datetime
    end_date: datetime.datetime

    @field_validator('end_date')
    @classmethod
    def end_date_must_be_after_start_date(cls, v, info):
        if 'start_date' in info.data and v <= info.data['start_date']:
            raise ValueError('end_date must be after start_date')
        return v

    @field_serializer("start_date", when_used="json")
    def _serialize_start_date(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None

    @field_serializer("end_date", when_used="json")
    def _serialize_end_date(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class DateRange(BaseModel):
    """Date range for filtering."""
    start_date: Optional[datetime.datetime] = None
    end_date: Optional[datetime.datetime] = None

    @field_validator('end_date')
    @classmethod
    def end_date_must_be_after_start_date(cls, v, info):
        if v and 'start_date' in info.data and info.data['start_date'] and v <= info.data['start_date']:
            raise ValueError('end_date must be after start_date')
        return v

    @field_serializer("start_date", when_used="json")
    def _serialize_start_date(self, dt: Optional[datetime.datetime]):
        return int(dt.timestamp() * 1000) if dt else None

    @field_serializer("end_date", when_used="json")
    def _serialize_end_date(self, dt: Optional[datetime.datetime]):
        return int(dt.timestamp() * 1000) if dt else None


class AnalysisConfig(BaseModel):
    """Configuration for analysis operations."""
    llm_model_id: Optional[str] = None
    batch_size: int = 100
    confidence_threshold: float = 0.5
    include_historical_trends: bool = False
    max_conversations: Optional[int] = None


# Response Schemas

class PreferenceTagResponse(BaseModel):
    """A user preference tag with detailed context."""
    model_config = ConfigDict(from_attributes=True)
    
    tag_name: str
    confidence_score: float = Field(ge=0.0, le=1.0)
    supporting_evidence: List[str]
    context_details: str
    created_at: datetime.datetime
    updated_at: datetime.datetime
    conversation_references: List[str]
    category: Optional[str] = None

    @field_serializer("created_at", when_used="json")
    def _serialize_created_at(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None

    @field_serializer("updated_at", when_used="json")
    def _serialize_updated_at(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class DimensionScoreResponse(BaseModel):
    """Score for a personality dimension."""
    model_config = ConfigDict(from_attributes=True)
    
    dimension_name: str
    percentage: float = Field(ge=0.0, le=100.0)
    evidence: List[str]
    reasoning: str
    confidence_level: int = Field(ge=0, le=100)


class DimensionPortraitResponse(BaseModel):
    """Four-dimension personality portrait."""
    model_config = ConfigDict(from_attributes=True)
    
    creativity: DimensionScoreResponse
    aesthetic: DimensionScoreResponse
    technology: DimensionScoreResponse
    literature: DimensionScoreResponse
    analysis_timestamp: datetime.datetime
    total_summaries_analyzed: int
    historical_trends: Optional[List[Dict[str, Any]]] = None

    @field_serializer("analysis_timestamp", when_used="json")
    def _serialize_analysis_timestamp(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class InterestCategoryResponse(BaseModel):
    """Interest category with percentage and evidence."""
    model_config = ConfigDict(from_attributes=True)
    
    category_name: str
    percentage: float = Field(ge=0.0, le=100.0)
    evidence: List[str]
    trending_direction: Optional[str] = None


class InterestAreaDistributionResponse(BaseModel):
    """Distribution of user interests across four areas."""
    model_config = ConfigDict(from_attributes=True)
    
    tech: InterestCategoryResponse
    lifestyle: InterestCategoryResponse
    music: InterestCategoryResponse
    art: InterestCategoryResponse
    analysis_timestamp: datetime.datetime
    total_summaries_analyzed: int
    
    @property
    def total_percentage(self) -> float:
        """Calculate total percentage across all interest areas."""
        return self.tech.percentage + self.lifestyle.percentage + self.music.percentage + self.art.percentage

    @field_serializer("analysis_timestamp", when_used="json")
    def _serialize_analysis_timestamp(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class BehaviorHabitResponse(BaseModel):
    """A behavioral habit identified from conversations."""
    model_config = ConfigDict(from_attributes=True)
    
    habit_description: str
    frequency_pattern: FrequencyPattern
    time_context: str
    confidence_level: int = Field(ge=0, le=100)
    first_observed: datetime.datetime
    last_observed: datetime.datetime
    is_current: bool = True
    specific_examples: List[str]

    @field_serializer("first_observed", when_used="json")
    def _serialize_first_observed(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None

    @field_serializer("last_observed", when_used="json")
    def _serialize_last_observed(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class UserProfileResponse(BaseModel):
    """Comprehensive user profile."""
    model_config = ConfigDict(from_attributes=True)
    
    preference_tags: List[PreferenceTagResponse]
    dimension_portrait: DimensionPortraitResponse
    interest_area_distribution: InterestAreaDistributionResponse
    behavior_habits: List[BehaviorHabitResponse]
    profile_version: int
    created_at: datetime.datetime
    updated_at: datetime.datetime
    total_summaries_analyzed: int
    analysis_completeness_score: float = Field(ge=0.0, le=1.0)

    @field_serializer("created_at", when_used="json")
    def _serialize_created_at(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None

    @field_serializer("updated_at", when_used="json")
    def _serialize_updated_at(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


# Internal/Business Logic Schemas

class MemorySummary(BaseModel):
    """Memory summary from existing storage system."""
    model_config = ConfigDict(from_attributes=True)
    
    summary_id: str
    content: str
    timestamp: datetime.datetime
    participants: List[str]
    summary_type: str

    @field_serializer("timestamp", when_used="json")
    def _serialize_timestamp(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class UserMemorySummary(BaseModel):
    """Memory summary filtered for specific user content."""
    model_config = ConfigDict(from_attributes=True)
    
    summary_id: str
    user_content: str
    timestamp: datetime.datetime
    confidence_score: float = Field(ge=0.0, le=1.0)
    summary_type: str

    @field_serializer("timestamp", when_used="json")
    def _serialize_timestamp(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


class SummaryAnalysisResult(BaseModel):
    """Result of analyzing memory summaries."""
    model_config = ConfigDict(from_attributes=True)
    
    preferences: List[PreferenceTagResponse]
    dimension_evidence: Dict[str, List[str]]
    interest_evidence: Dict[str, List[str]]
    habit_evidence: List[Dict[str, Any]]
    analysis_timestamp: datetime.datetime
    summaries_analyzed: List[str]

    @field_serializer("analysis_timestamp", when_used="json")
    def _serialize_analysis_timestamp(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None


# Aliases for backward compatibility with existing code
PreferenceTag = PreferenceTagResponse
DimensionScore = DimensionScoreResponse
DimensionPortrait = DimensionPortraitResponse
InterestCategory = InterestCategoryResponse
InterestAreaDistribution = InterestAreaDistributionResponse
BehaviorHabit = BehaviorHabitResponse
UserProfile = UserProfileResponse


# Cache-related Schemas

class GenerateProfileRequest(BaseModel):
    """生成完整用户画像请求"""
    end_user_id: str = Field(..., description="终端用户ID")


class CompleteProfileResponse(BaseModel):
    """完整用户画像响应（包含所有模块）"""
    preferences: List[PreferenceTagResponse]
    portrait: DimensionPortraitResponse
    interest_areas: InterestAreaDistributionResponse
    habits: List[BehaviorHabitResponse]
    generated_at: datetime.datetime
    cached: bool = Field(False, description="是否来自缓存")
    
    @field_serializer("generated_at", when_used="json")
    def _serialize_generated_at(self, dt: datetime.datetime):
        return int(dt.timestamp() * 1000) if dt else None
