# File: trendsagi-client/trendsagi/models.py

from pydantic import BaseModel, Field, HttpUrl
from typing import List, Optional, Any, Dict
from datetime import datetime, date

# --- Base & Helper Models ---
class OrmBaseModel(BaseModel):
    class Config:
        from_attributes = True
        populate_by_name = True  

class PaginationMeta(BaseModel):
    total: int
    limit: int
    offset: int
    period: Optional[str] = None
    sort_by: Optional[str] = None
    order: Optional[str] = None
    search: Optional[str] = None
    category: Optional[str] = None
    start_date: Optional[date] = None
    end_date: Optional[date] = None


# --- Autocomplete and Categories Models ---
class AutocompleteResponse(OrmBaseModel):
    suggestions: List[str]

class ActiveCategoriesResponse(OrmBaseModel):
    categories: List[str]

# --- Trends & Insights Models ---
class TrendItem(OrmBaseModel):
    id: int
    name: str
    volume: Optional[int] = None
    timestamp: datetime
    meta_description: Optional[str] = None
    category: Optional[str] = None
    growth: Optional[float] = None
    previous_volume: Optional[int] = None
    absolute_change: Optional[int] = None
    average_velocity: Optional[float] = Field(None, description="Average velocity (posts/hour) over recent snapshots.")
    trend_stability: Optional[float] = Field(None, description="Standard deviation of volume over recent snapshots. Lower is more stable.")
    overall_trend: Optional[str] = Field(None, description="Qualitative assessment of the trend's direction (growing, declining, stable).")

class TrendListResponse(OrmBaseModel):
    trends: List[TrendItem]
    meta: PaginationMeta 

class TrendDataPoint(OrmBaseModel):
    date: datetime
    volume: Optional[int] = None
    velocity_per_hour: Optional[float] = None
    acceleration: Optional[float] = None
    is_forecast: Optional[bool] = False

class TrendAnalytics(OrmBaseModel):
    trend_id: int
    name: str
    period: str
    start_date: Optional[str] = None
    end_date: str
    data: List[TrendDataPoint]

class TrendSearchResultItem(OrmBaseModel):
    id: int
    name: str
    category: Optional[str] = None
    volume: Optional[int] = None
    timestamp: Optional[datetime] = None
    meta_description: Optional[str] = None

class InsightSearchResponse(OrmBaseModel):
    trends: List[TrendSearchResultItem]
    meta: PaginationMeta

class AIInsightContentBrief(OrmBaseModel):
    target_audience_segments: List[str]
    key_angles_for_content: List[str]
    suggested_content_formats: List[str]
    call_to_action_ideas: List[str]

class AIInsightAdTargeting(OrmBaseModel):
    primary_audience_keywords: List[str]
    secondary_audience_keywords: List[str]
    potential_demographics_summary: Optional[str]

class AIInsight(OrmBaseModel):
    trend_id: int
    trend_name: str
    sentiment_summary: Optional[str]
    sentiment_category: Optional[str]
    key_themes: List[str]
    content_brief: Optional[AIInsightContentBrief]
    ad_platform_targeting: Optional[AIInsightAdTargeting]
    overall_topic_category_llm: Optional[str]
    generated_at: datetime
    llm_model_used: str

# --- Custom Report Models ---
class ReportMeta(OrmBaseModel):
    row_count: int
    limit_applied: Optional[int] = None
    time_period: str
    start_date: Optional[str] = None
    end_date: Optional[str] = None
    usage_count: Optional[int] = None
    usage_limit: Optional[int] = None

class CustomReport(OrmBaseModel):
    columns: List[str]
    rows: List[Dict[str, Any]]
    meta: ReportMeta

# --- Intelligence Suite Models ---
class Recommendation(OrmBaseModel):
    id: int
    user_id: int
    type: str
    title: str
    details: str
    source_trend_id: Optional[int] = None
    source_trend_name: Optional[str] = None
    priority: str
    status: str
    created_at: datetime
    status: Optional[str] = None
    updated_at: datetime
    user_feedback: Optional[str] = None

class RecommendationListResponse(OrmBaseModel):
    recommendations: List[Recommendation]
    meta: PaginationMeta

# --- Intelligence Models ---

