from typing import Any

from django import forms
from django.utils import timezone
from django_select2.forms import ModelSelect2Widget
from guardian.shortcuts import get_objects_for_user

from web.domains.template.context import CoverLetterTemplateContext
from web.domains.template.utils import find_invalid_placeholders
from web.forms.widgets import DateInput, JoditTextArea
from web.models import (
    EndorsementImportApplication,
    ImportApplication,
    ImportApplicationLicence,
    Importer,
    Office,
    Template,
    User,
)
from web.permissions import Perms


class CreateImportApplicationForm(forms.Form):
    importer = forms.ModelChoiceField(
        queryset=Importer.objects.none(),
        label="Main Importer",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Importer",
            },
            search_fields=(
                "name__icontains",
                "user__first_name__icontains",
                "user__last_name__icontains",
            ),
        ),
    )
    importer_office = forms.ModelChoiceField(
        queryset=Office.objects.none(),
        label="Importer Office",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Office",
            },
            search_fields=(
                "postcode__icontains",
                "address_1__icontains",
                "address_2__icontains",
                "address_3__icontains",
                "address_4__icontains",
                "address_5__icontains",
                "address_6__icontains",
                "address_7__icontains",
                "address_8__icontains",
            ),
            dependent_fields={"importer": "importer"},
        ),
    )

    agent = forms.ModelChoiceField(
        required=False,
        queryset=Importer.objects.none(),
        label="Agent of Main Importer",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Agent",
            },
            search_fields=("name__icontains",),
            # Key is a name of a field in a form.
            # Value is a name of a field in a model (used in `queryset`).
            dependent_fields={"importer": "main_importer"},
        ),
    )
    agent_office = forms.ModelChoiceField(
        required=False,
        queryset=Office.objects.none(),
        label="Agent Office",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Office",
            },
            search_fields=(
                "postcode__icontains",
                "address_1__icontains",
                "address_2__icontains",
                "address_3__icontains",
                "address_4__icontains",
                "address_5__icontains",
                "address_6__icontains",
                "address_7__icontains",
                "address_8__icontains",
            ),
            # Key is a name of a field in a form.
            # Value is a name of a field in a model (used in `queryset`).
            dependent_fields={"agent": "importer"},
        ),
    )

    def __init__(self, *args: Any, user: User, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

        self.user = user

        # Return main importers the user can edit or is an agent of.
        importers = get_objects_for_user(
            user,
            [Perms.obj.importer.edit, Perms.obj.importer.is_agent],
            Importer.objects.filter(is_active=True, main_importer__isnull=True),
            any_perm=True,
        )
        self.fields["importer"].queryset = importers
        self.fields["importer_office"].queryset = Office.objects.filter(
            is_active=True, importer__in=importers
        )

        # Return agents linked to importers the user can edit (if any)
        active_agents = Importer.objects.filter(is_active=True, main_importer__in=importers)
        agents = get_objects_for_user(user, [Perms.obj.importer.edit], active_agents)

        self.fields["agent"].queryset = agents
        self.fields["agent_office"].queryset = Office.objects.filter(
            is_active=True, importer__in=agents
        )

    def clean(self) -> dict[str, Any]:
        cleaned_data = super().clean()

        importer = cleaned_data.get("importer")
        # if importer is not set agent and agent_office are not displayed.
        if not importer:
            return cleaned_data

        is_agent = self.user.has_perm(Perms.obj.importer.is_agent, importer)

        if is_agent:
            if not cleaned_data.get("agent"):
                self.add_error("agent", "You must enter this item")

            if not cleaned_data.get("agent_office"):
                self.add_error("agent_office", "You must enter this item")

        return cleaned_data


class CreateWoodQuotaApplicationForm(CreateImportApplicationForm):
    """Create wood quota application form - Defines extra validation logic"""

    def clean(self) -> dict[str, Any]:
        cleaned_data = super().clean()

        if not self.has_error("importer_office"):
            office: Office = cleaned_data["importer_office"]
            postcode: str | None = office.postcode

            if not postcode or (not postcode.upper().startswith("BT")):
                self.add_error(
                    "importer_office",
                    "Wood applications can only be made for Northern Ireland traders.",
                )

        return cleaned_data


class CoverLetterForm(forms.ModelForm):
    class Meta:
        model = ImportApplication
        fields = ("cover_letter_text",)
        widgets = {"cover_letter_text": JoditTextArea(attrs={"lang": "html"})}

    def __init__(self, *args, readonly: bool = False, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["cover_letter_text"].widget.attrs["readonly"] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data["cover_letter_text"]
        invalid_placeholders = find_invalid_placeholders(
            cover_letter_text, CoverLetterTemplateContext.valid_placeholders
        )
        if invalid_placeholders:
            self.add_error(
                "cover_letter_text",
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}",
            )

        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(
        required=True, label="Licence Start Date", widget=DateInput
    )
    licence_end_date = forms.DateField(required=True, label="Licence End Date", widget=DateInput)

    class Meta:
        model = ImportApplicationLicence
        fields = ("licence_start_date", "licence_end_date")

    def clean(self):
        data = super().clean()
        start_date = data.get("licence_start_date")
        end_date = data.get("licence_end_date")

        if not start_date or not end_date:
            return

        today = timezone.now().date()

        if start_date < today:
            self.add_error("licence_start_date", "Date must be in the future.")

        if end_date < today:
            self.add_error("licence_end_date", "Date must be in the future.")

        if end_date <= start_date:
            self.add_error("licence_end_date", "End Date must be after Start Date.")


class LicenceDateAndPaperLicenceForm(LicenceDateForm):
    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ("issue_paper_licence_only",)

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

        # The default label for unknown is "Unknown"
        self.fields["issue_paper_licence_only"].required = True
        self.fields["issue_paper_licence_only"].widget.choices = [
            ("unknown", "Select One"),
            ("true", "Yes"),
            ("false", "No"),
        ]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(
        max_digits=9, decimal_places=2, min_value=0, label="Period for re-importation (months)"
    )

    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)

        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data["reimport_period"]
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(
        queryset=Template.objects.filter(is_active=True, template_type=Template.ENDORSEMENT)
    )

    class Meta:
        model = EndorsementImportApplication
        fields = ("content",)

    def clean_content(self):
        endorsement = self.cleaned_data["content"]
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):
    class Meta:
        model = EndorsementImportApplication
        fields = ("content",)


