from decimal import Decimal, ROUND_HALF_UP

from django.db import models


class PriceWatcher(models.Model):
    INTERVAL_CHOICES = [
        (6, 'Every 6 hours'),
        (12, 'Every 12 hours'),
        (24, 'Every day'),
        (48, 'Every 2 days'),
        (72, 'Every 3 days'),
        (168, 'Every 7 days'),
    ]

    name = models.CharField(max_length=200)
    url = models.URLField(max_length=2000)
    css_selector = models.CharField(
        max_length=500,
        help_text='CSS selector for the price element, e.g. span.price or .product-price',
    )
    check_interval_hours = models.IntegerField(choices=INTERVAL_CHOICES, default=24)
    alert_price_threshold = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True,
        help_text='Send an alert when the detected price is at or below this value. Leave blank to disable alerts.',
    )
    recurring_notification = models.BooleanField(
        default=True,
        help_text=(
            'Keep notifying on every check while the price meets the threshold. '
            'Disable to notify only once (until you dismiss the alert).'
        ),
    )
    enabled = models.BooleanField(default=True)
    last_checked_at = models.DateTimeField(null=True, blank=True)
    initial_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    last_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    @property
    def price_change_direction(self):
        if self.initial_price is None or self.last_price is None:
            return None
        if self.last_price > self.initial_price:
            return 'up'
        if self.last_price < self.initial_price:
            return 'down'
        return 'flat'

    @property
    def price_change_pct(self):
        if self.initial_price is None or self.last_price is None or self.initial_price == 0:
            return None
        pct = ((self.last_price - self.initial_price) / self.initial_price) * Decimal('100')
        return abs(pct).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

    @property
    def price_change_symbol(self):
        direction = self.price_change_direction
        if direction == 'up':
            return '↑'
        if direction == 'down':
            return '↓'
        if direction == 'flat':
            return '→'
        return ''


class PriceSnapshot(models.Model):
    watcher = models.ForeignKey(PriceWatcher, on_delete=models.CASCADE, related_name='snapshots')
    price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    raw_text = models.CharField(max_length=500, blank=True)
    error = models.CharField(max_length=500, blank=True)
    checked_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-checked_at']

    def __str__(self):
        return f'{self.watcher.name} @ {self.checked_at:%Y-%m-%d %H:%M}'


class PriceAlert(models.Model):
    watcher = models.ForeignKey(PriceWatcher, on_delete=models.CASCADE, related_name='alerts')
    old_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    new_price = models.DecimalField(max_digits=12, decimal_places=2)
    drop_pct = models.DecimalField(max_digits=5, decimal_places=2, default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    dismissed = models.BooleanField(default=False)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.watcher.name}: ${self.old_price} → ${self.new_price}'
