from pydantic import BaseModel, Field
from typing import List, Optional, Dict, Any, Union
from enum import Enum


class PersonaInfo(BaseModel):
    persona_id: Optional[str] = None
    tone: Optional[str] = None
    audience: Optional[str] = None
    industry: Optional[str] = None


class ResearchSource(BaseModel):
    title: str
    url: str
    excerpt: Optional[str] = None
    credibility_score: Optional[float] = None
    published_at: Optional[str] = None
    index: Optional[int] = None
    source_type: Optional[str] = None  # e.g., 'web'


class GroundingChunk(BaseModel):
    title: str
    url: str
    confidence_score: Optional[float] = None


class GroundingSupport(BaseModel):
    confidence_scores: List[float] = []
    grounding_chunk_indices: List[int] = []
    segment_text: str = ""
    start_index: Optional[int] = None
    end_index: Optional[int] = None


class Citation(BaseModel):
    citation_type: str  # e.g., 'inline'
    start_index: int
    end_index: int
    text: str
    source_indices: List[int] = []
    reference: str  # e.g., 'Source 1'


class GroundingMetadata(BaseModel):
    grounding_chunks: List[GroundingChunk] = []
    grounding_supports: List[GroundingSupport] = []
    citations: List[Citation] = []
    search_entry_point: Optional[str] = None
    web_search_queries: List[str] = []


class ResearchMode(str, Enum):
    """Research modes for different depth levels."""
    BASIC = "basic"
    COMPREHENSIVE = "comprehensive"
    TARGETED = "targeted"


class SourceType(str, Enum):
    """Types of sources to include in research."""
    WEB = "web"
    ACADEMIC = "academic"
    NEWS = "news"
    INDUSTRY = "industry"
    EXPERT = "expert"


class DateRange(str, Enum):
    """Date range filters for research."""
    LAST_WEEK = "last_week"
    LAST_MONTH = "last_month"
    LAST_3_MONTHS = "last_3_months"
    LAST_6_MONTHS = "last_6_months"
    LAST_YEAR = "last_year"
    ALL_TIME = "all_time"


class ResearchProvider(str, Enum):
    """Research provider options."""
    GOOGLE = "google"  # Gemini native grounding
    EXA = "exa"        # Exa neural search
    TAVILY = "tavily"  # Tavily AI-powered search


class ResearchConfig(BaseModel):
    """Configuration for research execution."""
    mode: ResearchMode = ResearchMode.BASIC
    provider: ResearchProvider = ResearchProvider.GOOGLE
    date_range: Optional[DateRange] = None
    source_types: List[SourceType] = []
    max_sources: int = 10
    include_statistics: bool = True
    include_expert_quotes: bool = True
    include_competitors: bool = True
    include_trends: bool = True
    
    # Exa-specific options
    exa_category: Optional[str] = None  # company, research paper, news, linkedin profile, github, tweet, movie, song, personal site, pdf, financial report
    exa_include_domains: List[str] = []  # Domain whitelist
    exa_exclude_domains: List[str] = []  # Domain blacklist
    exa_search_type: Optional[str] = "auto"  # "auto", "keyword", "neural"
    
    # Tavily-specific options
    tavily_topic: Optional[str] = "general"  # general, news, finance
    tavily_search_depth: Optional[str] = "basic"  # basic (1 credit), advanced (2 credits)
    tavily_include_domains: List[str] = []  # Domain whitelist (max 300)
    tavily_exclude_domains: List[str] = []  # Domain blacklist (max 150)
    tavily_include_answer: Union[bool, str] = False  # basic, advanced, true, false
    tavily_include_raw_content: Union[bool, str] = False  # markdown, text, true, false
    tavily_include_images: bool = False
    tavily_include_image_descriptions: bool = False
    tavily_include_favicon: bool = False
    tavily_time_range: Optional[str] = None  # day, week, month, year, d, w, m, y
    tavily_start_date: Optional[str] = None  # YYYY-MM-DD
    tavily_end_date: Optional[str] = None  # YYYY-MM-DD
    tavily_country: Optional[str] = None  # Country code (only for general topic)
    tavily_chunks_per_source: int = 3  # 1-3 (only for advanced search)
    tavily_auto_parameters: bool = False  # Auto-configure parameters based on query