class ChecklistBaseForm(forms.ModelForm):
    class Meta:
        fields = (
            "case_update",
            "fir_required",
            "response_preparation",
            "validity_period_correct",
            "endorsements_listed",
            "authorisation",
        )

    def __init__(self, *args, readonly_form: bool = False, **kwargs):
        super().__init__(*args, **kwargs)

        # Change checklist fields to required (e.g. only selected is valid)
        for field in ["response_preparation", "authorisation"]:
            self.fields[field].required = True

        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True

57b227b9bd5ced4ca7783c921591e4cda8524f6c
<mask token>


class CoverLetterForm(forms.ModelForm):


    class Meta:
        model = ImportApplication
        fields = 'cover_letter_text',
        widgets = {'cover_letter_text': JoditTextArea(attrs={'lang': 'html'})}

    def __init__(self, *args, readonly: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['cover_letter_text'].widget.attrs['readonly'] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data['cover_letter_text']
        invalid_placeholders = find_invalid_placeholders(cover_letter_text,
            CoverLetterTemplateContext.valid_placeholders)
        if invalid_placeholders:
            self.add_error('cover_letter_text',
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}"
                )
        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(required=True, label=
        'Licence Start Date', widget=DateInput)
    licence_end_date = forms.DateField(required=True, label=
        'Licence End Date', widget=DateInput)


    class Meta:
        model = ImportApplicationLicence
        fields = 'licence_start_date', 'licence_end_date'

    def clean(self):
        data = super().clean()
        start_date = data.get('licence_start_date')
        end_date = data.get('licence_end_date')
        if not start_date or not end_date:
            return
        today = timezone.now().date()
        if start_date < today:
            self.add_error('licence_start_date', 'Date must be in the future.')
        if end_date < today:
            self.add_error('licence_end_date', 'Date must be in the future.')
        if end_date <= start_date:
            self.add_error('licence_end_date',
                'End Date must be after Start Date.')


class LicenceDateAndPaperLicenceForm(LicenceDateForm):


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ('issue_paper_licence_only',)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['issue_paper_licence_only'].required = True
        self.fields['issue_paper_licence_only'].widget.choices = [(
            'unknown', 'Select One'), ('true', 'Yes'), ('false', 'No')]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(max_digits=9, decimal_places=2,
        min_value=0, label='Period for re-importation (months)')


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)
        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data['reimport_period']
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(queryset=Template.objects.filter(
        is_active=True, template_type=Template.ENDORSEMENT))


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',

    def clean_content(self):
        endorsement = self.cleaned_data['content']
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',