class UsageInfo(OrmBaseModel):
    count: int
    limit: int

class CrisisEvent(OrmBaseModel):
    id: int
    user_id: int
    title: str
    summary: str
    severity: str
    status: str
    detected_at: datetime
    source_keywords: Optional[List[str]] = None
    impacted_entity: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None
    updated_at: datetime

class CrisisEventListResponse(OrmBaseModel):
    events: List[CrisisEvent]
    meta: PaginationMeta

# --- Financial Data Models ---
class FinancialNews(OrmBaseModel):
    id: int
    title: str
    summary: str
    source_timestamp: Optional[str] = None
    sentiment: Optional[str] = None
    company: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None

class FinancialPressRelease(OrmBaseModel):
    id: int
    company: str
    title: str
    summary: str
    source_timestamp: Optional[str] = None
    sentiment: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None

class EarningsReport(OrmBaseModel):
    id: int
    company: str
    period: str
    revenue: Optional[str] = None
    earnings_per_share: Optional[str] = None
    guidance_update: Optional[str] = None
    source_timestamp: Optional[str] = None
    sentiment: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None

class IPONews(OrmBaseModel):
    id: int
    company: str
    symbol: Optional[str] = None
    status: Optional[str] = None
    filing_date: Optional[str] = None
    expected_trade_date: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None

class MarketSentiment(OrmBaseModel):
    id: int
    sentiment: str
    drivers: Optional[List[str]] = None
    source_timestamp: Optional[str] = None
    created_at: datetime
    status: Optional[str] = None


class ForexFactoryEvent(OrmBaseModel):
    id: int
    event_at: datetime  
    currency: str
    impact: Optional[str] = None
    event_name: str
    actual: Optional[str] = None
    forecast: Optional[str] = None
    previous: Optional[str] = None
    updated_at: datetime
    @property
    def event_date(self) -> str:
        return self.event_at.strftime('%Y-%m-%d')

    @property
    def event_time(self) -> str:
        return self.event_at.strftime('%H:%M:%S %Z') 

class FinancialDataResponse(OrmBaseModel):
    market_sentiment: Optional[MarketSentiment] = None
    earnings_reports: List[EarningsReport] = Field(default_factory=list)
    financial_news: List[FinancialNews] = Field(default_factory=list)
    financial_press_releases: List[FinancialPressRelease] = Field(default_factory=list)
    ipo_filings_news: List[IPONews] = Field(default_factory=list)
    forex_factory_events: List[ForexFactoryEvent] = Field(default_factory=list) 

class CombinedReleaseResponse(OrmBaseModel):
    id: str
    title: str
    published_at: str
    source: str
    source_id: Optional[str] = None

class HomepageEarningsReportResponse(OrmBaseModel):
    id: int
    company: str
    source_timestamp: Optional[datetime] = None
    report_time_of_day: str
    period: str

class HomepageIPONewsResponse(OrmBaseModel):
    id: int
    company: str
    symbol: str
    status: str
    expected_trade_date: str

class HomepageFinancialDataResponse(OrmBaseModel):
    earnings_reports: List[HomepageEarningsReportResponse]
    releases: List[CombinedReleaseResponse]
    ipo_filings_news: List[HomepageIPONewsResponse]

# --- User & Account Management Models ---
class TopicInterest(OrmBaseModel):
    id: int
    user_id: int
    keyword: Optional[str] = None
    alert_condition_type: str
    volume_threshold_value: Optional[int] = None
    percentage_growth_value: Optional[float] = None
    created_at: datetime
    status: Optional[str] = None

class ExportConfiguration(OrmBaseModel):
    id: int
    destination: str
    config: Dict[str, Any]
    schedule: str
    schedule_time: Optional[str] = None
    is_active: bool
    selected_fields: List[str] = Field(default_factory=list)
    file_name_template: Optional[str] = None

class ExportExecutionLog(OrmBaseModel):
    id: int
    execution_time: datetime
    duration_seconds: Optional[float] = None
    destination: str
    status: str
    message: Optional[str] = None
    records_exported: Optional[int] = None
    export_configuration_id: Optional[int] = None

class ExportHistoryResponse(OrmBaseModel):
    history: List[ExportExecutionLog]
    meta: PaginationMeta

