from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.forms import ModelForm
from django.utils.translation import gettext_lazy as _

from servala.core.models import Organization, OrganizationInvitation, OrganizationRole
from servala.core.odoo import get_invoice_addresses, get_odoo_countries
from servala.frontend.forms.mixins import HtmxMixin

ORG_NAME_PATTERN = r"[\w\s\-.,&'()+]+"


class OrganizationForm(HtmxMixin, ModelForm):
    name_validator = RegexValidator(
        regex=f"^{ORG_NAME_PATTERN}$",
        message=_(
            "Organization name can only contain letters, numbers, spaces, and common punctuation (-.,&'()+)."
        ),
    )

    # def __init__(self, *args, **kwargs):
    # super().__init__(*args, **kwargs)
    # if self.instance and self.instance.has_inherited_billing_entity:
    # TODO disable billing entity editing
    class Meta:
        model = Organization
        fields = ("name",)
        widgets = {
            "name": forms.TextInput(
                attrs={
                    "maxlength": "100",
                    "pattern": ORG_NAME_PATTERN,
                    "title": _(
                        "Organization name can contain letters, numbers, spaces, and common punctuation (-.,&'()+). Emoji not allowed."
                    ),
                }
            ),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["name"].validators.append(self.name_validator)
        self.fields["name"].max_length = 100


class OrganizationCreateForm(OrganizationForm):
    address_validator = RegexValidator(
        regex=r"^[\w\s\.,\-/()\']+$",
        message=_(
            "This field can only contain letters, numbers, spaces, and basic punctuation (.,-/()')."
        ),
    )
    city_validator = RegexValidator(
        regex=r"^[\w\s\-\']+$",
        message=_("City name contains invalid characters."),
    )
    postal_code_validator = RegexValidator(
        regex=r"^[\w\s\-]+$",
        message=_(
            "Postal code can only contain letters, numbers, spaces, and hyphens."
        ),
    )
    phone_validator = RegexValidator(
        regex=r"^[0-9\s\+\-()]+$",
        message=_(
            "Phone number can only contain numbers, spaces, and basic punctuation (+,-,())."
        ),
    )

    billing_processing_choice = forms.ChoiceField(
        choices=[
            ("existing", _("Use an existing billing address")),
            ("new", _("Create a new billing address")),
        ],
        widget=forms.RadioSelect,
        label=_("Billing Address"),
        initial="new",  # Will change to 'existing' if options are found
    )
    existing_odoo_address_id = forms.ChoiceField(
        label=_("Existing Billing Address"),
        required=False,
    )

    # Fields for creating a new billing address in Odoo, prefixed with 'invoice_'
    invoice_street = forms.CharField(
        label=_("Line 1"),
        required=False,
        max_length=128,
        validators=[address_validator],
        widget=forms.TextInput(
            attrs={
                "maxlength": "128",
                "title": _(
                    "Letters, numbers, spaces, and basic punctuation allowed. Emoji not allowed."
                ),
            }
        ),
    )
    invoice_street2 = forms.CharField(
        label=_("Line 2"),
        required=False,
        max_length=128,
        validators=[address_validator],
        widget=forms.TextInput(
            attrs={
                "maxlength": "128",
                "title": _(
                    "Letters, numbers, spaces, and basic punctuation allowed. Emoji not allowed."
                ),
            }
        ),
    )
    invoice_city = forms.CharField(
        label=_("City"),
        required=False,
        max_length=64,
        validators=[city_validator],
        widget=forms.TextInput(
            attrs={
                "maxlength": "64",
                "title": _(
                    "Letters, spaces, hyphens, and apostrophes allowed. Emoji not allowed."
                ),
            }
        ),
    )
    invoice_zip = forms.CharField(
        label=_("Postal Code"),
        required=False,
        max_length=20,
        validators=[postal_code_validator],
        widget=forms.TextInput(
            attrs={
                "maxlength": "20",
                "title": _(
                    "Letters, numbers, spaces, and hyphens allowed. Emoji not allowed."
                ),
            }
        ),
    )
    invoice_country = forms.ChoiceField(
        label=_("Country"),
        required=False,
        choices=get_odoo_countries(),
    )
    invoice_email = forms.EmailField(
        label=_("Billing Email"),
        required=False,
        max_length=254,
        widget=forms.EmailInput(attrs={"maxlength": "254"}),
    )
    invoice_phone = forms.CharField(
        label=_("Phone"),
        required=False,
        max_length=30,
        validators=[phone_validator],
        widget=forms.TextInput(
            attrs={
                "maxlength": "30",
                "pattern": r"[0-9\s\+\-()]+",
                "title": _("Only numbers, spaces, and basic punctuation allowed"),
            }
        ),
    )

    class Meta(OrganizationForm.Meta):
        pass

    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = user
        if not self.initial.get("invoice_country"):
            default_country_name = "Switzerland"
            country_choices = self.fields["invoice_country"].choices
            for country_id, country_name_label in country_choices:
                if country_name_label == default_country_name:
                    self.initial["invoice_country"] = country_id
                    break

        self.odoo_addresses = get_invoice_addresses(self.user)

        if self.odoo_addresses:
            address_choices = [("", _("---------"))]
            for addr in self.odoo_addresses:
                parent_name = None
                parent_info = addr.get("parent_id")
                if (
                    parent_info
                    and isinstance(parent_info, (list, tuple))
                    and len(parent_info) > 1
                ):
                    parent_name = parent_info[1]

                display_parts = [
                    parent_name,
                    addr.get("name"),
                    addr.get("street"),
                    addr.get("city"),
                    addr.get("zip"),
                ]
                display_name = ", ".join([part for part in display_parts if part])
                address_choices.append((str(addr["id"]), display_name))

            self.fields["existing_odoo_address_id"].choices = address_choices
            if not self.is_bound and "billing_processing_choice" not in self.initial:
                self.fields["billing_processing_choice"].initial = "existing"
        else:
            self.fields.pop("billing_processing_choice")
            self.fields["existing_odoo_address_id"].widget = forms.HiddenInput()

    def clean(self):
        cleaned_data = super().clean()
        choice = cleaned_data.get("billing_processing_choice")
        if not choice or choice == "new":
            required_fields = [
                "invoice_street",
                "invoice_city",
                "invoice_zip",
                "invoice_country",
                "invoice_email",
            ]
            for field_name in required_fields:
                if not cleaned_data.get(field_name):
                    self.add_error(field_name, _("This field is required."))
        else:
            existing_id_str = cleaned_data.get("existing_odoo_address_id")
            if not existing_id_str:
                self.add_error(
                    "existing_odoo_address_id", _("Please select an invoice address.")
                )
        return cleaned_data


class OrganizationInvitationForm(forms.ModelForm):

    def __init__(self, *args, organization=None, user_role=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.organization = organization
        self.user_role = user_role

        if user_role:
            allowed_roles = self._get_allowed_roles(user_role)
            self.fields["role"].choices = [
                (value, label)
                for value, label in OrganizationRole.choices
                if value in allowed_roles
            ]

    def _get_allowed_roles(self, user_role):
        role_hierarchy = {
            OrganizationRole.OWNER: [
                OrganizationRole.OWNER,
                OrganizationRole.ADMIN,
                OrganizationRole.MEMBER,
            ],
            OrganizationRole.ADMIN: [
                OrganizationRole.ADMIN,
                OrganizationRole.MEMBER,
            ],
            OrganizationRole.MEMBER: [],
        }
        return role_hierarchy.get(user_role, [])

    def clean_email(self):
        email = self.cleaned_data["email"].lower()

        if self.organization.members.filter(email__iexact=email).exists():
            raise ValidationError(
                _("A user with this email is already a member of this organization.")
            )

        if OrganizationInvitation.objects.filter(
            organization=self.organization,
            email__iexact=email,
            accepted_by__isnull=True,
        ).exists():
            raise ValidationError(
                _("An invitation has already been sent to this email address.")
            )

        return email

    def save(self, commit=True):
        invitation = super().save(commit=False)
        invitation.organization = self.organization
        if commit:
            invitation.save()
        return invitation

    class Meta:
        model = OrganizationInvitation
        fields = ("email", "role")
        widgets = {
            "email": forms.EmailInput(attrs={"placeholder": _("user@example.com")}),
            "role": forms.RadioSelect(),
        }