class ChecklistBaseForm(forms.ModelForm):


    class Meta:
        fields = ('case_update', 'fir_required', 'response_preparation',
            'validity_period_correct', 'endorsements_listed', 'authorisation')

    def __init__(self, *args, readonly_form: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        for field in ['response_preparation', 'authorisation']:
            self.fields[field].required = True
        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True

<mask token>


class CreateWoodQuotaApplicationForm(CreateImportApplicationForm):
    <mask token>
    <mask token>


class CoverLetterForm(forms.ModelForm):


    class Meta:
        model = ImportApplication
        fields = 'cover_letter_text',
        widgets = {'cover_letter_text': JoditTextArea(attrs={'lang': 'html'})}

    def __init__(self, *args, readonly: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['cover_letter_text'].widget.attrs['readonly'] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data['cover_letter_text']
        invalid_placeholders = find_invalid_placeholders(cover_letter_text,
            CoverLetterTemplateContext.valid_placeholders)
        if invalid_placeholders:
            self.add_error('cover_letter_text',
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}"
                )
        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(required=True, label=
        'Licence Start Date', widget=DateInput)
    licence_end_date = forms.DateField(required=True, label=
        'Licence End Date', widget=DateInput)


    class Meta:
        model = ImportApplicationLicence
        fields = 'licence_start_date', 'licence_end_date'

    def clean(self):
        data = super().clean()
        start_date = data.get('licence_start_date')
        end_date = data.get('licence_end_date')
        if not start_date or not end_date:
            return
        today = timezone.now().date()
        if start_date < today:
            self.add_error('licence_start_date', 'Date must be in the future.')
        if end_date < today:
            self.add_error('licence_end_date', 'Date must be in the future.')
        if end_date <= start_date:
            self.add_error('licence_end_date',
                'End Date must be after Start Date.')


class LicenceDateAndPaperLicenceForm(LicenceDateForm):


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ('issue_paper_licence_only',)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['issue_paper_licence_only'].required = True
        self.fields['issue_paper_licence_only'].widget.choices = [(
            'unknown', 'Select One'), ('true', 'Yes'), ('false', 'No')]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(max_digits=9, decimal_places=2,
        min_value=0, label='Period for re-importation (months)')


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)
        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data['reimport_period']
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(queryset=Template.objects.filter(
        is_active=True, template_type=Template.ENDORSEMENT))


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',

    def clean_content(self):
        endorsement = self.cleaned_data['content']
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',


