#!/usr/bin/env python3
"""
Type definitions and protocols for the HKIA Competitive Intelligence system.
Provides comprehensive type hints for better IDE support and runtime validation.
"""

from typing import (
    Any, Dict, List, Optional, Union, Tuple, Protocol, TypeVar, Generic,
    Callable, Awaitable, TypedDict, Literal, Final
)
from typing_extensions import NotRequired
from datetime import datetime
from pathlib import Path
from dataclasses import dataclass
from abc import ABC, abstractmethod


# Type variables
T = TypeVar('T')
ContentType = TypeVar('ContentType', bound='ContentItem')
ScraperType = TypeVar('ScraperType', bound='CompetitiveScraper')


# Literal types for better type safety
Platform = Literal['youtube', 'instagram', 'hvacrschool']
OperationType = Literal['backlog', 'incremental', 'analysis']
ContentItemType = Literal['youtube_video', 'instagram_post', 'instagram_story', 'article', 'blog_post']
CompetitivePriority = Literal['high', 'medium', 'low']
QualityTier = Literal['excellent', 'good', 'average', 'below_average', 'poor']
ExtractionMethod = Literal['youtube_data_api_v3', 'instaloader', 'jina_ai', 'standard_scraping']


# Configuration types
@dataclass
class CompetitorConfig:
    """Configuration for a competitive scraper."""
    key: str
    name: str
    platform: Platform
    url: str
    priority: CompetitivePriority
    enabled: bool = True
    custom_settings: Optional[Dict[str, Any]] = None


class ScrapingConfig(TypedDict):
    """Configuration for scraping operations."""
    request_delay: float
    max_concurrent_requests: int
    use_proxy: bool
    proxy_rotation: bool
    backlog_limit: int
    timeout: int
    retry_attempts: int


class QuotaConfig(TypedDict):
    """Configuration for API quota management."""
    daily_limit: int
    current_usage: int
    reset_time: Optional[str]
    operation_costs: Dict[str, int]


# Content data structures
class SocialMetrics(TypedDict):
    """Social engagement metrics."""
    views: NotRequired[int]
    likes: int
    comments: int
    shares: NotRequired[int]
    engagement_rate: float
    follower_engagement: NotRequired[str]


class QualityMetrics(TypedDict):
    """Content quality assessment metrics."""
    total_score: float
    max_score: int
    percentage: float
    breakdown: Dict[str, float]
    quality_tier: QualityTier


class ContentItem(TypedDict):
    """Base structure for scraped content items."""
    id: str
    url: str
    title: str
    description: str
    author: str
    publish_date: str
    type: ContentItemType
    competitor: str
    capture_timestamp: str
    extraction_method: ExtractionMethod
    word_count: int
    categories: List[str]
    content: str
    social_metrics: NotRequired[SocialMetrics]
    quality_metrics: NotRequired[QualityMetrics]


class YouTubeVideoItem(ContentItem):
    """YouTube video specific content structure."""
    video_id: str
    duration: int
    view_count: int
    like_count: int
    comment_count: int
    engagement_rate: float
    thumbnail_url: str
    tags: List[str]
    category_id: NotRequired[str]
    privacy_status: str
    topic_categories: List[str]
    content_focus_tags: List[str]
    competitive_priority: CompetitivePriority


class InstagramPostItem(ContentItem):
    """Instagram post specific content structure."""
    shortcode: str
    post_id: str
    is_video: bool
    likes: int
    comments: int
    location: Optional[str]
    hashtags: List[str]
    tagged_users: List[str]
    media_count: int


# State management types
class CompetitiveState(TypedDict):
    """State tracking for competitive scrapers."""
    competitor_name: str
    last_backlog_capture: Optional[str]
    last_incremental_sync: Optional[str]
    total_items_captured: int
    content_urls: List[str]  # Set converted to list for JSON serialization
    initialized: str


class QuotaState(TypedDict):
    """YouTube API quota state."""
    quota_used: int
    quota_reset_time: Optional[str]
    daily_limit: int
    last_updated: str


# Analysis types
class PublishingAnalysis(TypedDict):
    """Analysis of publishing patterns."""
    total_videos_analyzed: int
    date_range_days: int
    average_frequency_per_day: float
    most_common_weekday: Optional[int]
    most_common_hour: Optional[int]
    latest_video_date: Optional[str]


class ContentAnalysis(TypedDict):
    """Analysis of content themes and characteristics."""
    total_videos_analyzed: int
    top_title_keywords: List[Dict[str, Union[str, int, float]]]
    content_focus_distribution: List[Dict[str, Union[str, int, float]]]
    content_type_distribution: List[Dict[str, Union[str, int, float]]]
    average_title_length: float
    videos_with_descriptions: int
    content_diversity_score: int
    primary_content_focus: str
    content_strategy_insights: Dict[str, str]


class EngagementAnalysis(TypedDict):
    """Analysis of engagement patterns."""
    total_videos_analyzed: int
    recent_videos_30d: int
    older_videos: int
    content_focus_performance: Dict[str, Dict[str, Union[int, float, List[str]]]]
    publishing_consistency: Dict[str, float]
    engagement_insights: Dict[str, str]


class CompetitorAnalysis(TypedDict):
    """Comprehensive competitor analysis result."""
    competitor: str
    competitor_name: str
    competitive_profile: Dict[str, Any]
    sample_size: int
    channel_metadata: Dict[str, Any]
    publishing_analysis: PublishingAnalysis
    content_analysis: ContentAnalysis
    engagement_analysis: EngagementAnalysis
    competitive_positioning: Dict[str, Any]
    content_gaps: Dict[str, Any]
    api_quota_status: Dict[str, Any]
    analysis_timestamp: str


