"""
SEO Monitoring and Dashboard Models

This module provides models for tracking SEO metrics including:
- Organic traffic
- Keyword rankings
- Conversions
- Core Web Vitals
- Crawl errors
- Ranking changes
"""

from django.db import models
from django.utils import timezone
from django.core.cache import cache
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
import json


class KeywordRanking(models.Model):
    """Model for tracking keyword rankings over time."""
    
    SEARCH_ENGINE_CHOICES = [
        ('google', 'Google'),
        ('bing', 'Bing'),
        ('yahoo', 'Yahoo'),
    ]
    
    # Keyword information
    keyword = models.CharField(
        max_length=255,
        help_text="Target keyword"
    )
    search_engine = models.CharField(
        max_length=50,
        choices=SEARCH_ENGINE_CHOICES,
        default='google',
        help_text="Search engine"
    )
    
    # Ranking information
    current_rank = models.IntegerField(
        help_text="Current ranking position (1-100+)"
    )
    previous_rank = models.IntegerField(
        null=True,
        blank=True,
        help_text="Previous ranking position"
    )
    
    # Target page
    target_url = models.URLField(
        help_text="URL being ranked"
    )
    
    # Keyword metrics
    search_volume = models.IntegerField(
        default=0,
        help_text="Monthly search volume"
    )
    keyword_difficulty = models.IntegerField(
        default=0,
        help_text="Keyword difficulty score (0-100)"
    )
    
    # Tracking
    tracked_date = models.DateTimeField(
        auto_now_add=True,
        help_text="When this ranking was recorded"
    )
    
    class Meta:
        verbose_name = 'Keyword Ranking'
        verbose_name_plural = 'Keyword Rankings'
        ordering = ['keyword', '-tracked_date']
        indexes = [
            models.Index(fields=['keyword', '-tracked_date']),
            models.Index(fields=['search_engine', '-tracked_date']),
        ]
    
    def __str__(self):
        return f"{self.keyword} - Rank #{self.current_rank}"
    
    def get_rank_change(self) -> Optional[int]:
        """Get the change in ranking (positive = improvement)."""
        if self.previous_rank is None:
            return None
        return self.previous_rank - self.current_rank
    
    def is_improved(self) -> bool:
        """Check if ranking has improved."""
        change = self.get_rank_change()
        return change is not None and change > 0
    
    def is_declined(self) -> bool:
        """Check if ranking has declined."""
        change = self.get_rank_change()
        return change is not None and change < 0


class OrganicTraffic(models.Model):
    """Model for tracking organic traffic metrics."""
    
    # Traffic metrics
    date = models.DateField(
        help_text="Date of the traffic data"
    )
    sessions = models.IntegerField(
        default=0,
        help_text="Number of organic sessions"
    )
    users = models.IntegerField(
        default=0,
        help_text="Number of unique users"
    )
    pageviews = models.IntegerField(
        default=0,
        help_text="Number of pageviews"
    )
    
    # Engagement metrics
    bounce_rate = models.FloatField(
        default=0.0,
        help_text="Bounce rate percentage"
    )
    avg_session_duration = models.FloatField(
        default=0.0,
        help_text="Average session duration in seconds"
    )
    
    # Conversion metrics
    conversions = models.IntegerField(
        default=0,
        help_text="Number of conversions"
    )
    conversion_rate = models.FloatField(
        default=0.0,
        help_text="Conversion rate percentage"
    )
    
    # Device breakdown
    mobile_sessions = models.IntegerField(
        default=0,
        help_text="Mobile sessions"
    )
    desktop_sessions = models.IntegerField(
        default=0,
        help_text="Desktop sessions"
    )
    tablet_sessions = models.IntegerField(
        default=0,
        help_text="Tablet sessions"
    )
    
    # Tracking
    recorded_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When this data was recorded"
    )
    
    class Meta:
        verbose_name = 'Organic Traffic'
        verbose_name_plural = 'Organic Traffic'
        ordering = ['-date']
        indexes = [
            models.Index(fields=['-date']),
        ]
        unique_together = ['date']
    
    def __str__(self):
        return f"Organic Traffic - {self.date}"
    
    def get_mobile_percentage(self) -> float:
        """Get mobile traffic percentage."""
        total = self.mobile_sessions + self.desktop_sessions + self.tablet_sessions
        if total == 0:
            return 0.0
        return (self.mobile_sessions / total) * 100
    
    def get_desktop_percentage(self) -> float:
        """Get desktop traffic percentage."""
        total = self.mobile_sessions + self.desktop_sessions + self.tablet_sessions
        if total == 0:
            return 0.0
        return (self.desktop_sessions / total) * 100