class DashboardStats(OrmBaseModel):
    active_trends: int
    alerts_today: int
    topic_interests: int
    avg_growth: Optional[float] = None

class Notification(OrmBaseModel):
    id: int
    title: str
    message: str
    notification_type: str
    is_read: bool
    created_at: datetime
    status: Optional[str] = None
    read_at: Optional[datetime] = None
    data: Optional[Dict[str, Any]] = None

class DashboardOverview(OrmBaseModel):
    stats: DashboardStats
    top_trends: List[TrendItem]
    recent_alerts: List[Notification]

class NotificationListResponse(OrmBaseModel):
    notifications: List[Notification]
    unread_count: int

# --- Public Information & Status Models ---
class SessionInfoResponse(OrmBaseModel):
    country: str

class SubscriptionPlan(OrmBaseModel):
    id: int
    name: str
    description: Optional[str] = None
    price_monthly: Optional[Dict[str, float]] = None
    price_yearly: Optional[Dict[str, float]] = None
    is_custom: bool
    features: Optional[Dict[str, Any]] = Field(default_factory=dict)

class ComponentStatus(OrmBaseModel):
    name: str
    status: str
    description: Optional[str] = None

class StatusPage(OrmBaseModel):
    overall_status: str
    last_updated: datetime
    components: List[ComponentStatus]

class StatusHistoryResponse(OrmBaseModel):
    uptime_percentages: Dict[str, float]
    daily_statuses: Dict[str, Dict[str, str]]


# --- Context Intelligence Suite Models ---

class ContextProject(OrmBaseModel):
    """A context project for organizing AI agent context."""
    id: int
    name: str
    description: Optional[str] = None
    is_active: bool = True
    item_count: int = 0
    total_size_bytes: int = 0
    created_at: datetime
    status: Optional[str] = None
    updated_at: datetime


class ContextProjectListResponse(OrmBaseModel):
    projects: List[ContextProject]
    meta: PaginationMeta


class ContextItem(OrmBaseModel):
    """A context item (spec, plan, code, etc.) within a project."""
    id: int
    project_id: int
    item_type: str
    name: str
    content: Optional[str] = None
    file_size_bytes: int = 0
    mime_type: Optional[str] = None
    original_filename: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None
    has_content: bool = False
    created_at: datetime
    status: Optional[str] = None
    updated_at: datetime


class ContextItemListResponse(OrmBaseModel):
    items: List[ContextItem]
    meta: PaginationMeta


class ContextUsage(OrmBaseModel):
    """Storage usage for context items."""
    used_bytes: int
    limit_bytes: int
    used_percentage: float
    plan_name: str


# --- Agents Models (formerly Deep Analysis) ---

class Agent(OrmBaseModel):
    """An AI agent with configurable settings for conversations."""
    id: int
    name: str
    description: Optional[str] = None
    icon: Optional[str] = None
    
    # Generation settings (Gemini Flash 3.0)
    temperature: float = 1.0
    max_output_tokens: int = 8192
    thinking_level: str = "HIGH"
    top_p: Optional[float] = 0.95
    top_k: Optional[int] = 64
    
    # Conversation settings
    enable_multi_turn: bool = True
    enable_web_search: bool = False
    
    # Persona & style
    persona_preset: Optional[str] = None
    system_prompt: Optional[str] = None
    
    # Output format
    output_language: Optional[str] = None
    response_format: Optional[str] = "prose"
    
    # Safety
    safety_level: str = "block_medium_and_above"
    
    # Query Reformulation
    enable_query_expansion: bool = False
    query_expansion_prompt: Optional[str] = None
    query_expansion_examples: List[str] = Field(default_factory=list)
    enable_query_decomposition: bool = False
    query_decomposition_prompt: Optional[str] = None

    # Retrieval
    top_k_retrieved_chunks: int = 160
    lexical_alpha: float = 0.35
    semantic_alpha: float = 0.65

    # Rerank
    enable_rerank: bool = True
    top_k_reranked_chunks: int = 25
    reranker_score_threshold: float = 0.0
    rerank_instructions: Optional[str] = None

    # Filter
    enable_filter: bool = True
    filter_prompt: Optional[str] = None

    # Model Armor / Granular Safety
    safety_csam: str = 'high'
    safety_malicious_urls: str = 'high'
    safety_prompt_injection: str = 'medium'
    safety_sexual_content: str = 'disabled'
    safety_hate_speech: str = 'disabled'
    safety_harassment: str = 'disabled'
    safety_dangerous_content: str = 'disabled'
    
    # Context
    default_project_id: Optional[int] = None
    
    # Metadata
    is_archived: bool = False
    conversation_count: int = 0
    created_at: datetime
    updated_at: datetime