# Operation result types
class OperationResult(TypedDict, Generic[T]):
    """Generic operation result structure."""
    status: Literal['success', 'error', 'partial']
    message: str
    data: Optional[T]
    timestamp: str
    errors: NotRequired[List[str]]
    warnings: NotRequired[List[str]]


class ScrapingResult(OperationResult[List[ContentItem]]):
    """Result of a scraping operation."""
    items_scraped: int
    items_failed: int
    content_types: Dict[str, int]


class AnalysisResult(OperationResult[CompetitorAnalysis]):
    """Result of a competitive analysis operation."""
    analysis_type: str
    confidence_score: float


# Protocol definitions for type safety
class CompetitiveScraper(Protocol):
    """Protocol defining the interface for competitive scrapers."""
    
    @property
    def competitor_name(self) -> str: ...
    
    @property
    def base_url(self) -> str: ...
    
    def discover_content_urls(self, limit: Optional[int] = None) -> List[Dict[str, Any]]: ...
    
    def scrape_content_item(self, url: str) -> Optional[ContentItem]: ...
    
    def run_backlog_capture(self, limit: Optional[int] = None) -> None: ...
    
    def run_incremental_sync(self) -> None: ...
    
    def load_competitive_state(self) -> CompetitiveState: ...
    
    def save_competitive_state(self, state: CompetitiveState) -> None: ...


class QuotaManager(Protocol):
    """Protocol for API quota management."""
    
    def check_and_reserve_quota(self, operation: str, count: int = 1) -> bool: ...
    
    def get_quota_status(self) -> Dict[str, Any]: ...
    
    def release_quota(self, operation: str, count: int = 1) -> None: ...


class ContentValidator(Protocol):
    """Protocol for content validation."""
    
    def validate_content_item(self, item: ContentItem) -> Tuple[bool, List[str]]: ...
    
    def validate_required_fields(self, item: ContentItem) -> bool: ...
    
    def sanitize_content(self, content: str) -> str: ...


# Async operation types for future async implementation
AsyncContentItem = Awaitable[Optional[ContentItem]]
AsyncContentList = Awaitable[List[ContentItem]]
AsyncAnalysisResult = Awaitable[AnalysisResult]
AsyncScrapingResult = Awaitable[ScrapingResult]

# Callback types
ContentProcessorCallback = Callable[[ContentItem], ContentItem]
ErrorHandlerCallback = Callable[[Exception, str], None]
ProgressCallback = Callable[[int, int, str], None]

# Factory types
ScraperFactory = Callable[[Path, Path, str], CompetitiveScraper]
AnalyzerFactory = Callable[[List[ContentItem]], CompetitorAnalysis]

# Request/response types for API operations
class APIRequest(TypedDict):
    """Generic API request structure."""
    endpoint: str
    method: Literal['GET', 'POST', 'PUT', 'DELETE']
    params: NotRequired[Dict[str, Any]]
    headers: NotRequired[Dict[str, str]]
    data: NotRequired[Dict[str, Any]]
    timeout: NotRequired[int]


class APIResponse(TypedDict, Generic[T]):
    """Generic API response structure."""
    status_code: int
    data: Optional[T]
    headers: Dict[str, str]
    error: Optional[str]
    request_id: Optional[str]


# Configuration validation types
class ConfigValidator(Protocol):
    """Protocol for configuration validation."""
    
    def validate_scraper_config(self, config: ScrapingConfig) -> Tuple[bool, List[str]]: ...
    
    def validate_competitor_config(self, config: CompetitorConfig) -> Tuple[bool, List[str]]: ...


# Logging and monitoring types
class LogEntry(TypedDict):
    """Structured log entry."""
    timestamp: str
    level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
    logger: str
    message: str
    competitor: NotRequired[str]
    operation: NotRequired[str]
    duration: NotRequired[float]
    extra_data: NotRequired[Dict[str, Any]]


class PerformanceMetrics(TypedDict):
    """Performance monitoring metrics."""
    operation: str
    start_time: str
    end_time: str
    duration_seconds: float
    items_processed: int
    success_rate: float
    errors_count: int
    warnings_count: int
    memory_usage_mb: NotRequired[float]
    cpu_usage_percent: NotRequired[float]


# Constants
SUPPORTED_PLATFORMS: Final[List[Platform]] = ['youtube', 'instagram', 'hvacrschool']
DEFAULT_REQUEST_DELAY: Final[float] = 2.0
DEFAULT_TIMEOUT: Final[int] = 30
MAX_CONTENT_LENGTH: Final[int] = 10000
MAX_TITLE_LENGTH: Final[int] = 200
DEFAULT_BACKLOG_LIMIT: Final[int] = 100

# Type guards for runtime type checking
def is_youtube_item(item: ContentItem) -> bool:
    """Check if content item is a YouTube video."""
    return item['type'] == 'youtube_video' and 'video_id' in item

def is_instagram_item(item: ContentItem) -> bool:
    """Check if content item is an Instagram post."""
    return item['type'] in ('instagram_post', 'instagram_story') and 'shortcode' in item

def is_valid_content_item(data: Dict[str, Any]) -> bool:
    """Check if data structure is a valid content item."""
    required_fields = ['id', 'url', 'title', 'author', 'publish_date', 'type', 'competitor']
    return all(field in data for field in required_fields)