import uuid

from functools import partial

from django.contrib.auth import get_user_model
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.forms import BooleanField
from django.utils.functional import cached_property
from model_utils.fields import AutoCreatedField
from model_utils.models import TimeStampedModel

from . import choices


User = get_user_model()


EmptyForeignKey = partial(
    models.ForeignKey,
    on_delete=models.PROTECT,
    related_name='+',
    blank=True,
    null=True,
)


class HireOrder(TimeStampedModel):

    uuid = models.UUIDField(
        default=uuid.uuid4,
        db_index=True,
        editable=False,
    )
    sha1 = models.CharField(
        max_length=40,
        db_index=True,
        null=True,
        help_text='Хэш, взятый по raw_data',
    )
    created_by = models.ForeignKey(
        to=User,
        on_delete=models.PROTECT,
        related_name='+',
    )

    status = models.CharField(
        max_length=32,
        choices=choices.HIRE_ORDER_STATUSES,
        default=choices.HIRE_ORDER_STATUSES.new,
    )
    resolution = models.CharField(
        max_length=32,
        choices=choices.HIRE_ORDER_RESOLUTIONS,
        blank=True,
    )
    resolution_description = models.TextField(blank=True)

    recruiter = EmptyForeignKey(User)
    candidate = EmptyForeignKey('candidates.Candidate')
    vacancy = EmptyForeignKey('vacancies.Vacancy')
    application = EmptyForeignKey('interviews.Application')
    offer = EmptyForeignKey('offers.Offer')

    raw_data = JSONField()
    table_flow_data = JSONField(null=True, blank=True)

    TRACK_HISTORY_FIELDS = {
        'status',
        'resolution',
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._store_old_fields()

    def __str__(self):
        return f'HireOrder {self.uuid} [{self.status}]'

    def save(self, *args, **kwargs):
        is_creation = self.pk is None
        super().save(*args, **kwargs)
        is_history_needed = (
            is_creation
            or any(self._old[f] != getattr(self, f) for f in self.TRACK_HISTORY_FIELDS)
        )
        if is_history_needed:
            HireOrderHistory.create_from_hire_order(self)
            self._store_old_fields()

    @property
    def is_incorrect(self):
        return (
            self.status == choices.HIRE_ORDER_STATUSES.closed
            and self.resolution == choices.HIRE_ORDER_RESOLUTIONS.incorrect
        )

    @property
    def is_cancelled(self):
        return (
            self.status == choices.HIRE_ORDER_STATUSES.closed
            and self.resolution == choices.HIRE_ORDER_RESOLUTIONS.cancelled
        )

    @cached_property
    def force_verification_sending(self):
        """
        Если force_verification_sending=True:
        1. отправляем проверку КИ даже если она не обязательна, но при этом не задерживаем процесс
        автонайма на ожидании результатов проверки
        2. если проверка КИ обязательна - ни на что не влияет
        """
        return BooleanField().to_python(self.raw_data.get('force_verification_sending'))

    @cached_property
    def autofill_offer(self):
        return BooleanField().to_python(self.raw_data.get('autofill_offer'))

    def _store_old_fields(self):
        self._old = {
            field: getattr(self, field)
            for field in self.TRACK_HISTORY_FIELDS
        }

    class Meta:
        constraints = [
            # Может быть только 1 активный заказ с заданными параметрами у 1го создателя
            models.UniqueConstraint(
                fields=['created_by', 'sha1'],
                name='unique_active_hire_order',
                condition=~models.Q(status=choices.HIRE_ORDER_STATUSES.closed),
            ),
        ]


class HireOrderHistory(models.Model):

    hire_order = models.ForeignKey(HireOrder, on_delete=models.CASCADE, related_name='history')
    status = models.CharField(max_length=32, choices=choices.HIRE_ORDER_STATUSES)
    resolution = models.CharField(max_length=32, choices=choices.HIRE_ORDER_RESOLUTIONS, blank=True)
    changed_at = AutoCreatedField()

    @classmethod
    def create_from_hire_order(cls, hire_order: HireOrder):
        return cls.objects.create(
            hire_order=hire_order,
            status=hire_order.status,
            resolution=hire_order.resolution,
        )
