import re
import secrets
from decimal import Decimal

from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.validators import FileExtensionValidator
from django.db import models
from django.urls import reverse
from django.utils.deconstruct import deconstructible
from django.utils.text import slugify

from apps.core.models import SingletonMixin


@deconstructible
class PrivateStorage(FileSystemStorage):
    """Full magazine PDFs live outside /media and never get a public URL.
    The folder comes from settings.PRIVATE_MEDIA_ROOT, so nothing machine-specific
    ends up in migrations."""

    def __init__(self, **kwargs):
        kwargs.setdefault('location', getattr(settings, 'PRIVATE_MEDIA_ROOT', settings.BASE_DIR / 'private_media'))
        super().__init__(**kwargs)

    def deconstruct(self):
        path, args, kwargs = super().deconstruct()
        kwargs.pop('location', None)
        return path, args, kwargs

    def url(self, name):
        return ''


private_storage = PrivateStorage()

class StorePageContent(SingletonMixin, models.Model):
    hero_title = models.CharField(max_length=200, default="Wearable History")
    hero_description = models.TextField(default="Exclusive merchandise from Bangladesh's First Historical Magazine.")
    whatsapp_number = models.CharField(max_length=20, blank=True, default="01967286753", help_text="WhatsApp number readers message after paying, e.g. 01967286753")
    messenger_link = models.URLField(blank=True, help_text="Link to your Facebook Messenger (m.me/yourpage)")
    global_delivery_info = models.TextField(default="Delivery within 3-5 business days. Cash on delivery available.", help_text="Delivery process shown on all product pages.")

    # Digital magazine payments
    payment_number = models.CharField(max_length=20, default="01967286753",
                                      help_text="Number readers send money to for digital magazines.")
    payment_methods = models.CharField(max_length=100, default="bKash / Nagad (Send Money)",
                                       help_text="Shown to readers, e.g. 'bKash / Nagad (Send Money)'.")
    order_email = models.CharField("Order alert email", max_length=300, blank=True, default="sazzadbytes@gmail.com",
                                   help_text="New digital magazine orders are emailed here. Separate several with commas.")
    approval_time_text = models.CharField(max_length=120, default="২ থেকে ১০ মিনিটের মধ্যে",
                                          help_text="Shown in Bangla sentences, e.g. '২ থেকে ১০ মিনিটের মধ্যে'.")

    @property
    def whatsapp_digits(self):
        """The WhatsApp number as wa.me wants it, e.g. 8801967286753."""
        from .magazine import whatsapp_number
        return whatsapp_number(self)

    # SEO for the shop and magazine landing pages
    shop_meta_title = models.CharField(max_length=70, blank=True,
        default="The Reverse Times Shop — ইতিহাসের টি-শার্ট, নস্টালজিক পণ্য ও ম্যাগাজিন",
        help_text="Browser tab / Google title for /shop/ (about 60 characters).")
    shop_meta_description = models.CharField(max_length=170, blank=True,
        default="দ্য রিভার্স টাইমস শপ — ইতিহাসের গল্প নিয়ে টি-শার্ট, নস্টালজিক পণ্য আর বাংলা ইতিহাস ম্যাগাজিন। সারা বাংলাদেশে ক্যাশ অন ডেলিভারি।")
    magazine_title = models.CharField(max_length=120, default="The Reverse Times Magazine")
    magazine_intro = models.TextField(
        default="বাংলাদেশের প্রথম ইতিহাস ম্যাগাজিন। হারিয়ে যাওয়া পেশা, পুরোনো জনপদ আর ভুলে যাওয়া মানুষের "
                "গবেষণাভিত্তিক গল্প — ছবি, অভিধান আর তথ্যসূত্রসহ। বাছাই করা পাতা বিনামূল্যে পড়ুন, "
                "ছাপা কপি ঘরে বসে অর্ডার করুন।")
    magazine_meta_title = models.CharField(max_length=70, blank=True,
        default="The Reverse Times Magazine — বাংলা ইতিহাস ম্যাগাজিন")
    magazine_meta_description = models.CharField(max_length=170, blank=True,
        default="বাংলাদেশের প্রথম ইতিহাস ম্যাগাজিন The Reverse Times। হারিয়ে যাওয়া পেশা, স্থান আর মানুষের গল্প — বাছাই করা পাতা বিনামূল্যে পড়ুন, ছাপা কপি অর্ডার করুন।")

    class Meta:
        verbose_name = "Store Page Settings"
        verbose_name_plural = "Store Page Settings"

    def __str__(self):
        return "Store Page Content"