class ChecklistBaseForm(forms.ModelForm):


    class Meta:
        fields = ('case_update', 'fir_required', 'response_preparation',
            'validity_period_correct', 'endorsements_listed', 'authorisation')

    def __init__(self, *args, readonly_form: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        for field in ['response_preparation', 'authorisation']:
            self.fields[field].required = True
        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True

<mask token>


class CreateImportApplicationForm(forms.Form):
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    def __init__(self, *args: Any, user: User, **kwargs: Any) ->None:
        super().__init__(*args, **kwargs)
        self.user = user
        importers = get_objects_for_user(user, [Perms.obj.importer.edit,
            Perms.obj.importer.is_agent], Importer.objects.filter(is_active
            =True, main_importer__isnull=True), any_perm=True)
        self.fields['importer'].queryset = importers
        self.fields['importer_office'].queryset = Office.objects.filter(
            is_active=True, importer__in=importers)
        active_agents = Importer.objects.filter(is_active=True,
            main_importer__in=importers)
        agents = get_objects_for_user(user, [Perms.obj.importer.edit],
            active_agents)
        self.fields['agent'].queryset = agents
        self.fields['agent_office'].queryset = Office.objects.filter(is_active
            =True, importer__in=agents)

    def clean(self) ->dict[str, Any]:
        cleaned_data = super().clean()
        importer = cleaned_data.get('importer')
        if not importer:
            return cleaned_data
        is_agent = self.user.has_perm(Perms.obj.importer.is_agent, importer)
        if is_agent:
            if not cleaned_data.get('agent'):
                self.add_error('agent', 'You must enter this item')
            if not cleaned_data.get('agent_office'):
                self.add_error('agent_office', 'You must enter this item')
        return cleaned_data


class CreateWoodQuotaApplicationForm(CreateImportApplicationForm):
    """Create wood quota application form - Defines extra validation logic"""

    def clean(self) ->dict[str, Any]:
        cleaned_data = super().clean()
        if not self.has_error('importer_office'):
            office: Office = cleaned_data['importer_office']
            postcode: str | None = office.postcode
            if not postcode or not postcode.upper().startswith('BT'):
                self.add_error('importer_office',
                    'Wood applications can only be made for Northern Ireland traders.'
                    )
        return cleaned_data


class CoverLetterForm(forms.ModelForm):


    class Meta:
        model = ImportApplication
        fields = 'cover_letter_text',
        widgets = {'cover_letter_text': JoditTextArea(attrs={'lang': 'html'})}

    def __init__(self, *args, readonly: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['cover_letter_text'].widget.attrs['readonly'] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data['cover_letter_text']
        invalid_placeholders = find_invalid_placeholders(cover_letter_text,
            CoverLetterTemplateContext.valid_placeholders)
        if invalid_placeholders:
            self.add_error('cover_letter_text',
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}"
                )
        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(required=True, label=
        'Licence Start Date', widget=DateInput)
    licence_end_date = forms.DateField(required=True, label=
        'Licence End Date', widget=DateInput)


    class Meta:
        model = ImportApplicationLicence
        fields = 'licence_start_date', 'licence_end_date'

    def clean(self):
        data = super().clean()
        start_date = data.get('licence_start_date')
        end_date = data.get('licence_end_date')
        if not start_date or not end_date:
            return
        today = timezone.now().date()
        if start_date < today:
            self.add_error('licence_start_date', 'Date must be in the future.')
        if end_date < today:
            self.add_error('licence_end_date', 'Date must be in the future.')
        if end_date <= start_date:
            self.add_error('licence_end_date',
                'End Date must be after Start Date.')


class LicenceDateAndPaperLicenceForm(LicenceDateForm):


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ('issue_paper_licence_only',)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['issue_paper_licence_only'].required = True
        self.fields['issue_paper_licence_only'].widget.choices = [(
            'unknown', 'Select One'), ('true', 'Yes'), ('false', 'No')]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(max_digits=9, decimal_places=2,
        min_value=0, label='Period for re-importation (months)')


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)
        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data['reimport_period']
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(queryset=Template.objects.filter(
        is_active=True, template_type=Template.ENDORSEMENT))


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',

    def clean_content(self):
        endorsement = self.cleaned_data['content']
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',


