"""Models for Reporting and Analytics app.

This module defines models for:
- SFR Analytics and market share data
- Verification and compliance tracking
- Performance metrics and KPIs
- Prediction models
- Real-time analytics
- Activity logging
"""

import uuid
from django.db import models
from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator
from django.contrib.auth import get_user_model
from decimal import Decimal

from apps.core.models import TimeStampedModel, UUIDModel, SoftDeleteModel
from apps.channels.models import Channel
from apps.campaigns.models import Campaign
from apps.advertisers.models import Brand

User = get_user_model()


class AnalyticsRegion(TimeStampedModel, SoftDeleteModel):
    """Geographic regions for analytics segmentation."""
    
    name = models.CharField(
        max_length=100,
        unique=True,
        help_text="Region name (e.g., Paris, Lyon, Marseille)"
    )
    code = models.CharField(
        max_length=10,
        unique=True,
        help_text="Region code for identification"
    )
    country = models.CharField(
        max_length=100,
        default='France',
        help_text="Country this region belongs to"
    )
    population = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Population of the region"
    )
    timezone_name = models.CharField(
        max_length=50,
        default='Europe/Paris',
        help_text="Timezone for this region"
    )
    
    class Meta:
        db_table = 'reporting_analytics_regions'
        verbose_name = 'Analytics Region'
        verbose_name_plural = 'Analytics Regions'
        ordering = ['name']
    
    def __str__(self):
        return f"{self.name} ({self.code})"


class AnalyticsTarget(TimeStampedModel, SoftDeleteModel):
    """Target demographics for analytics."""
    
    name = models.CharField(
        max_length=100,
        unique=True,
        help_text="Target demographic name (e.g., Adults 18-49, Women 25-54)"
    )
    code = models.CharField(
        max_length=20,
        unique=True,
        help_text="Target code for identification"
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the target demographic"
    )
    age_min = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Minimum age for this target"
    )
    age_max = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Maximum age for this target"
    )
    gender = models.CharField(
        max_length=20,
        choices=[
            ('all', 'All'),
            ('male', 'Male'),
            ('female', 'Female'),
            ('other', 'Other'),
        ],
        default='all',
        help_text="Gender specification for this target"
    )
    
    class Meta:
        db_table = 'reporting_analytics_targets'
        verbose_name = 'Analytics Target'
        verbose_name_plural = 'Analytics Targets'
        ordering = ['name']
    
    def __str__(self):
        return f"{self.name} ({self.code})"


class SfrAnalytics(TimeStampedModel):
    """SFR Analytics data for audience measurement."""
    
    INDICATOR_CHOICES = [
        ('rating', 'Rating'),
        ('share', 'Share'),
        ('reach', 'Reach'),
        ('frequency', 'Frequency'),
        ('grp', 'GRP (Gross Rating Points)'),
        ('impressions', 'Impressions'),
        ('viewers', 'Viewers'),
    ]
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='sfr_analytics',
        help_text="Channel being measured"
    )
    sfr_channel_name = models.CharField(
        max_length=255,
        help_text="SFR system channel name"
    )
    measurement_date = models.DateField(
        help_text="Date of measurement"
    )
    measurement_time = models.TimeField(
        null=True,
        blank=True,
        help_text="Time of measurement (minute-by-minute data)"
    )
    region = models.ForeignKey(
        AnalyticsRegion,
        on_delete=models.CASCADE,
        related_name='sfr_analytics',
        help_text="Geographic region"
    )
    target = models.ForeignKey(
        AnalyticsTarget,
        on_delete=models.CASCADE,
        related_name='sfr_analytics',
        help_text="Target demographic"
    )
    indicator = models.CharField(
        max_length=20,
        choices=INDICATOR_CHOICES,
        help_text="Type of measurement indicator"
    )
    value = models.DecimalField(
        max_digits=10,
        decimal_places=4,
        help_text="Measurement value"
    )
    percentage = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Value as percentage"
    )
    raw_data = models.JSONField(
        default=dict,
        blank=True,
        help_text="Raw measurement data from SFR"
    )
    data_source = models.CharField(
        max_length=100,
        default='SFR',
        help_text="Source of the analytics data"
    )
    quality_score = models.DecimalField(
        max_digits=3,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(1)],
        help_text="Data quality score (0-1)"
    )
    
    class Meta:
        db_table = 'reporting_sfr_analytics'
        verbose_name = 'SFR Analytics'
        verbose_name_plural = 'SFR Analytics'
        ordering = ['-measurement_date', '-measurement_time']
        indexes = [
            models.Index(fields=['channel', 'measurement_date']),
            models.Index(fields=['measurement_date', 'measurement_time']),
            models.Index(fields=['region', 'target']),
            models.Index(fields=['indicator']),
        ]
        unique_together = [
            ['channel', 'measurement_date', 'measurement_time', 'region', 'target', 'indicator']
        ]
    
    def __str__(self):
        time_str = f" {self.measurement_time}" if self.measurement_time else ""
        return f"{self.channel.name} - {self.indicator} - {self.measurement_date}{time_str}"