class ConversionMetric(models.Model):
    """Model for tracking conversion metrics."""
    
    CONVERSION_TYPE_CHOICES = [
        ('contact_form', 'Contact Form'),
        ('phone_call', 'Phone Call'),
        ('demo_request', 'Demo Request'),
        ('quote_request', 'Quote Request'),
        ('newsletter_signup', 'Newsletter Signup'),
        ('download', 'Download'),
        ('other', 'Other'),
    ]
    
    # Conversion information
    date = models.DateField(
        help_text="Date of the conversion data"
    )
    conversion_type = models.CharField(
        max_length=50,
        choices=CONVERSION_TYPE_CHOICES,
        help_text="Type of conversion"
    )
    
    # Metrics
    total_conversions = models.IntegerField(
        default=0,
        help_text="Total number of conversions"
    )
    conversion_value = models.FloatField(
        default=0.0,
        help_text="Total conversion value"
    )
    avg_conversion_value = models.FloatField(
        default=0.0,
        help_text="Average conversion value"
    )
    
    # Source breakdown
    organic_conversions = models.IntegerField(
        default=0,
        help_text="Conversions from organic traffic"
    )
    paid_conversions = models.IntegerField(
        default=0,
        help_text="Conversions from paid traffic"
    )
    direct_conversions = models.IntegerField(
        default=0,
        help_text="Conversions from direct traffic"
    )
    
    # Tracking
    recorded_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When this data was recorded"
    )
    
    class Meta:
        verbose_name = 'Conversion Metric'
        verbose_name_plural = 'Conversion Metrics'
        ordering = ['-date', 'conversion_type']
        indexes = [
            models.Index(fields=['-date', 'conversion_type']),
        ]
        unique_together = ['date', 'conversion_type']
    
    def __str__(self):
        return f"{self.get_conversion_type_display()} - {self.date}"
    
    def get_organic_conversion_percentage(self) -> float:
        """Get percentage of conversions from organic traffic."""
        if self.total_conversions == 0:
            return 0.0
        return (self.organic_conversions / self.total_conversions) * 100


class CoreWebVital(models.Model):
    """Model for tracking Core Web Vitals metrics."""
    
    # Page information
    page_url = models.URLField(
        help_text="URL of the page"
    )
    date = models.DateField(
        help_text="Date of the measurement"
    )
    
    # Core Web Vitals
    lcp = models.FloatField(
        help_text="Largest Contentful Paint (LCP) in seconds"
    )
    fid = models.FloatField(
        help_text="First Input Delay (FID) in milliseconds"
    )
    cls = models.FloatField(
        help_text="Cumulative Layout Shift (CLS) score"
    )
    
    # Overall score
    overall_score = models.IntegerField(
        default=0,
        help_text="Overall PageSpeed score (0-100)"
    )
    
    # Status
    lcp_status = models.CharField(
        max_length=20,
        choices=[('good', 'Good'), ('needs_improvement', 'Needs Improvement'), ('poor', 'Poor')],
        help_text="LCP status"
    )
    fid_status = models.CharField(
        max_length=20,
        choices=[('good', 'Good'), ('needs_improvement', 'Needs Improvement'), ('poor', 'Poor')],
        help_text="FID status"
    )
    cls_status = models.CharField(
        max_length=20,
        choices=[('good', 'Good'), ('needs_improvement', 'Needs Improvement'), ('poor', 'Poor')],
        help_text="CLS status"
    )
    
    # Tracking
    recorded_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When this data was recorded"
    )
    
    class Meta:
        verbose_name = 'Core Web Vital'
        verbose_name_plural = 'Core Web Vitals'
        ordering = ['-date', 'page_url']
        indexes = [
            models.Index(fields=['page_url', '-date']),
        ]
        unique_together = ['page_url', 'date']
    
    def __str__(self):
        return f"Core Web Vitals - {self.page_url} ({self.date})"
    
    def is_all_good(self) -> bool:
        """Check if all Core Web Vitals are in good status."""
        return (
            self.lcp_status == 'good' and
            self.fid_status == 'good' and
            self.cls_status == 'good'
        )