class ChecklistBaseForm(forms.ModelForm):


    class Meta:
        fields = ('case_update', 'fir_required', 'response_preparation',
            'validity_period_correct', 'endorsements_listed', 'authorisation')

    def __init__(self, *args, readonly_form: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        for field in ['response_preparation', 'authorisation']:
            self.fields[field].required = True
        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True

from typing import Any
from django import forms
from django.utils import timezone
from django_select2.forms import ModelSelect2Widget
from guardian.shortcuts import get_objects_for_user
from web.domains.template.context import CoverLetterTemplateContext
from web.domains.template.utils import find_invalid_placeholders
from web.forms.widgets import DateInput, JoditTextArea
from web.models import EndorsementImportApplication, ImportApplication, ImportApplicationLicence, Importer, Office, Template, User
from web.permissions import Perms


class CreateImportApplicationForm(forms.Form):
    importer = forms.ModelChoiceField(queryset=Importer.objects.none(),
        label='Main Importer', widget=ModelSelect2Widget(attrs={
        'data-minimum-input-length': 0, 'data-placeholder':
        '-- Select Importer'}, search_fields=('name__icontains',
        'user__first_name__icontains', 'user__last_name__icontains')))
    importer_office = forms.ModelChoiceField(queryset=Office.objects.none(),
        label='Importer Office', widget=ModelSelect2Widget(attrs={
        'data-minimum-input-length': 0, 'data-placeholder':
        '-- Select Office'}, search_fields=('postcode__icontains',
        'address_1__icontains', 'address_2__icontains',
        'address_3__icontains', 'address_4__icontains',
        'address_5__icontains', 'address_6__icontains',
        'address_7__icontains', 'address_8__icontains'), dependent_fields={
        'importer': 'importer'}))
    agent = forms.ModelChoiceField(required=False, queryset=Importer.
        objects.none(), label='Agent of Main Importer', widget=
        ModelSelect2Widget(attrs={'data-minimum-input-length': 0,
        'data-placeholder': '-- Select Agent'}, search_fields=(
        'name__icontains',), dependent_fields={'importer': 'main_importer'}))
    agent_office = forms.ModelChoiceField(required=False, queryset=Office.
        objects.none(), label='Agent Office', widget=ModelSelect2Widget(
        attrs={'data-minimum-input-length': 0, 'data-placeholder':
        '-- Select Office'}, search_fields=('postcode__icontains',
        'address_1__icontains', 'address_2__icontains',
        'address_3__icontains', 'address_4__icontains',
        'address_5__icontains', 'address_6__icontains',
        'address_7__icontains', 'address_8__icontains'), dependent_fields={
        'agent': 'importer'}))

    def __init__(self, *args: Any, user: User, **kwargs: Any) ->None:
        super().__init__(*args, **kwargs)
        self.user = user
        importers = get_objects_for_user(user, [Perms.obj.importer.edit,
            Perms.obj.importer.is_agent], Importer.objects.filter(is_active
            =True, main_importer__isnull=True), any_perm=True)
        self.fields['importer'].queryset = importers
        self.fields['importer_office'].queryset = Office.objects.filter(
            is_active=True, importer__in=importers)
        active_agents = Importer.objects.filter(is_active=True,
            main_importer__in=importers)
        agents = get_objects_for_user(user, [Perms.obj.importer.edit],
            active_agents)
        self.fields['agent'].queryset = agents
        self.fields['agent_office'].queryset = Office.objects.filter(is_active
            =True, importer__in=agents)

    def clean(self) ->dict[str, Any]:
        cleaned_data = super().clean()
        importer = cleaned_data.get('importer')
        if not importer:
            return cleaned_data
        is_agent = self.user.has_perm(Perms.obj.importer.is_agent, importer)
        if is_agent:
            if not cleaned_data.get('agent'):
                self.add_error('agent', 'You must enter this item')
            if not cleaned_data.get('agent_office'):
                self.add_error('agent_office', 'You must enter this item')
        return cleaned_data


class CreateWoodQuotaApplicationForm(CreateImportApplicationForm):
    """Create wood quota application form - Defines extra validation logic"""

    def clean(self) ->dict[str, Any]:
        cleaned_data = super().clean()
        if not self.has_error('importer_office'):
            office: Office = cleaned_data['importer_office']
            postcode: str | None = office.postcode
            if not postcode or not postcode.upper().startswith('BT'):
                self.add_error('importer_office',
                    'Wood applications can only be made for Northern Ireland traders.'
                    )
        return cleaned_data


class CoverLetterForm(forms.ModelForm):


    class Meta:
        model = ImportApplication
        fields = 'cover_letter_text',
        widgets = {'cover_letter_text': JoditTextArea(attrs={'lang': 'html'})}

    def __init__(self, *args, readonly: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['cover_letter_text'].widget.attrs['readonly'] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data['cover_letter_text']
        invalid_placeholders = find_invalid_placeholders(cover_letter_text,
            CoverLetterTemplateContext.valid_placeholders)
        if invalid_placeholders:
            self.add_error('cover_letter_text',
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}"
                )
        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(required=True, label=
        'Licence Start Date', widget=DateInput)
    licence_end_date = forms.DateField(required=True, label=
        'Licence End Date', widget=DateInput)


    class Meta:
        model = ImportApplicationLicence
        fields = 'licence_start_date', 'licence_end_date'

    def clean(self):
        data = super().clean()
        start_date = data.get('licence_start_date')
        end_date = data.get('licence_end_date')
        if not start_date or not end_date:
            return
        today = timezone.now().date()
        if start_date < today:
            self.add_error('licence_start_date', 'Date must be in the future.')
        if end_date < today:
            self.add_error('licence_end_date', 'Date must be in the future.')
        if end_date <= start_date:
            self.add_error('licence_end_date',
                'End Date must be after Start Date.')


class LicenceDateAndPaperLicenceForm(LicenceDateForm):


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ('issue_paper_licence_only',)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['issue_paper_licence_only'].required = True
        self.fields['issue_paper_licence_only'].widget.choices = [(
            'unknown', 'Select One'), ('true', 'Yes'), ('false', 'No')]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(max_digits=9, decimal_places=2,
        min_value=0, label='Period for re-importation (months)')


    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)
        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data['reimport_period']
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(queryset=Template.objects.filter(
        is_active=True, template_type=Template.ENDORSEMENT))


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',

    def clean_content(self):
        endorsement = self.cleaned_data['content']
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):


    class Meta:
        model = EndorsementImportApplication
        fields = 'content',


