import datetime
from pathlib import Path
from uuid import uuid4

from category.models import Category
from django.core.validators import FileExtensionValidator
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from main.models import NummiModel, NummiQuerySet
from main.utils import pdf_outline_to_str
from media.utils import get_path
from pypdf import PdfReader
from statement.models import Statement


class TransactionQuerySet(NummiQuerySet):
    fields = {
        "description": "B",
        "trader": "B",
        "category__name": "C",
    }


class Transaction(NummiModel):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(
        max_length=256, default=_("Transaction"), verbose_name=_("Name")
    )
    description = models.TextField(null=True, blank=True, verbose_name=_("Description"))
    value = models.DecimalField(
        max_digits=12, decimal_places=2, default=0, verbose_name=_("Value")
    )
    date = models.DateField(default=datetime.date.today, verbose_name=_("Date"))
    real_date = models.DateField(blank=True, null=True, verbose_name=_("Real date"))
    trader = models.CharField(
        max_length=128, blank=True, null=True, verbose_name=_("Trader")
    )
    payment = models.CharField(
        max_length=128, blank=True, null=True, verbose_name=_("Payment")
    )
    category = models.ForeignKey(
        Category,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        verbose_name=_("Category"),
    )
    statement = models.ForeignKey(
        Statement,
        on_delete=models.CASCADE,
        blank=True,
        null=True,
        verbose_name=_("Statement"),
    )

    objects = TransactionQuerySet.as_manager()

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

    def get_absolute_url(self):
        return reverse("transaction", args=(self.pk,))

    def get_delete_url(self):
        return reverse("del_transaction", args=(self.pk,))

    @property
    def account(self):
        if self.statement:
            return self.statement.account

    class Meta:
        ordering = ["-date", "statement"]
        verbose_name = _("Transaction")
        verbose_name_plural = _("Transactions")


class InvoiceQuerySet(NummiQuerySet):
    fields = {
        "metadata": "B",
        "tags": "C",
    }


class Invoice(NummiModel):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    name = models.CharField(
        max_length=256, default=_("Invoice"), verbose_name=_("Name")
    )
    file = models.FileField(
        upload_to=get_path,
        validators=[FileExtensionValidator(["pdf"])],
        verbose_name=_("File"),
        max_length=128,
    )
    transaction = models.ForeignKey(
        Transaction, on_delete=models.CASCADE, editable=False
    )
    metadata = models.TextField(blank=True)
    tags = models.TextField(blank=True)

    objects = InvoiceQuerySet.as_manager()

    def save(self, *args, **kwargs):
        if Invoice.objects.filter(id=self.id).exists():
            _prever = Invoice.objects.get(id=self.id)
            if _prever.file and _prever.file != self.file:
                Path(_prever.file.path).unlink(missing_ok=True)

        if self.file:
            reader = PdfReader(self.file)

            if reader.metadata:
                self.metadata = " ".join(
                    (
                        m.replace("\x00", "").strip()
                        for m in (
                            reader.metadata.title,
                            reader.metadata.author,
                            reader.metadata.subject,
                        )
                        if m
                    )
                )

            _tags = pdf_outline_to_str(reader.outline)
            _tags += " ".join(
                (page.extract_text().replace("\x00", "") for page in reader.pages)
            )
            self.tags = " ".join((tag for tag in _tags.split() if len(tag) >= 3))

        super().save(*args, **kwargs)

    def __str__(self):
        return str(self.name)

    def delete(self, *args, **kwargs):
        self.file.delete()
        super().delete(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("invoice", args=(self.transaction.pk, self.pk))

    def get_delete_url(self):
        return reverse("del_invoice", args=(self.transaction.pk, self.pk))

    class Meta:
        verbose_name = _("Invoice")
        verbose_name_plural = _("Invoices")
        ordering = ["transaction", "name"]