class CrawlError(models.Model):
    """Model for tracking crawl errors."""
    
    ERROR_TYPE_CHOICES = [
        ('404', '404 Not Found'),
        ('500', '500 Server Error'),
        ('403', '403 Forbidden'),
        ('timeout', 'Timeout'),
        ('redirect_error', 'Redirect Error'),
        ('ssl_error', 'SSL Error'),
        ('other', 'Other'),
    ]
    
    # Error information
    error_url = models.URLField(
        help_text="URL that caused the error"
    )
    error_type = models.CharField(
        max_length=50,
        choices=ERROR_TYPE_CHOICES,
        help_text="Type of error"
    )
    error_message = models.TextField(
        blank=True,
        help_text="Error message details"
    )
    
    # Error details
    http_status_code = models.IntegerField(
        null=True,
        blank=True,
        help_text="HTTP status code"
    )
    
    # Tracking
    first_detected = models.DateTimeField(
        auto_now_add=True,
        help_text="When the error was first detected"
    )
    last_detected = models.DateTimeField(
        auto_now=True,
        help_text="When the error was last detected"
    )
    is_resolved = models.BooleanField(
        default=False,
        help_text="Has the error been resolved?"
    )
    resolved_date = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the error was resolved"
    )
    
    class Meta:
        verbose_name = 'Crawl Error'
        verbose_name_plural = 'Crawl Errors'
        ordering = ['-last_detected']
        indexes = [
            models.Index(fields=['error_type', '-last_detected']),
            models.Index(fields=['is_resolved', '-last_detected']),
        ]
    
    def __str__(self):
        return f"{self.error_type} - {self.error_url}"
    
    def mark_resolved(self):
        """Mark the error as resolved."""
        self.is_resolved = True
        self.resolved_date = timezone.now()
        self.save()