class ChecklistBaseForm(forms.ModelForm):


    class Meta:
        fields = ('case_update', 'fir_required', 'response_preparation',
            'validity_period_correct', 'endorsements_listed', 'authorisation')

    def __init__(self, *args, readonly_form: bool=False, **kwargs):
        super().__init__(*args, **kwargs)
        for field in ['response_preparation', 'authorisation']:
            self.fields[field].required = True
        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True

from typing import Any

from django import forms
from django.utils import timezone
from django_select2.forms import ModelSelect2Widget
from guardian.shortcuts import get_objects_for_user

from web.domains.template.context import CoverLetterTemplateContext
from web.domains.template.utils import find_invalid_placeholders
from web.forms.widgets import DateInput, JoditTextArea
from web.models import (
    EndorsementImportApplication,
    ImportApplication,
    ImportApplicationLicence,
    Importer,
    Office,
    Template,
    User,
)
from web.permissions import Perms


class CreateImportApplicationForm(forms.Form):
    importer = forms.ModelChoiceField(
        queryset=Importer.objects.none(),
        label="Main Importer",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Importer",
            },
            search_fields=(
                "name__icontains",
                "user__first_name__icontains",
                "user__last_name__icontains",
            ),
        ),
    )
    importer_office = forms.ModelChoiceField(
        queryset=Office.objects.none(),
        label="Importer Office",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Office",
            },
            search_fields=(
                "postcode__icontains",
                "address_1__icontains",
                "address_2__icontains",
                "address_3__icontains",
                "address_4__icontains",
                "address_5__icontains",
                "address_6__icontains",
                "address_7__icontains",
                "address_8__icontains",
            ),
            dependent_fields={"importer": "importer"},
        ),
    )

    agent = forms.ModelChoiceField(
        required=False,
        queryset=Importer.objects.none(),
        label="Agent of Main Importer",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Agent",
            },
            search_fields=("name__icontains",),
            # Key is a name of a field in a form.
            # Value is a name of a field in a model (used in `queryset`).
            dependent_fields={"importer": "main_importer"},
        ),
    )
    agent_office = forms.ModelChoiceField(
        required=False,
        queryset=Office.objects.none(),
        label="Agent Office",
        widget=ModelSelect2Widget(
            attrs={
                "data-minimum-input-length": 0,
                "data-placeholder": "-- Select Office",
            },
            search_fields=(
                "postcode__icontains",
                "address_1__icontains",
                "address_2__icontains",
                "address_3__icontains",
                "address_4__icontains",
                "address_5__icontains",
                "address_6__icontains",
                "address_7__icontains",
                "address_8__icontains",
            ),
            # Key is a name of a field in a form.
            # Value is a name of a field in a model (used in `queryset`).
            dependent_fields={"agent": "importer"},
        ),
    )

    def __init__(self, *args: Any, user: User, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)

        self.user = user

        # Return main importers the user can edit or is an agent of.
        importers = get_objects_for_user(
            user,
            [Perms.obj.importer.edit, Perms.obj.importer.is_agent],
            Importer.objects.filter(is_active=True, main_importer__isnull=True),
            any_perm=True,
        )
        self.fields["importer"].queryset = importers
        self.fields["importer_office"].queryset = Office.objects.filter(
            is_active=True, importer__in=importers
        )

        # Return agents linked to importers the user can edit (if any)
        active_agents = Importer.objects.filter(is_active=True, main_importer__in=importers)
        agents = get_objects_for_user(user, [Perms.obj.importer.edit], active_agents)

        self.fields["agent"].queryset = agents
        self.fields["agent_office"].queryset = Office.objects.filter(
            is_active=True, importer__in=agents
        )

    def clean(self) -> dict[str, Any]:
        cleaned_data = super().clean()

        importer = cleaned_data.get("importer")
        # if importer is not set agent and agent_office are not displayed.
        if not importer:
            return cleaned_data

        is_agent = self.user.has_perm(Perms.obj.importer.is_agent, importer)

        if is_agent:
            if not cleaned_data.get("agent"):
                self.add_error("agent", "You must enter this item")

            if not cleaned_data.get("agent_office"):
                self.add_error("agent_office", "You must enter this item")

        return cleaned_data


