import uuid
import secrets
import string
import time
import hashlib

from django.db import models
from django.conf import settings
from django.utils import timezone


def uuid7() -> uuid.UUID:
    """Generate a UUID v7 (time-ordered UUID)."""
    nanoseconds = time.time_ns()
    uuid_int = (nanoseconds << 16) | secrets.randbits(48)
    return uuid.UUID(int=uuid_int)


def generate_short_code(length=6) -> str:
    """Generate a random short code for URLs."""
    chars = string.ascii_letters + string.digits
    return ''.join(secrets.choice(chars) for _ in range(length))


class URL(models.Model):
    """Shortened URL model."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    original_url = models.URLField(max_length=2048)
    short_code = models.CharField(max_length=20, unique=True, blank=True)
    title = models.CharField(max_length=255, blank=True)
    clicks = models.PositiveIntegerField(default=0)
    last_clicked_at = models.DateTimeField(null=True, blank=True)
    expires_at = models.DateTimeField(null=True, blank=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='shortened_urls'
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'tools_urls'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.short_code} -> {self.original_url[:50]}"

    def save(self, *args, **kwargs):
        if not self.short_code:
            while True:
                code = generate_short_code()
                if not URL.objects.filter(short_code=code).exists():
                    self.short_code = code
                    break
        super().save(*args, **kwargs)

    def is_expired(self):
        if self.expires_at is None:
            return False
        return timezone.now() > self.expires_at

    def increment_clicks(self):
        self.clicks += 1
        self.last_clicked_at = timezone.now()
        self.save(update_fields=['clicks', 'last_clicked_at'])


class URLClick(models.Model):
    """Track individual clicks on shortened URLs."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    url = models.ForeignKey(URL, on_delete=models.CASCADE, related_name='click_logs')
    clicked_at = models.DateTimeField(auto_now_add=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.CharField(max_length=512, blank=True)
    referer = models.URLField(max_length=2048, blank=True)

    class Meta:
        db_table = 'tools_url_clicks'
        ordering = ['-clicked_at']


class QRCode(models.Model):
    """QR Code generation tracking."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    content = models.TextField()
    short_code = models.CharField(max_length=20, unique=True, blank=True)
    title = models.CharField(max_length=255, blank=True)
    size = models.PositiveIntegerField(default=300)
    format = models.CharField(max_length=10, default='png')
    downloads = models.PositiveIntegerField(default=0)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='qr_codes'
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'tools_qr_codes'
        ordering = ['-created_at']

    def __str__(self):
        return self.title or f"QR Code {self.short_code}"

    def save(self, *args, **kwargs):
        if not self.short_code:
            while True:
                code = generate_short_code()
                if not QRCode.objects.filter(short_code=code).exists():
                    self.short_code = code
                    break
        super().save(*args, **kwargs)


class ImageToolUsage(models.Model):
    """Track usage of image manipulation tools."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    tool_name = models.CharField(max_length=50)
    original_filename = models.CharField(max_length=255, blank=True)
    result_filename = models.CharField(max_length=255, blank=True)
    original_size = models.PositiveIntegerField(default=0)
    result_size = models.PositiveIntegerField(default=0)
    compression_ratio = models.FloatField(null=True, blank=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='image_tool_usages'
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'tools_image_usage'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.tool_name} - {self.original_filename}"


class FileConversion(models.Model):
    """Track file conversions."""
    FORMAT_CHOICES = [
        ('pdf', 'PDF'),
        ('jpg', 'JPEG'),
        ('png', 'PNG'),
        ('docx', 'Word'),
        ('xlsx', 'Excel'),
    ]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    from_format = models.CharField(max_length=10, choices=FORMAT_CHOICES)
    to_format = models.CharField(max_length=10, choices=FORMAT_CHOICES)
    original_filename = models.CharField(max_length=255)
    result_filename = models.CharField(max_length=255, blank=True)
    original_size = models.PositiveIntegerField(default=0)
    result_size = models.PositiveIntegerField(default=0)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='file_conversions'
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = 'tools_file_conversions'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.original_filename} ({self.from_format} -> {self.to_format})"


class CurrencyRate(models.Model):
    base = models.CharField(max_length=3)
    quote = models.CharField(max_length=3)
    date = models.DateField()
    rate = models.DecimalField(max_digits=20, decimal_places=8)
    fetched_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'tools_currency_rates'
        ordering = ['date']
        constraints = [
            models.UniqueConstraint(fields=['base', 'quote', 'date'], name='uniq_currency_rate'),
        ]
        indexes = [models.Index(fields=['base', 'quote', 'date'])]

    def __str__(self):
        return f"{self.base}/{self.quote} {self.date} = {self.rate}"