MAX_PDF_MB = 120


def validate_pdf(file):
    """Reject anything that isn't really a PDF, and very large uploads."""
    from django.core.exceptions import ValidationError
    if file.size > MAX_PDF_MB * 1024 * 1024:
        raise ValidationError(f'PDF is larger than {MAX_PDF_MB} MB. Please compress it first.')
    pos = file.tell() if hasattr(file, 'tell') else 0
    file.seek(0)
    head = file.read(5)
    file.seek(pos)
    if head != b'%PDF-':
        raise ValidationError('This file is not a valid PDF.')


def parse_page_list(text, total=None):
    """'1-3, 7, 10-11' → [1, 2, 3, 7, 10, 11] (sorted, unique, within 1..total)."""
    pages = set()
    for part in re.split(r'[,\s]+', (text or '').strip()):
        if not part:
            continue
        m = re.fullmatch(r'(\d+)(?:-(\d+))?', part)
        if not m:
            continue
        a = int(m.group(1))
        b = int(m.group(2) or a)
        if a > b:
            a, b = b, a
        for n in range(a, min(b, a + 2000) + 1):
            if n >= 1 and (total is None or n <= total):
                pages.add(n)
    return sorted(pages)


class Product(models.Model):
    TYPE_CHOICES = (
        ('magazine', 'Magazine issue'),
        ('merch', 'Wearable History (T-shirts & merchandise)'),
        ('nostalgic', 'Nostalgic item'),
    )
    DIGITAL_CHOICES = (
        ('none', 'No digital version (print only)'),
        ('free', 'Free — anyone can read the whole issue online'),
        ('paid', 'Paid — selected pages free, rest unlocked after payment'),
    )
    LANGUAGE_CHOICES = (('bn', 'Bangla'), ('en', 'English'), ('bn-en', 'Bangla & English'))

    product_type = models.CharField(max_length=10, choices=TYPE_CHOICES, default='merch', db_index=True)
    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, blank=True)
    description = models.TextField()
    image = models.ImageField(upload_to='store/products/', help_text="Main photo. For a magazine: the cover (portrait, ideally 1200×1700).")
    price = models.DecimalField(max_digits=10, decimal_places=2, default=0,
                                help_text="Selling price. For a magazine this is the PRINTED copy price.")
    discount_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    sizes = models.CharField(max_length=200, blank=True, help_text="Comma-separated sizes (e.g., S, M, L, XL)")
    colors = models.CharField(max_length=200, blank=True, help_text="Comma-separated colors (e.g., Black, White, Red)")
    is_active = models.BooleanField(default=True, help_text="Untick to hide from the website.")
    is_featured = models.BooleanField(default=False, help_text="Show first on the homepage and at the top of its shop/magazine page.")
    in_stock = models.BooleanField(default=True, help_text="Untick when sold out (shown to Google as out of stock).")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)

    # SEO (optional — sensible defaults are used when blank)
    meta_title = models.CharField(max_length=70, blank=True, help_text="Google title, about 60 characters. Blank = product title.")
    meta_description = models.CharField(max_length=170, blank=True, help_text="Google description, about 155 characters. Blank = start of description.")
    image_alt = models.CharField(max_length=150, blank=True, help_text="Describe the main photo for Google Images and screen readers.")
    sku = models.CharField(max_length=40, blank=True, help_text="Optional stock code. Blank = RT-<id>.")

    # Magazine issue fields (used when type = Magazine issue)
    issue_label = models.CharField(max_length=60, blank=True, help_text="e.g. সংখ্যা ০১ · কার্তিক ১৪৩৩")
    subtitle = models.CharField(max_length=200, blank=True, help_text="One-line hook shown under the title.")
    contents = models.TextField(blank=True, help_text="What's inside — one item per line, e.g. '০০১ ভিস্তিওয়ালা — মশকে ভরা শহরের তৃষ্ণা'.")
    language = models.CharField(max_length=6, choices=LANGUAGE_CHOICES, default='bn')
    published_on = models.DateField(null=True, blank=True)
    page_count = models.PositiveSmallIntegerField(null=True, blank=True)
    print_available = models.BooleanField(default=True, help_text="Sell printed copies through the cart at the price above.")
    digital_mode = models.CharField(max_length=5, choices=DIGITAL_CHOICES, default='paid',
                                    help_text="How the digital (online) edition works.")
    digital_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True,
                                        help_text="Price to unlock the full digital issue (Paid only).")
    pdf_file = models.FileField(storage=private_storage, upload_to='magazines/', blank=True,
                                validators=[FileExtensionValidator(['pdf']), validate_pdf],
                                help_text=f"Full magazine PDF (max {MAX_PDF_MB} MB). Stored privately.")
    preview_pages = models.CharField(max_length=200, blank=True, default='1-3',
                                     help_text="Pages guests can read without paying or signing in, e.g. '1-3, 7, 10-11'. Paid: the free sample. Free: the preview before sign-in.")
    preview_page_list = models.JSONField(default=list, blank=True, editable=False)
    preview_pdf = models.FileField(upload_to='magazines/previews/', blank=True, editable=False)

    def save(self, *args, **kwargs):
        if not self.slug:
            fallback = {'magazine': 'issue', 'nostalgic': 'nostalgic-item'}.get(self.product_type, 'item')
            base = slugify(self.title) or f'{fallback}-{(Product.objects.order_by("-pk").values_list("pk", flat=True).first() or 0) + 1}'
            slug, n = base, 2
            while Product.objects.filter(slug=slug).exclude(pk=self.pk).exists():
                slug, n = f'{base}-{n}', n + 1
            self.slug = slug
        super().save(*args, **kwargs)

    @property
    def is_magazine(self):
        return self.product_type == 'magazine'

    def get_absolute_url(self):
        if self.is_magazine:
            return reverse('magazine_detail', kwargs={'slug': self.slug})
        return reverse('product_detail', kwargs={'slug': self.slug})

    @property
    def current_price(self):
        if self.discount_price and self.discount_price < self.price:
            return self.discount_price
        return self.price

    @property
    def sku_code(self):
        return self.sku or f'RT-{self.pk}'

    @property
    def has_digital(self):
        return self.is_magazine and self.digital_mode != 'none' and bool(self.pdf_file)

    @property
    def is_free_digital(self):
        return self.has_digital and self.digital_mode == 'free'

    @property
    def can_buy_digital(self):
        return self.has_digital and self.digital_mode == 'paid' and self.digital_price is not None

    @property
    def free_page_count(self):
        if self.is_free_digital:
            return self.page_count or 0
        return len(self.preview_page_list or [])

    # kept for older templates / code
    @property
    def free_pages(self):
        return self.free_page_count

    @property
    def can_order_print(self):
        return (not self.is_magazine or self.print_available) and self.in_stock

    @property
    def edition_label(self):
        parts = []
        if self.is_free_digital:
            parts.append('Free online')
        elif self.can_buy_digital:
            parts.append('Digital')
        if self.is_magazine and self.print_available:
            parts.append('Print')
        return ' · '.join(parts)

    @property
    def contents_list(self):
        return [line.strip() for line in self.contents.splitlines() if line.strip()]

    def __str__(self):
        return self.title

