import decimal
from typing import List

import sform

from staff.departments.models import HRProduct
from staff.map.models import Office
from staff.departments import models as dep_models
from staff.oebs.models import Review, Reward, Job
from staff.person.models import Organization, Staff, Occupation

from staff.budget_position import models
from staff.budget_position.const import FemidaRequestType, FemidaProfessionalLevel


class AttachToVacancyForm(sform.SForm):
    budget_position_id = sform.SuggestField(
        queryset=models.BudgetPosition.objects.all(),
        to_field_name='code',
        label_fields=('code',),
    )
    vacancy = sform.IntegerField()
    vacancy_name = sform.CharField()
    job_issue_key = sform.CharField()
    salary_issue_key = sform.CharField()
    department = sform.ModelChoiceField(
        queryset=dep_models.Department.objects.all(),
        label_extractor='id',
    )
    office = sform.ModelChoiceField(
        queryset=Office.objects.filter(intranet_status=1).order_by('name'),
        label_extractor='name',
    )
    payment_type = sform.CharField()
    salary = sform.CharField()
    currency = sform.CharField(max_length=4)
    review_scheme = sform.SuggestField(
        queryset=Review.objects.all(),
        to_field_name='scheme_id',
        label_fields=('name',),
    )
    bonus_scheme = sform.SuggestField(
        queryset=dep_models.Bonus.objects.filter(intranet_status=1),
        to_field_name='scheme_id',
        label_fields=('name',),
    )
    reward_scheme = sform.SuggestField(
        queryset=Reward.objects.all(),
        to_field_name='scheme_id',
        label_fields=('name',),
    )
    geography_translation_id = sform.SuggestField(
        queryset=dep_models.Geography.objects.filter(intranet_status=1),
        to_field_name='st_translation_id',
        label_fields=('description',),
    )
    hr_product_translation_id = sform.SuggestField(
        queryset=HRProduct.objects.active(),
        to_field_name='st_translation_id',
        label_fields=('product_name',),
    )
    hr_product_id = sform.SuggestField(
        queryset=HRProduct.objects.active(),
        to_field_name='id',
        label_fields=('product_name',),
    )
    profession_key = sform.SuggestField(
        queryset=Occupation.objects.all(),
        to_field_name='name',
        label_fields=('name',),
    )
    professional_level = sform.ChoiceField(
        choices=FemidaProfessionalLevel.choices(),
        state=sform.NORMAL,
    )
    dismissal_date = sform.CharField()
    grade = sform.IntegerField()
    offer = sform.IntegerField()
    organization = sform.ModelChoiceField(
        queryset=Organization.objects.filter(intranet_status=1).order_by('name'),
        label_extractor='name',
    )
    username = sform.ModelChoiceField(
        queryset=Staff.objects.all(),
        to_field_name='login',
        label_extractor='login',
    )
    work_hours_weekly = sform.IntegerField()
    request_type = sform.ChoiceField(choices=FemidaRequestType.choices(), state=sform.REQUIRED)
    is_internship = sform.NullBooleanField()

    def get_field_state(self, name):
        if (
            name == 'hr_product_translation_id'
            and self.data.get('budget_position_id') is None
            and self.data.get('hr_product_id') is None
        ):
            return sform.REQUIRED

        return super(AttachToVacancyForm, self).get_field_state(name=name)

    @staticmethod
    def clean_salary(value):
        if not value:
            return value

        try:
            decimal.Decimal(value)
        except decimal.InvalidOperation:
            raise sform.ValidationError('salary is not a number', code='invalid')
        return value

    @staticmethod
    def clean_professional_level(value: str) -> FemidaProfessionalLevel or None:
        if not value:
            return None
        return FemidaProfessionalLevel(int(value))


class AssignmentCreateForm(sform.SForm):
    # Fields, required by OEBS Hire
    # ID физ лица в Я.Найм
    person = sform.IntegerField(state=sform.REQUIRED)
    join_at = sform.DateField(state=sform.REQUIRED)

    # Fields, not required by OEBS Hire
    budget_position_id = sform.SuggestField(
        queryset=models.BudgetPosition.objects.all(),
        to_field_name='code',
        label_fields=('code',),
    )
    department = sform.ModelChoiceField(
        queryset=dep_models.Department.objects.all(),
        label_extractor='id',
    )
    office = sform.ModelChoiceField(
        queryset=Office.objects.filter(intranet_status=1),
        label_extractor='name',
    )
    employment_type = sform.CharField()
    payment_type = sform.CharField()
    salary = sform.CharField()
    currency = sform.CharField()
    organization = sform.ModelChoiceField(
        queryset=Organization.objects.filter(intranet_status=1),
        label_extractor='name',
    )
    position = sform.ModelChoiceField(
        queryset=Job.objects.filter(is_deleted_from_oebs=False),
        label_extractor='code',
    )
    other_payments = sform.CharField()
    probation_period = sform.IntegerField()
    is_replacement = sform.BooleanField()
    instead_of = sform.ModelChoiceField(
        queryset=Staff.objects.all(),
        to_field_name='login',
        label_extractor='login',
    )
    contract_term_date = sform.DateField()
    contract_term = sform.IntegerField()


class ExportChangesForm(sform.SForm):
    from_id = sform.IntegerField()
    from_date = sform.DateTimeField(input_formats=(
        '%Y-%m-%dT%H:%M:%S.%fZ',  # '2006-10-25T14:30:59.000Z'
        '%Y-%m-%dT%H:%M:%S',      # '2006-10-25T14:30:59'
        '%Y-%m-%dT%H:%M',         # '2006-10-25T14:30'
        '%Y-%m-%d',               # '2006-10-25'
    ))
    from_effective_date = sform.DateField()


class ExportChangeRegistryForm(sform.SForm):
    continuation_token = sform.DateTimeField(input_formats=(
        '%Y-%m-%dT%H:%M:%S.%fZ',  # '2006-10-25T14:30:59.000Z'
        '%Y-%m-%dT%H:%M:%S.%f',   # '2006-10-25T14:30:59.000'
        '%Y-%m-%dT%H:%M:%S',      # '2006-10-25T14:30:59'
        '%Y-%m-%dT%H:%M',         # '2006-10-25T14:30'
        '%Y-%m-%d',               # '2006-10-25'
    ))


class GetBlockedBudgetPositionsForm(sform.SForm):
    codes = sform.GridField(
        sform.SuggestField(
            queryset=models.BudgetPosition.objects.all(),
            to_field_name='code',
            label_fields=('code',),
        ),
        state=sform.REQUIRED,
    )

    def clean_codes(self, value: List[models.BudgetPosition]) -> List[int]:
        return [item.code for item in value]