class BlogResearchRequest(BaseModel):
    keywords: List[str]
    topic: Optional[str] = None
    industry: Optional[str] = None
    target_audience: Optional[str] = None
    tone: Optional[str] = None
    word_count_target: Optional[int] = 1500
    persona: Optional[PersonaInfo] = None
    research_mode: Optional[ResearchMode] = ResearchMode.BASIC
    config: Optional[ResearchConfig] = None


class BlogResearchResponse(BaseModel):
    success: bool = True
    sources: List[ResearchSource] = []
    keyword_analysis: Dict[str, Any] = {}
    competitor_analysis: Dict[str, Any] = {}
    suggested_angles: List[str] = []
    search_widget: Optional[str] = None  # HTML content for search widget
    search_queries: List[str] = []  # Search queries generated by Gemini
    grounding_metadata: Optional[GroundingMetadata] = None  # Google grounding metadata
    original_keywords: List[str] = []  # Original user-provided keywords for caching
    error_message: Optional[str] = None  # Error message for graceful failures
    retry_suggested: Optional[bool] = None  # Whether retry is recommended
    error_code: Optional[str] = None  # Specific error code
    actionable_steps: List[str] = []  # Steps user can take to resolve the issue


class BlogOutlineSection(BaseModel):
    id: str
    heading: str
    subheadings: List[str] = []
    key_points: List[str] = []
    references: List[ResearchSource] = []
    target_words: Optional[int] = None
    keywords: List[str] = []


class BlogOutlineRequest(BaseModel):
    research: BlogResearchResponse
    persona: Optional[PersonaInfo] = None
    word_count: Optional[int] = 1500
    custom_instructions: Optional[str] = None


class SourceMappingStats(BaseModel):
    total_sources_mapped: int = 0
    coverage_percentage: float = 0.0
    average_relevance_score: float = 0.0
    high_confidence_mappings: int = 0

class GroundingInsights(BaseModel):
    confidence_analysis: Optional[Dict[str, Any]] = None
    authority_analysis: Optional[Dict[str, Any]] = None
    temporal_analysis: Optional[Dict[str, Any]] = None
    content_relationships: Optional[Dict[str, Any]] = None
    citation_insights: Optional[Dict[str, Any]] = None
    search_intent_insights: Optional[Dict[str, Any]] = None
    quality_indicators: Optional[Dict[str, Any]] = None

class OptimizationResults(BaseModel):
    overall_quality_score: float = 0.0
    improvements_made: List[str] = []
    optimization_focus: str = "general optimization"

class ResearchCoverage(BaseModel):
    sources_utilized: int = 0
    content_gaps_identified: int = 0
    competitive_advantages: List[str] = []

class BlogOutlineResponse(BaseModel):
    success: bool = True
    title_options: List[str] = []
    outline: List[BlogOutlineSection] = []
    
    # Additional metadata for enhanced UI
    source_mapping_stats: Optional[SourceMappingStats] = None
    grounding_insights: Optional[GroundingInsights] = None
    optimization_results: Optional[OptimizationResults] = None
    research_coverage: Optional[ResearchCoverage] = None


class BlogOutlineRefineRequest(BaseModel):
    outline: List[BlogOutlineSection]
    operation: str
    section_id: Optional[str] = None
    payload: Optional[Dict[str, Any]] = None


class BlogSectionRequest(BaseModel):
    section: BlogOutlineSection
    keywords: List[str] = []
    tone: Optional[str] = None
    persona: Optional[PersonaInfo] = None
    mode: Optional[str] = "polished"  # 'draft' | 'polished'