class CreateWoodQuotaApplicationForm(CreateImportApplicationForm):
    """Create wood quota application form - Defines extra validation logic"""

    def clean(self) -> dict[str, Any]:
        cleaned_data = super().clean()

        if not self.has_error("importer_office"):
            office: Office = cleaned_data["importer_office"]
            postcode: str | None = office.postcode

            if not postcode or (not postcode.upper().startswith("BT")):
                self.add_error(
                    "importer_office",
                    "Wood applications can only be made for Northern Ireland traders.",
                )

        return cleaned_data


class CoverLetterForm(forms.ModelForm):
    class Meta:
        model = ImportApplication
        fields = ("cover_letter_text",)
        widgets = {"cover_letter_text": JoditTextArea(attrs={"lang": "html"})}

    def __init__(self, *args, readonly: bool = False, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["cover_letter_text"].widget.attrs["readonly"] = readonly

    def clean_cover_letter_text(self):
        cover_letter_text = self.cleaned_data["cover_letter_text"]
        invalid_placeholders = find_invalid_placeholders(
            cover_letter_text, CoverLetterTemplateContext.valid_placeholders
        )
        if invalid_placeholders:
            self.add_error(
                "cover_letter_text",
                f"The following placeholders are invalid: {', '.join(invalid_placeholders)}",
            )

        return cover_letter_text


class LicenceDateForm(forms.ModelForm):
    licence_start_date = forms.DateField(
        required=True, label="Licence Start Date", widget=DateInput
    )
    licence_end_date = forms.DateField(required=True, label="Licence End Date", widget=DateInput)

    class Meta:
        model = ImportApplicationLicence
        fields = ("licence_start_date", "licence_end_date")

    def clean(self):
        data = super().clean()
        start_date = data.get("licence_start_date")
        end_date = data.get("licence_end_date")

        if not start_date or not end_date:
            return

        today = timezone.now().date()

        if start_date < today:
            self.add_error("licence_start_date", "Date must be in the future.")

        if end_date < today:
            self.add_error("licence_end_date", "Date must be in the future.")

        if end_date <= start_date:
            self.add_error("licence_end_date", "End Date must be after Start Date.")


class LicenceDateAndPaperLicenceForm(LicenceDateForm):
    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields + ("issue_paper_licence_only",)

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

        # The default label for unknown is "Unknown"
        self.fields["issue_paper_licence_only"].required = True
        self.fields["issue_paper_licence_only"].widget.choices = [
            ("unknown", "Select One"),
            ("true", "Yes"),
            ("false", "No"),
        ]


class OPTLicenceForm(LicenceDateForm):
    reimport_period = forms.DecimalField(
        max_digits=9, decimal_places=2, min_value=0, label="Period for re-importation (months)"
    )

    class Meta:
        model = ImportApplicationLicence
        fields = LicenceDateForm.Meta.fields

    def save(self, commit=True):
        super().save(commit)

        opt_app = self.instance.import_application.get_specific_model()
        opt_app.reimport_period = self.cleaned_data["reimport_period"]
        opt_app.save()


class EndorsementChoiceImportApplicationForm(forms.ModelForm):
    content = forms.ModelChoiceField(
        queryset=Template.objects.filter(is_active=True, template_type=Template.ENDORSEMENT)
    )

    class Meta:
        model = EndorsementImportApplication
        fields = ("content",)

    def clean_content(self):
        endorsement = self.cleaned_data["content"]
        return endorsement.template_content


class EndorsementImportApplicationForm(forms.ModelForm):
    class Meta:
        model = EndorsementImportApplication
        fields = ("content",)


class ChecklistBaseForm(forms.ModelForm):
    class Meta:
        fields = (
            "case_update",
            "fir_required",
            "response_preparation",
            "validity_period_correct",
            "endorsements_listed",
            "authorisation",
        )

    def __init__(self, *args, readonly_form: bool = False, **kwargs):
        super().__init__(*args, **kwargs)

        # Change checklist fields to required (e.g. only selected is valid)
        for field in ["response_preparation", "authorisation"]:
            self.fields[field].required = True

        if readonly_form:
            for f in self.fields:
                self.fields[f].disabled = True