class MarketShare(TimeStampedModel):
    """Market share data by region and demographic."""
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='market_shares',
        help_text="Channel being measured"
    )
    measurement_date = models.DateField(
        help_text="Date of measurement"
    )
    region = models.ForeignKey(
        AnalyticsRegion,
        on_delete=models.CASCADE,
        related_name='market_shares',
        help_text="Geographic region"
    )
    target = models.ForeignKey(
        AnalyticsTarget,
        on_delete=models.CASCADE,
        related_name='market_shares',
        help_text="Target demographic"
    )
    total_users = models.PositiveIntegerField(
        help_text="Total users in the market"
    )
    channel_users = models.PositiveIntegerField(
        help_text="Users watching this channel"
    )
    market_share_percentage = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        help_text="Market share as percentage"
    )
    ranking = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Channel ranking in this market"
    )
    tool_name = models.CharField(
        max_length=100,
        default='SFR',
        help_text="Measurement tool used"
    )
    
    class Meta:
        db_table = 'reporting_market_shares'
        verbose_name = 'Market Share'
        verbose_name_plural = 'Market Shares'
        ordering = ['-measurement_date', '-market_share_percentage']
        indexes = [
            models.Index(fields=['channel', 'measurement_date']),
            models.Index(fields=['measurement_date']),
            models.Index(fields=['region', 'target']),
        ]
        unique_together = [
            ['channel', 'measurement_date', 'region', 'target']
        ]
    
    def __str__(self):
        return f"{self.channel.name} - {self.market_share_percentage}% ({self.measurement_date})"


class VerificationRecord(UUIDModel, TimeStampedModel):
    """Ad verification and compliance tracking."""
    
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('verified', 'Verified'),
        ('failed', 'Failed'),
        ('incomplete', 'Incomplete'),
        ('error', 'Error'),
    ]
    
    network_name = models.CharField(
        max_length=255,
        help_text="Network/channel name"
    )
    zone_name = models.CharField(
        max_length=255,
        help_text="Geographic zone"
    )
    broadcast_date = models.DateField(
        help_text="Date of broadcast"
    )
    broadcast_time = models.TimeField(
        null=True,
        blank=True,
        help_text="Time of broadcast"
    )
    traffic_id = models.PositiveIntegerField(
        help_text="Traffic system ID"
    )
    spot_id = models.CharField(
        max_length=255,
        help_text="Spot identifier"
    )
    air_time = models.CharField(
        max_length=50,
        help_text="Actual air time"
    )
    air_length = models.CharField(
        max_length=50,
        help_text="Actual air duration"
    )
    air_status_code = models.CharField(
        max_length=50,
        help_text="Air status code from verification system"
    )
    revision = models.PositiveIntegerField(
        default=1,
        help_text="Revision number"
    )
    verification_complete = models.CharField(
        max_length=50,
        blank=True,
        help_text="Verification completion status"
    )
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )
    campaign = models.ForeignKey(
        Campaign,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='verification_records',
        help_text="Associated campaign"
    )
    advertiser = models.ForeignKey(
        Brand,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='verification_records',
        help_text="Associated advertiser"
    )
    verification_data = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional verification data"
    )
    error_message = models.TextField(
        blank=True,
        help_text="Error message if verification failed"
    )
    verified_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='verified_records',
        help_text="User who verified this record"
    )
    verified_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When verification was completed"
    )
    
    class Meta:
        db_table = 'reporting_verification_records'
        verbose_name = 'Verification Record'
        verbose_name_plural = 'Verification Records'
        ordering = ['-broadcast_date', '-created_at']
        indexes = [
            models.Index(fields=['broadcast_date']),
            models.Index(fields=['traffic_id']),
            models.Index(fields=['spot_id']),
            models.Index(fields=['status']),
            models.Index(fields=['network_name']),
        ]
    
    def __str__(self):
        return f"Verification {self.spot_id} - {self.network_name} ({self.broadcast_date})"