class BlogSectionResponse(BaseModel):
    success: bool = True
    markdown: str
    citations: List[ResearchSource] = []
    continuity_metrics: Optional[Dict[str, float]] = None


class BlogOptimizeRequest(BaseModel):
    content: str
    goals: List[str] = []


class BlogOptimizeResponse(BaseModel):
    success: bool = True
    optimized: str
    diff_preview: Optional[str] = None


class BlogSEOAnalyzeRequest(BaseModel):
    content: str
    blog_title: Optional[str] = None
    keywords: List[str] = []
    research_data: Optional[Dict[str, Any]] = None


class BlogSEOAnalyzeResponse(BaseModel):
    success: bool = True
    seo_score: float
    density: Dict[str, Any] = {}
    structure: Dict[str, Any] = {}
    readability: Dict[str, Any] = {}
    link_suggestions: List[Dict[str, Any]] = []
    image_alt_status: Dict[str, Any] = {}
    recommendations: List[str] = []


class BlogSEOMetadataRequest(BaseModel):
    content: str
    title: Optional[str] = None
    keywords: List[str] = []
    research_data: Optional[Dict[str, Any]] = None
    outline: Optional[List[Dict[str, Any]]] = None  # Add outline structure
    seo_analysis: Optional[Dict[str, Any]] = None  # Add SEO analysis results


class BlogSEOMetadataResponse(BaseModel):
    success: bool = True
    title_options: List[str] = []
    meta_descriptions: List[str] = []
    seo_title: Optional[str] = None
    meta_description: Optional[str] = None
    url_slug: Optional[str] = None
    blog_tags: List[str] = []
    blog_categories: List[str] = []
    social_hashtags: List[str] = []
    open_graph: Dict[str, Any] = {}
    twitter_card: Dict[str, Any] = {}
    json_ld_schema: Dict[str, Any] = {}
    canonical_url: Optional[str] = None
    reading_time: float = 0.0
    focus_keyword: Optional[str] = None
    generated_at: Optional[str] = None
    optimization_score: int = 0
    error: Optional[str] = None


class BlogPublishRequest(BaseModel):
    platform: str = Field(pattern="^(wix|wordpress)$")
    html: str
    metadata: BlogSEOMetadataResponse
    schedule_time: Optional[str] = None


class BlogPublishResponse(BaseModel):
    success: bool = True
    platform: str
    url: Optional[str] = None
    post_id: Optional[str] = None


class HallucinationCheckRequest(BaseModel):
    content: str
    sources: List[str] = []


class HallucinationCheckResponse(BaseModel):
    success: bool = True
    claims: List[Dict[str, Any]] = []
    suggestions: List[Dict[str, Any]] = []


# -----------------------
# Medium Blog Generation
# -----------------------

class MediumSectionOutline(BaseModel):
    """Lightweight outline payload for medium blog generation."""
    id: str
    heading: str
    keyPoints: List[str] = []
    subheadings: List[str] = []
    keywords: List[str] = []
    targetWords: Optional[int] = None
    references: List[ResearchSource] = []


class MediumBlogGenerateRequest(BaseModel):
    """Request to generate an entire medium-length blog in one pass."""
    title: str
    sections: List[MediumSectionOutline]
    persona: Optional[PersonaInfo] = None
    tone: Optional[str] = None
    audience: Optional[str] = None
    globalTargetWords: Optional[int] = 1000
    researchKeywords: Optional[List[str]] = None  # Original research keywords for better caching


class MediumGeneratedSection(BaseModel):
    id: str
    heading: str
    content: str
    wordCount: int
    sources: Optional[List[ResearchSource]] = None


class MediumBlogGenerateResult(BaseModel):
    success: bool = True
    title: str
    sections: List[MediumGeneratedSection]
    model: Optional[str] = None
    generation_time_ms: Optional[int] = None
    safety_flags: Optional[Dict[str, Any]] = None