class SEOAlert(models.Model):
    """Model for tracking SEO alerts and issues."""
    
    ALERT_TYPE_CHOICES = [
        ('ranking_drop', 'Ranking Drop'),
        ('traffic_drop', 'Traffic Drop'),
        ('crawl_error', 'Crawl Error'),
        ('core_web_vitals', 'Core Web Vitals Issue'),
        ('indexation', 'Indexation Issue'),
        ('security', 'Security Issue'),
        ('other', 'Other'),
    ]
    
    SEVERITY_CHOICES = [
        ('critical', 'Critical'),
        ('high', 'High'),
        ('medium', 'Medium'),
        ('low', 'Low'),
    ]
    
    # Alert information
    alert_type = models.CharField(
        max_length=50,
        choices=ALERT_TYPE_CHOICES,
        help_text="Type of alert"
    )
    severity = models.CharField(
        max_length=20,
        choices=SEVERITY_CHOICES,
        default='medium',
        help_text="Severity level"
    )
    title = models.CharField(
        max_length=255,
        help_text="Alert title"
    )
    description = models.TextField(
        help_text="Alert description"
    )
    
    # Alert details
    affected_url = models.URLField(
        blank=True,
        help_text="URL affected by the alert"
    )
    affected_keyword = models.CharField(
        max_length=255,
        blank=True,
        help_text="Keyword affected by the alert"
    )
    
    # Metrics
    metric_value = models.FloatField(
        null=True,
        blank=True,
        help_text="Metric value that triggered the alert"
    )
    threshold_value = models.FloatField(
        null=True,
        blank=True,
        help_text="Threshold that was exceeded"
    )
    
    # Status
    is_active = models.BooleanField(
        default=True,
        help_text="Is the alert currently active?"
    )
    is_acknowledged = models.BooleanField(
        default=False,
        help_text="Has the alert been acknowledged?"
    )
    is_resolved = models.BooleanField(
        default=False,
        help_text="Has the alert been resolved?"
    )
    
    # Tracking
    created_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When the alert was created"
    )
    acknowledged_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the alert was acknowledged"
    )
    resolved_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the alert was resolved"
    )
    
    class Meta:
        verbose_name = 'SEO Alert'
        verbose_name_plural = 'SEO Alerts'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['alert_type', '-created_at']),
            models.Index(fields=['severity', '-created_at']),
            models.Index(fields=['is_active', '-created_at']),
        ]
    
    def __str__(self):
        return f"{self.title} ({self.get_severity_display()})"
    
    def acknowledge(self):
        """Acknowledge the alert."""
        self.is_acknowledged = True
        self.acknowledged_at = timezone.now()
        self.save()
    
    def resolve(self):
        """Resolve the alert."""
        self.is_resolved = True
        self.is_active = False
        self.resolved_at = timezone.now()
        self.save()


class SEODashboardMetrics(models.Model):
    """Model for storing aggregated SEO dashboard metrics."""
    
    # Date
    date = models.DateField(
        unique=True,
        help_text="Date of the metrics"
    )
    
    # Traffic metrics
    organic_traffic = models.IntegerField(
        default=0,
        help_text="Total organic traffic"
    )
    organic_traffic_change = models.FloatField(
        default=0.0,
        help_text="Percentage change from previous day"
    )
    
    # Ranking metrics
    keywords_top_10 = models.IntegerField(
        default=0,
        help_text="Number of keywords in top 10"
    )
    keywords_top_3 = models.IntegerField(
        default=0,
        help_text="Number of keywords in top 3"
    )
    keywords_top_1 = models.IntegerField(
        default=0,
        help_text="Number of keywords in position 1"
    )
    
    # Conversion metrics
    total_conversions = models.IntegerField(
        default=0,
        help_text="Total conversions"
    )
    conversion_rate = models.FloatField(
        default=0.0,
        help_text="Conversion rate percentage"
    )
    
    # Core Web Vitals
    avg_lcp = models.FloatField(
        default=0.0,
        help_text="Average LCP across all pages"
    )
    avg_fid = models.FloatField(
        default=0.0,
        help_text="Average FID across all pages"
    )
    avg_cls = models.FloatField(
        default=0.0,
        help_text="Average CLS across all pages"
    )
    
    # Crawl errors
    total_crawl_errors = models.IntegerField(
        default=0,
        help_text="Total number of crawl errors"
    )
    new_crawl_errors = models.IntegerField(
        default=0,
        help_text="New crawl errors since last day"
    )
    
    # Alerts
    active_alerts = models.IntegerField(
        default=0,
        help_text="Number of active alerts"
    )
    critical_alerts = models.IntegerField(
        default=0,
        help_text="Number of critical alerts"
    )
    
    # Tracking
    recorded_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When this data was recorded"
    )
    
    class Meta:
        verbose_name = 'SEO Dashboard Metrics'
        verbose_name_plural = 'SEO Dashboard Metrics'
        ordering = ['-date']
        indexes = [
            models.Index(fields=['-date']),
        ]
    
    def __str__(self):
        return f"SEO Dashboard Metrics - {self.date}"
    
    def get_traffic_trend(self) -> str:
        """Get traffic trend indicator."""
        if self.organic_traffic_change > 0:
            return 'up'
        elif self.organic_traffic_change < 0:
            return 'down'
        return 'stable'