class ProductImage(models.Model):
    product = models.ForeignKey(Product, related_name='images', on_delete=models.CASCADE)
    image = models.ImageField(upload_to='store/products/gallery/')
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Image for {self.product.title}"

class Coupon(models.Model):
    """Discount codes. Every rule is optional — leave a field empty for "no limit"."""
    DISCOUNT_CHOICES = (
        ('percentage', 'Percentage (%)'),
        ('fixed', 'Fixed Amount (৳)'),
    )
    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'),
    )
    SOURCE = (('manual', 'Made in admin'), ('game', 'Game reward'))

    code = models.CharField(max_length=50, unique=True, help_text="Coupon code (e.g. WINTER20). Not case-sensitive.")
    note = models.CharField(max_length=200, blank=True, help_text="Internal note, e.g. 'Facebook winter campaign'.")
    discount_type = models.CharField(max_length=20, choices=DISCOUNT_CHOICES, default='percentage')
    discount_value = models.DecimalField(max_digits=10, decimal_places=2, help_text="Percentage or fixed amount to deduct")
    max_discount = models.DecimalField("Maximum discount (৳)", max_digits=10, decimal_places=2, null=True, blank=True,
                                       help_text="Cap for percentage coupons, e.g. 20% but never more than ৳200. Empty = no cap.")
    min_order_amount = models.DecimalField("Minimum order (৳)", max_digits=10, decimal_places=2, null=True, blank=True,
                                           help_text="Coupon works only when the eligible items cost at least this much.")
    applies_to = models.CharField(max_length=20, choices=APPLIES, default='all')
    products = models.ManyToManyField('Product', blank=True, related_name='coupons',
                                      help_text="Used when 'Applies to' is 'Only the products picked below'.")
    is_active = models.BooleanField(default=True)
    valid_from = models.DateTimeField(null=True, blank=True)
    valid_to = models.DateTimeField(null=True, blank=True)
    max_uses = models.PositiveIntegerField("Total uses allowed", null=True, blank=True, default=100,
                                           help_text="How many times the code can be used in total. Empty = unlimited.")
    per_customer_limit = models.PositiveIntegerField("Uses per customer", null=True, blank=True, default=1,
                                                     help_text="Counted by account and by phone number. Empty = unlimited.")
    requires_login = models.BooleanField("Signed-in customers only", default=False)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE,
                              related_name='coupons', help_text="If set, only this account can use the code.")
    source = models.CharField(max_length=10, choices=SOURCE, default='manual', editable=False)
    current_uses = models.PositiveIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']

    def save(self, *args, **kwargs):
        self.code = (self.code or '').strip().upper()
        super().save(*args, **kwargs)

    @property
    def uses_left(self):
        return None if self.max_uses is None else max(0, self.max_uses - self.current_uses)

    def is_valid(self):
        from django.utils import timezone
        if not self.is_active:
            return False
        if self.max_uses is not None and self.current_uses >= self.max_uses:
            return False
        now = timezone.now()
        if self.valid_from and now < self.valid_from:
            return False
        if self.valid_to and now > self.valid_to:
            return False
        return True

    def covers(self, product, channel='print'):
        """Is this product (bought as 'print' or 'digital') eligible?"""
        a = self.applies_to
        if a == 'all':
            return True
        if a == 'selected':
            return self.products.filter(pk=product.pk).exists()
        if product.product_type == 'magazine':
            return a == 'magazines' or a == f'magazine_{channel}'
        return a == product.product_type

    SCOPE_BN = {
        'all': 'সব পণ্য ও ডিজিটাল ম্যাগাজিনে', 'magazines': 'ম্যাগাজিনে (ছাপা ও ডিজিটাল)',
        'magazine_digital': 'ডিজিটাল ম্যাগাজিনে', 'magazine_print': 'ছাপা ম্যাগাজিনে',
        'merch': 'ইতিহাস-পোশাকে', 'nostalgic': 'পুরনো দিনের জিনিসে', 'selected': 'বাছাই করা পণ্যে',
    }

    def describe_bn(self):
        bn = str.maketrans('0123456789', '০১২৩৪৫৬৭৮৯')
        amount = (f"{self.discount_value:.0f}%" if self.discount_type == 'percentage' else f"৳{self.discount_value:.0f}").translate(bn)
        text = f"{self.SCOPE_BN.get(self.applies_to, '')} {amount} ছাড়"
        if self.max_discount is not None and self.discount_type == 'percentage':
            text += f" (সর্বোচ্চ ৳{self.max_discount:.0f})".translate(bn)
        return text

    def describe(self):
        amount = f"{self.discount_value:.0f}%" if self.discount_type == 'percentage' else f"৳{self.discount_value:.0f}"
        return f"{amount} off · {self.get_applies_to_display()}"

    def __str__(self):
        return f"{self.code} ({self.describe()})"