class AgentListResponse(OrmBaseModel):
    agents: List[Agent]
    meta: PaginationMeta


class AgentConversation(OrmBaseModel):
    """A conversation within an agent."""
    id: int
    agent_id: int
    title: Optional[str] = None
    query: str
    task_id: Optional[str] = None
    response_json: Optional[Dict[str, Any]] = None
    use_context: bool = False
    project_id: Optional[int] = None
    created_at: datetime
    updated_at: datetime


class AgentConversationListResponse(OrmBaseModel):
    conversations: List[AgentConversation]
    meta: PaginationMeta


class AgentTaskResponse(OrmBaseModel):
    """Response from queueing an agent analysis task."""
    task_id: str
    status: str
    message: Optional[str] = None
    conversation_id: Optional[int] = None


# --- Blog Models ---

class BlogPost(OrmBaseModel):
    id: int
    title: str
    slug: str
    excerpt: Optional[str] = None
    cover_image: Optional[str] = None
    published_at: datetime
    author_name: Optional[str] = None
    reading_time_minutes: int = 0
    content: Optional[str] = None  # Full content included in single post view

class BlogPostListResponse(OrmBaseModel):
    posts: List[BlogPost]
    meta: PaginationMeta


# --- User Profile & API Keys Models ---

class UserSubscription(OrmBaseModel):
    plan_name: str
    status: str
    current_period_end: Optional[datetime] = None
    cancel_at_period_end: bool = False

class UserProfile(OrmBaseModel):
    id: int
    email: str
    full_name: Optional[str] = None
    is_active: bool
    is_verified: bool
    organization_role: Optional[str] = None
    subscription: Optional[UserSubscription] = None
    avatar_url: Optional[str] = None
    created_at: datetime

class ApiKey(OrmBaseModel):
    id: int
    name: str
    prefix: str
    created_at: datetime
    last_used_at: Optional[datetime] = None
    permissions: List[str] = Field(default_factory=list)
    is_active: bool = True

class ApiKeyCreateResponse(ApiKey):
    key: str  # The full secret key, only returned on creation

class ApiKeyListResponse(OrmBaseModel):
    keys: List[ApiKey]

class ApiUsageSummary(OrmBaseModel):
    plan_daily_limit: int
    requests_today: int
    remaining_today: int

class ApiUsageDaily(OrmBaseModel):
    date: date
    request_count: int

class ApiUsageResponse(OrmBaseModel):
    summary: ApiUsageSummary
    daily_usage: List[ApiUsageDaily] = Field(default_factory=list)


# --- Organization Models ---

class OrgMember(OrmBaseModel):
    id: int
    email: str
    full_name: Optional[str] = None
    role: str
    joined_at: datetime
    user_id: Optional[int] = None

class OrgMemberListResponse(OrmBaseModel):
    members: List[OrgMember]

class OrgInvite(OrmBaseModel):
    id: int
    email: str
    role: str
    invited_by_email: Optional[str] = None
    status: str
    created_at: datetime
    expires_at: datetime

class OrgInviteListResponse(OrmBaseModel):
    invites: List[OrgInvite]

    
# --- Integration Models ---

class WebhookSubscription(OrmBaseModel):
    id: int
    target_url: str
    events: List[str]
    is_active: bool
    secret: Optional[str] = None # Partial/masked usually
    created_at: datetime
    failure_count: int = 0

class WebhookListResponse(OrmBaseModel):
    webhooks: List[WebhookSubscription]

class SlackStatus(OrmBaseModel):
    is_connected: bool
    team_name: Optional[str] = None
    channel: Optional[str] = None
    channel_id: Optional[str] = None
    configuration_url: Optional[str] = None