from django.db import models, transaction
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError

from tickets.models.ticket_list import TicketList


class Ticket(models.Model):
    TICKET_TYPES = (
        (1, "ST_REQUEST", [
            [111, 121, 149, 159],
            [110, 121, 149, 159],
            [121, 131, 149, 159],
            [131, 141, 149],
            [141, 151, 110],
            [149, 151, 110],
            [159],
            [151]
        ]),
        (2, "SERVICE_REQUEST", [
            [210, 211, 251],
            [211, 212, 220, 238, 249],
            [212, 221, 229, 238, 249],
            [221, 222, 238, 249],
            [220, 211, 238, 249],
            [229, 211, 251],
            [222, 231, 238, 249],
            [231, 241, 238, 249],
            [238, 231, 239, 211, 212, 221, 220, 222, 249],
            [239, 231, 239, 211, 212, 221, 220, 222, 249],
            [241, 251],
            [249, 251],
            [251]
        ]),
        (3, "ACCESS_REQUEST", [
            [320, 321, 359],
            [321, 359],
            [359]
        ]),
        (4, "NEG_REQUEST", [
            [420, 421, 459],
            [421, 459],
            [459]
        ])
    )

    TICKET_STATUSES_NAMES = {
        111: "NEW",
        110: "REOPENED",
        121: "ASSIGNED",
        131: "IN PROCESS",
        149: "WONTFIX",
        141: "DONE",
        159: "DUPLICATE",
        151: "CLOSED",
        210: "TEMPLATE",
        211: "BOOKED",
        212: "ASSIGNED",
        221: "ACCEPTED",
        220: "PENDING",
        229: "DECLINED",
        222: "PRE-START",
        231: "PROCESS",
        238: "PRE-FORCEMAJEUER",
        239: "FORCEMAJEUER",
        241: "DONE",
        249: "CANCELLED",
        251: "CLOSED",
        320: "PENDING",
        321: "ACCEPTED",
        359: "DECLINED",
        420: "PENDING",
        421: "ACCEPTED",
        459: "DECLINED"
    }

    TICKET_TYPES_CHOICES = tuple((item[0], item[1]) for item in TICKET_TYPES)
    LIFE_CYCLE_DICT = dict((item[0], item[2]) for item in TICKET_TYPES)

    # DATA
    title = models.CharField(max_length=128)
    status = models.PositiveSmallIntegerField(null=True)
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True)
    due_date = models.DateField()
    note = models.TextField(blank=True, null=True)
    json = models.TextField(blank=True, null=True)
    priority = models.PositiveSmallIntegerField(default=0)

    # FK
    created_by = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, related_name="created_by", editable=False)
    assigned_to = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, blank=True, related_name="assigned_to")
    ticket_list = models.ForeignKey(TicketList, on_delete=models.CASCADE)
    ticket_type = models.PositiveSmallIntegerField(choices=TICKET_TYPES_CHOICES, default=1)

    def __str__(self):
        return self.title

    def _get_statuses(self) -> list:
        return self.LIFE_CYCLE_DICT.get(self.ticket_type)

    def get_available_statuses(self) -> list:
        for status_scenario in self._get_statuses():
            if status_scenario[0] == int(self.status):
                return status_scenario[1:] if len(status_scenario) > 1 else None

    def set_first_status(self):
        self.status = self._get_statuses()[0][0]

    def get_status_display(self):
        return self.TICKET_STATUSES_NAMES.get(self.status)

    def archive(self):
        """
        Архивирует текущий тикет.
        
        Создает новую запись в TicketArchive с информацией текущего тикета,
        а затем удаляет текущий тикет из базы данных.
        """
        with transaction.atomic():
            # Создаем новую запись в TicketArhive, сохраняя значения всех полей
            TicketArchive.objects.create(
                title=self.title,
                ticket_list=self.ticket_list,
                ticket_type=self.ticket_type,
                status=self.status,
                created_at=self.created_at,
                due_date=self.due_date,
                created_by=self.created_by,
                assigned_to=self.assigned_to,
                note=self.note
            )
            # Удаляем текущий тикет
            self.delete()

    def save(self, *args, **kwargs):
        if not self.status:
            self.set_first_status()
        
        super(Ticket, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("tickets:ticket_detail", kwargs={"ticket_id": self.pk})

    class Meta:
        ordering = ["-priority", "created_at"]


class TicketArchive(models.Model):
    title = models.CharField(max_length=128, editable=False)
    ticket_list = models.ForeignKey(TicketList, on_delete=models.CASCADE, editable=False)
    ticket_type = models.PositiveSmallIntegerField(choices=Ticket.TICKET_TYPES_CHOICES, editable=False)
    status = models.PositiveSmallIntegerField(editable=False)
    created_at = models.DateTimeField(editable=False)
    updated_at = models.DateTimeField(auto_now_add=True, editable=False)
    due_date = models.DateField(editable=False)
    created_by = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, related_name="ticket_archive_created_by", editable=False)
    assigned_to = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, blank=True, related_name="ticket_archive_assigned_to", editable=False)
    note = models.TextField(blank=True, null=True, editable=False)

    def get_status_display(self):
        return Ticket.TICKET_STATUSES_NAMES.get(self.status)