class PredictionModel(UUIDModel, TimeStampedModel, SoftDeleteModel):
    """Base class for prediction models."""
    
    MODEL_TYPES = [
        ('audience', 'Audience Prediction'),
        ('adbreak', 'Ad Break Prediction'),
        ('performance', 'Performance Prediction'),
        ('market_share', 'Market Share Prediction'),
    ]
    
    name = models.CharField(
        max_length=255,
        help_text="Model name"
    )
    model_type = models.CharField(
        max_length=20,
        choices=MODEL_TYPES,
        help_text="Type of prediction model"
    )
    description = models.TextField(
        blank=True,
        help_text="Model description"
    )
    algorithm = models.CharField(
        max_length=100,
        help_text="Algorithm used (e.g., Linear Regression, Random Forest)"
    )
    version = models.CharField(
        max_length=20,
        default='1.0',
        help_text="Model version"
    )
    accuracy_score = models.DecimalField(
        max_digits=5,
        decimal_places=4,
        null=True,
        blank=True,
        help_text="Model accuracy score"
    )
    training_data_start = models.DateField(
        null=True,
        blank=True,
        help_text="Start date of training data"
    )
    training_data_end = models.DateField(
        null=True,
        blank=True,
        help_text="End date of training data"
    )
    is_active = models.BooleanField(
        default=True,
        help_text="Whether this model is active"
    )
    parameters = models.JSONField(
        default=dict,
        blank=True,
        help_text="Model parameters and configuration"
    )
    
    class Meta:
        db_table = 'reporting_prediction_models'
        verbose_name = 'Prediction Model'
        verbose_name_plural = 'Prediction Models'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.name} v{self.version}"


class SfrPrediction(TimeStampedModel):
    """SFR audience predictions."""
    
    model = models.ForeignKey(
        PredictionModel,
        on_delete=models.CASCADE,
        related_name='sfr_predictions',
        help_text="Prediction model used"
    )
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='sfr_predictions',
        help_text="Channel being predicted"
    )
    sfr_channel_name = models.CharField(
        max_length=255,
        help_text="SFR system channel name"
    )
    prediction_date = models.DateField(
        help_text="Date being predicted"
    )
    prediction_time = models.TimeField(
        null=True,
        blank=True,
        help_text="Time being predicted"
    )
    region = models.ForeignKey(
        AnalyticsRegion,
        on_delete=models.CASCADE,
        related_name='sfr_predictions',
        help_text="Geographic region"
    )
    target = models.ForeignKey(
        AnalyticsTarget,
        on_delete=models.CASCADE,
        related_name='sfr_predictions',
        help_text="Target demographic"
    )
    indicator = models.CharField(
        max_length=20,
        choices=SfrAnalytics.INDICATOR_CHOICES,
        help_text="Type of measurement indicator"
    )
    predicted_value = models.DecimalField(
        max_digits=10,
        decimal_places=4,
        help_text="Predicted value"
    )
    predicted_percentage = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Predicted value as percentage"
    )
    confidence_score = models.DecimalField(
        max_digits=5,
        decimal_places=4,
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(1)],
        help_text="Prediction confidence score (0-1)"
    )
    actual_value = models.DecimalField(
        max_digits=10,
        decimal_places=4,
        null=True,
        blank=True,
        help_text="Actual value (for accuracy tracking)"
    )
    
    class Meta:
        db_table = 'reporting_sfr_predictions'
        verbose_name = 'SFR Prediction'
        verbose_name_plural = 'SFR Predictions'
        ordering = ['-prediction_date', '-prediction_time']
        indexes = [
            models.Index(fields=['channel', 'prediction_date']),
            models.Index(fields=['prediction_date', 'prediction_time']),
            models.Index(fields=['model']),
        ]
    
    def __str__(self):
        time_str = f" {self.prediction_time}" if self.prediction_time else ""
        return f"Prediction: {self.channel.name} - {self.indicator} - {self.prediction_date}{time_str}"
    
    @property
    def accuracy(self):
        """Calculate prediction accuracy if actual value is available."""
        if self.actual_value is not None and self.predicted_value:
            error = abs(self.actual_value - self.predicted_value)
            relative_error = error / max(abs(self.actual_value), abs(self.predicted_value))
            return max(0, 1 - relative_error)
        return None


