"""
History games. Three game types, each designed to also work as a printed card game:

  timeline  — কালচক্র: place event cards in the right order (physical: timeline card deck)
  whoami    — কে আমি?: guess the person/place/object from as few clues as possible (physical: clue cards)
  factmyth  — সত্য না গুজব: decide fast whether a statement is true (physical: quiz cards + sand timer)

All scoring happens on the server, so the discount rewards cannot be faked from the browser.
"""
import secrets

from django.conf import settings
from django.db import models
from django.urls import reverse


class Game(models.Model):
    TYPES = (('timeline', 'Timeline (put events in order)'), ('whoami', 'Who am I? (clues)'),
             ('factmyth', 'Fact or myth (true / false)'))
    APPLIES = (
        ('all', 'Everything (shop + digital magazines)'),
        ('magazines', 'Magazines — printed and digital'),
        ('magazine_digital', 'Digital magazines only'),
        ('magazine_print', 'Printed magazines only'),
        ('merch', 'Wearable history (merch) only'),
        ('nostalgic', 'Nostalgic items only'),
        ('selected', 'Only the products picked below'),
    )

    kind = models.CharField(max_length=10, choices=TYPES, unique=True)
    title = models.CharField(max_length=120)
    title_en = models.CharField("English title", max_length=120, blank=True)
    slug = models.SlugField(unique=True)
    tagline = models.CharField(max_length=200, blank=True)
    description = models.TextField(help_text="What the game is and how to play (shown on the game page).")
    how_to_play = models.TextField(blank=True, help_text="One rule per line.")
    physical_note = models.TextField("Printed version", blank=True,
                                     help_text="How this game works as a physical card game (shown on the page).")
    image = models.ImageField(upload_to='games/', blank=True)
    rounds = models.PositiveSmallIntegerField(default=10, help_text="Questions/cards per play.")
    is_active = models.BooleanField(default=True)
    order = models.PositiveSmallIntegerField(default=0)
    meta_description = models.CharField(max_length=160, blank=True)

    # ── Score → discount reward ──
    reward_enabled = models.BooleanField("Give a discount for good scores", default=True)
    reward_min_score = models.PositiveSmallIntegerField("Minimum score (%)", default=40,
                                                        help_text="Players below this score get no coupon.")
    reward_max_percent = models.PositiveSmallIntegerField("Discount at 100% score (%)", default=20,
                                                          help_text="Discount grows with the score. 70% score → 70% of this.")
    reward_max_taka = models.DecimalField("Maximum discount (৳)", max_digits=8, decimal_places=2, null=True, blank=True)
    reward_min_order = models.DecimalField("Minimum order (৳)", max_digits=8, decimal_places=2, null=True, blank=True)
    reward_applies_to = models.CharField("Discount works on", max_length=20, choices=APPLIES, default='magazines')
    reward_products = models.ManyToManyField('store.Product', blank=True, related_name='game_rewards',
                                             help_text="Used when 'Discount works on' is 'Only the products picked below'.")
    reward_valid_days = models.PositiveSmallIntegerField("Coupon valid for (days)", default=7)
    reward_cooldown_days = models.PositiveSmallIntegerField(
        "One reward every (days)", default=7, help_text="A player can earn one coupon from this game per this many days.")

    class Meta:
        ordering = ['order', 'id']

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('game_detail', args=[self.slug])

    def rules(self):
        return [r.strip() for r in self.how_to_play.splitlines() if r.strip()]

    @property
    def reward_scope_bn(self):
        from apps.store.models import Coupon
        return Coupon.SCOPE_BN.get(self.reward_applies_to, '')

    def reward_percent(self, score_percent):
        if not self.reward_enabled or score_percent < self.reward_min_score:
            return 0
        return max(1, round(self.reward_max_percent * score_percent / 100))


class GameCard(models.Model):
    """One question/card. Which fields matter depends on the game type."""
    game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name='cards')
    title = models.CharField(max_length=300, help_text="Timeline: the event · Who am I: the answer · Fact/myth: the statement")
    year = models.IntegerField(null=True, blank=True, help_text="Timeline only: the year (negative for BCE).")
    year_label = models.CharField(max_length=40, blank=True, help_text="Optional display, e.g. '১২০৪ খ্রি.' or 'আনু. ৩০০ খ্রিস্টপূর্ব'.")
    clues = models.TextField(blank=True, help_text="Who am I only: one clue per line, hardest first.")
    wrong_options = models.TextField(blank=True, help_text="Who am I only: three wrong answers, one per line.")
    is_true = models.BooleanField(null=True, blank=True, help_text="Fact/myth only: is the statement true?")
    explanation = models.TextField(blank=True, help_text="Shown after answering — the real story in 1–3 sentences.")
    image = models.ImageField(upload_to='games/cards/', blank=True)
    source = models.CharField(max_length=300, blank=True, help_text="Where this fact comes from (for editors).")
    article = models.ForeignKey('articles.Article', null=True, blank=True, on_delete=models.SET_NULL,
                                help_text="Optional: an article to read more.")
    is_active = models.BooleanField(default=True)

    class Meta:
        ordering = ['game', 'year', 'id']

    def __str__(self):
        return self.title[:80]

    def clue_list(self):
        return [c.strip() for c in self.clues.splitlines() if c.strip()]

    def wrong_list(self):
        return [c.strip() for c in self.wrong_options.splitlines() if c.strip()]


def _token():
    return secrets.token_urlsafe(18)


class Play(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name='plays')
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL,
                             related_name='game_plays')
    token = models.CharField(max_length=32, unique=True, default=_token, editable=False)
    session_key = models.CharField(max_length=40, blank=True)
    cards = models.JSONField(default=list)
    state = models.JSONField(default=dict)
    step = models.PositiveSmallIntegerField(default=0)
    score = models.PositiveIntegerField(default=0)
    max_score = models.PositiveIntegerField(default=0)
    correct = models.PositiveSmallIntegerField(default=0)
    mistakes = models.PositiveSmallIntegerField(default=0)
    finished = models.BooleanField(default=False, db_index=True)
    coupon = models.ForeignKey('store.Coupon', null=True, blank=True, on_delete=models.SET_NULL, related_name='game_plays')
    created_at = models.DateTimeField(auto_now_add=True)
    finished_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.game} · {self.score}/{self.max_score}'

    @property
    def percent(self):
        return round(100 * self.score / self.max_score) if self.max_score else 0