class CouponRedemption(models.Model):
    coupon = models.ForeignKey(Coupon, on_delete=models.CASCADE, related_name='redemptions')
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL,
                             related_name='coupon_redemptions')
    phone = models.CharField(max_length=20, blank=True, db_index=True)
    order = models.ForeignKey('Order', null=True, blank=True, on_delete=models.SET_NULL, related_name='redemptions')
    digital_access = models.ForeignKey('DigitalAccess', null=True, blank=True, on_delete=models.SET_NULL,
                                       related_name='redemptions')
    amount = models.DecimalField("Discount given (৳)", max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.coupon.code} − ৳{self.amount}"


class Order(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL,
                             related_name='shop_orders', help_text="Customer account (if signed in)")
    STATUS_CHOICES = (
        ('pending', 'Order received'),
        ('confirmed', 'Confirmed'),
        ('shipped', 'Shipped / on the way'),
        ('delivered', 'Delivered'),
        ('cancelled', 'Cancelled'),
    )
    STEPS = ('pending', 'confirmed', 'shipped', 'delivered')

    name = models.CharField(max_length=150)
    phone = models.CharField(max_length=20)
    alt_phone = models.CharField(max_length=20, blank=True)
    division = models.CharField(max_length=40, blank=True)
    district = models.CharField(max_length=40, blank=True)
    area = models.CharField("Area / Upazila / Thana", max_length=80, blank=True)
    address_line = models.CharField("Village / Road / House / Market", max_length=300, blank=True)
    location = models.TextField(help_text="Full delivery address")
    note = models.TextField(blank=True, null=True, help_text="Special instructions")
    
    coupon = models.ForeignKey(Coupon, on_delete=models.SET_NULL, null=True, blank=True)
    discount_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    courier = models.CharField(max_length=80, blank=True, help_text="e.g. Pathao, Steadfast, RedX, Sundarban")
    tracking_code = models.CharField(max_length=80, blank=True, help_text="Courier tracking / consignment number")
    customer_message = models.CharField(max_length=300, blank=True,
                                        help_text="Shown to the customer on their order page, e.g. 'Arriving Thursday'.")
    created_at = models.DateTimeField(auto_now_add=True)
    confirmed_at = models.DateTimeField(null=True, blank=True)
    shipped_at = models.DateTimeField(null=True, blank=True)
    delivered_at = models.DateTimeField(null=True, blank=True)
    cancelled_at = models.DateTimeField(null=True, blank=True)

    def save(self, *args, **kwargs):
        # Remember when each step happened, for the customer's tracking timeline.
        from django.utils import timezone
        stamp = {'confirmed': 'confirmed_at', 'shipped': 'shipped_at', 'delivered': 'delivered_at',
                 'cancelled': 'cancelled_at'}.get(self.status)
        if stamp and not getattr(self, stamp):
            setattr(self, stamp, timezone.now())
            if self.status in ('shipped', 'delivered') and not self.confirmed_at:
                self.confirmed_at = getattr(self, stamp)
            if self.status == 'delivered' and not self.shipped_at:
                self.shipped_at = self.delivered_at
        super().save(*args, **kwargs)

    def timeline(self):
        """Steps for the tracking view: [{key, label, done, current, at}]."""
        labels = {'pending': 'অর্ডার গ্রহণ করা হয়েছে', 'confirmed': 'অর্ডার নিশ্চিত হয়েছে',
                  'shipped': 'পাঠানো হয়েছে', 'delivered': 'ডেলিভারি সম্পন্ন'}
        times = {'pending': self.created_at, 'confirmed': self.confirmed_at, 'shipped': self.shipped_at,
                 'delivered': self.delivered_at}
        reached = self.STEPS.index(self.status) if self.status in self.STEPS else -1
        return [{'key': k, 'label': labels[k], 'done': i <= reached, 'current': i == reached, 'at': times[k]}
                for i, k in enumerate(self.STEPS)]

    def __str__(self):
        return f"Order #{self.id} - {self.name}"