class AdbreakPrediction(TimeStampedModel):
    """Ad break timing and duration predictions."""
    
    model = models.ForeignKey(
        PredictionModel,
        on_delete=models.CASCADE,
        related_name='adbreak_predictions',
        help_text="Prediction model used"
    )
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='adbreak_predictions',
        help_text="Channel being predicted"
    )
    prediction_datetime = models.DateTimeField(
        help_text="Predicted ad break start time"
    )
    prediction_date = models.DateField(
        help_text="Date of predicted ad break"
    )
    prediction_time = models.TimeField(
        help_text="Time of predicted ad break"
    )
    predicted_duration = models.CharField(
        max_length=50,
        help_text="Predicted duration of ad break"
    )
    predicted_duration_seconds = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Predicted duration in seconds"
    )
    confidence_score = models.DecimalField(
        max_digits=5,
        decimal_places=4,
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(1)],
        help_text="Prediction confidence score (0-1)"
    )
    actual_datetime = models.DateTimeField(
        null=True,
        blank=True,
        help_text="Actual ad break start time"
    )
    actual_duration_seconds = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Actual duration in seconds"
    )
    
    class Meta:
        db_table = 'reporting_adbreak_predictions'
        verbose_name = 'Ad Break Prediction'
        verbose_name_plural = 'Ad Break Predictions'
        ordering = ['-prediction_datetime']
        indexes = [
            models.Index(fields=['channel', 'prediction_date']),
            models.Index(fields=['prediction_datetime']),
            models.Index(fields=['model']),
        ]
    
    def __str__(self):
        return f"Ad Break Prediction: {self.channel.name} - {self.prediction_datetime}"
    
    @property
    def timing_accuracy_minutes(self):
        """Calculate timing accuracy in minutes."""
        if self.actual_datetime:
            delta = abs((self.actual_datetime - self.prediction_datetime).total_seconds())
            return delta / 60
        return None


class ActivityLog(TimeStampedModel):
    """System activity logging."""
    
    ACTIVITY_TYPES = [
        ('user_login', 'User Login'),
        ('user_logout', 'User Logout'),
        ('campaign_created', 'Campaign Created'),
        ('campaign_updated', 'Campaign Updated'),
        ('adspot_uploaded', 'Ad Spot Uploaded'),
        ('adspot_processed', 'Ad Spot Processed'),
        ('verification_completed', 'Verification Completed'),
        ('report_generated', 'Report Generated'),
        ('data_import', 'Data Import'),
        ('data_export', 'Data Export'),
        ('system_error', 'System Error'),
        ('maintenance', 'Maintenance'),
    ]
    
    activity_type = models.CharField(
        max_length=50,
        choices=ACTIVITY_TYPES,
        help_text="Type of activity"
    )
    activity_date = models.DateField(
        default=timezone.now,
        help_text="Date of activity"
    )
    description = models.CharField(
        max_length=500,
        help_text="Activity description"
    )
    user = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='activity_logs',
        help_text="User who performed the activity"
    )
    ip_address = models.GenericIPAddressField(
        null=True,
        blank=True,
        help_text="IP address of the user"
    )
    user_agent = models.TextField(
        blank=True,
        help_text="User agent string"
    )
    additional_data = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional activity data"
    )
    
    class Meta:
        db_table = 'reporting_activity_logs'
        verbose_name = 'Activity Log'
        verbose_name_plural = 'Activity Logs'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['activity_type']),
            models.Index(fields=['activity_date']),
            models.Index(fields=['user']),
            models.Index(fields=['created_at']),
        ]
    
    def __str__(self):
        user_str = f" by {self.user.username}" if self.user else ""
        return f"{self.get_activity_type_display()}{user_str} - {self.activity_date}"


class RealTimeAdbreak(TimeStampedModel):
    """Real-time ad break tracking."""
    
    STATUS_CHOICES = [
        ('scheduled', 'Scheduled'),
        ('started', 'Started'),
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled'),
        ('error', 'Error'),
    ]
    
    channel = models.ForeignKey(
        Channel,
        on_delete=models.CASCADE,
        related_name='realtime_adbreaks',
        help_text="Channel broadcasting the ad break"
    )
    start_time = models.DateTimeField(
        help_text="Ad break start time"
    )
    end_time = models.DateTimeField(
        null=True,
        blank=True,
        help_text="Ad break end time"
    )
    duration_seconds = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Duration in seconds"
    )
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='scheduled'
    )
    ad_count = models.PositiveIntegerField(
        default=0,
        help_text="Number of ads in this break"
    )
    total_revenue = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Total revenue from this ad break"
    )
    viewer_count = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="Number of viewers during ad break"
    )
    tracking_data = models.JSONField(
        default=dict,
        blank=True,
        help_text="Real-time tracking data"
    )
    
    class Meta:
        db_table = 'reporting_realtime_adbreaks'
        verbose_name = 'Real-time Ad Break'
        verbose_name_plural = 'Real-time Ad Breaks'
        ordering = ['-start_time']
        indexes = [
            models.Index(fields=['channel', 'start_time']),
            models.Index(fields=['start_time']),
            models.Index(fields=['status']),
        ]
    
    def __str__(self):
        return f"Ad Break: {self.channel.name} - {self.start_time}"
    
    @property
    def actual_duration_seconds(self):
        """Calculate actual duration if end time is available."""
        if self.end_time:
            delta = self.end_time - self.start_time
            return int(delta.total_seconds())
        return self.duration_seconds