class OrderItem(models.Model):
    order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
    size = models.CharField(max_length=50, blank=True, null=True)
    color = models.CharField(max_length=50, blank=True, null=True)
    quantity = models.PositiveIntegerField(default=1)
    price = models.DecimalField(max_digits=10, decimal_places=2, help_text="Price at the time of purchase")

    @property
    def line_total(self):
        return self.price * self.quantity

    def __str__(self):
        return f"{self.quantity} x {self.product.title if self.product else 'Unknown Product'} for Order #{self.order.id}"


class DigitalAccess(models.Model):
    """A reader's request to read a full digital magazine (approved by the team)."""
    STATUS = (
        ('pending', 'Pending — check payment'),
        ('approved', 'Approved — can read'),
        ('rejected', 'Rejected'),
        ('revoked', 'Access revoked'),
    )
    reference = models.CharField(max_length=12, unique=True, editable=False)
    product = models.ForeignKey(Product, on_delete=models.PROTECT, related_name='digital_access',
                                limit_choices_to={'product_type': 'magazine'})
    user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL,
                             related_name='magazine_access', help_text="Reader account (if signed in)")
    name = models.CharField(max_length=150)
    phone = models.CharField(max_length=20, help_text="Reader's mobile number")
    sender_number = models.CharField(max_length=20, help_text="Number the money was sent from")
    trx_id = models.CharField("Transaction ID", max_length=30, unique=True)
    amount = models.DecimalField(max_digits=8, decimal_places=2, help_text="What the reader should have sent (after any coupon)")
    coupon = models.ForeignKey(Coupon, null=True, blank=True, on_delete=models.SET_NULL, related_name='digital_orders')
    discount_amount = models.DecimalField(max_digits=8, decimal_places=2, default=0)
    status = models.CharField(max_length=10, choices=STATUS, default='pending', db_index=True)
    access_token = models.CharField(max_length=64, unique=True, editable=False)
    admin_note = models.TextField(blank=True, help_text="Internal; shown to the reader only if rejected.")
    open_count = models.PositiveIntegerField(default=0)
    created_at = models.DateTimeField(auto_now_add=True)
    reviewed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = "Digital magazine access"
        verbose_name_plural = "Digital magazine access (approve readers)"

    def __str__(self):
        return f"{self.reference} · {self.name} · {self.product.title}"

    def save(self, *args, **kwargs):
        if not self.reference:
            alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
            while True:
                code = 'RT-' + ''.join(secrets.choice(alphabet) for _ in range(6))
                if not DigitalAccess.objects.filter(reference=code).exists():
                    break
            self.reference = code
        if not self.access_token:
            self.access_token = secrets.token_urlsafe(32)
        super().save(*args, **kwargs)


# ─── Admin-friendly views of the one Product table ─────────────────────────────

class MagazineIssueManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(product_type='magazine')


class WearableManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(product_type='merch')


class NostalgicManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(product_type='nostalgic')


class MagazineIssue(Product):
    objects = MagazineIssueManager()

    class Meta:
        proxy = True
        verbose_name = 'Magazine issue'
        verbose_name_plural = 'Magazine issues'

    def save(self, *args, **kwargs):
        self.product_type = 'magazine'
        super().save(*args, **kwargs)


class WearableHistoryProduct(Product):
    objects = WearableManager()

    class Meta:
        proxy = True
        verbose_name = 'Wearable History product'
        verbose_name_plural = 'Wearable History (merchandise)'

    def save(self, *args, **kwargs):
        self.product_type = 'merch'
        super().save(*args, **kwargs)


class NostalgicItem(Product):
    objects = NostalgicManager()

    class Meta:
        proxy = True
        verbose_name = 'Nostalgic item'
        verbose_name_plural = 'Nostalgic items'

    def save(self, *args, **kwargs):
        self.product_type = 'nostalgic'
        super().save(*args, **kwargs)
