from datetime import timedelta

from allianceauth.services.hooks import get_extension_logger
from django import forms
from django.forms import ModelForm
from django.forms.widgets import TextInput

from opcalendar.models import (
    Event,
    EventCategory,
    EventHost,
    EventMember,
    EventVisibility,
    UserSettings,
)

logger = get_extension_logger(__name__)


class EventForm(ModelForm):
    end_time_mode = forms.ChoiceField(
        choices=[("duration", "Duration"), ("custom", "Set end time")],
        widget=forms.RadioSelect,
        initial="duration",
        required=False,
        label="End time",
    )
    duration = forms.IntegerField(
        required=False,
        min_value=1,
        label="Duration (hours)",
        widget=forms.NumberInput(attrs={"placeholder": "e.g. 2"}),
    )
    enable_repeat = forms.BooleanField(
        required=False,
        label="Repeat event",
    )
    notification_timings = forms.MultipleChoiceField(
        choices=Event.NOTIFICATION_TIMING_CHOICES,
        widget=forms.CheckboxSelectMultiple,
        required=False,
        initial=[Event.NOTIFY_NOW],
        label="Discord ping timing",
        help_text=(
            "When should this event be pinged on Discord? "
            "Select 'Custom date and time' to also set a specific date below."
        ),
    )

    field_order = [
        "operation_type",
        "title",
        "host",
        "event_visibility",
        "doctrine",
        "formup_system",
        "fc",
        "description",
        "start_time",
        "end_time_mode",
        "duration",
        "end_time",
        "important",
        "enable_repeat",
        "repeat_event",
        "repeat_interval",
        "repeat_times",
        "notification_timings",
        "notification_custom_date",
    ]

    class Meta:
        model = Event
        # datetime-local is a HTML5 input type, format to make date time show on fields
        exclude = [
            "user",
            "eve_character",
            "created_date",
            "external",
            "notifications_sent",
        ]

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

        super(EventForm, self).__init__(*args, **kwargs)

        self.fields["start_time"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["end_time"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["end_time"].required = False
        self.fields["repeat_event"].required = False
        self.fields["repeat_times"].required = False
        self.fields["notification_custom_date"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["host"].queryset = EventHost.objects.filter(external=False)
        self.fields["event_visibility"].required = True
        self.fields["event_visibility"].queryset = EventVisibility.objects.filter(
            is_visible=True, is_active=True
        )
        try:
            self.initial["event_visibility"] = EventVisibility.objects.get(
                is_default=True
            )
        except Exception:
            logger.debug("Form defaults: No default visibility set")

        try:
            self.initial["host"] = EventHost.objects.get(is_default=True)
        except Exception:
            logger.debug("Form defaults: No default host set")

    def clean(self):
        cleaned_data = super().clean()
        end_time_mode = cleaned_data.get("end_time_mode")
        start_time = cleaned_data.get("start_time")

        if end_time_mode == "duration":
            duration = cleaned_data.get("duration")
            if not duration:
                self.add_error("duration", "Please select a duration.")
            elif start_time:
                cleaned_data["end_time"] = start_time + timedelta(hours=int(duration))
        else:
            if not cleaned_data.get("end_time"):
                self.add_error("end_time", "End time is required.")

        if not cleaned_data.get("enable_repeat"):
            cleaned_data["repeat_event"] = ""
            cleaned_data["repeat_times"] = 0

        # Clear notification_custom_date if custom timing not selected
        timings = cleaned_data.get("notification_timings") or []
        if Event.NOTIFY_CUSTOM not in timings:
            cleaned_data["notification_custom_date"] = None
            if "notification_custom_date" in self.errors:
                del self.errors["notification_custom_date"]

        return cleaned_data


class EventEditForm(ModelForm):
    end_time_mode = forms.ChoiceField(
        choices=[("duration", "Duration"), ("custom", "Set end time")],
        widget=forms.RadioSelect,
        initial="custom",
        required=False,
        label="End time",
    )
    duration = forms.IntegerField(
        required=False,
        min_value=1,
        label="Duration (hours)",
        widget=forms.NumberInput(attrs={"placeholder": "e.g. 2"}),
    )
    enable_repeat = forms.BooleanField(
        required=False,
        label="Repeat event",
    )
    notification_timings = forms.MultipleChoiceField(
        choices=Event.NOTIFICATION_TIMING_CHOICES,
        widget=forms.CheckboxSelectMultiple,
        required=False,
        label="Discord ping timing",
        help_text=(
            "When should this event be pinged on Discord? "
            "Select 'Custom date and time' to also set a specific date below."
        ),
    )

    field_order = [
        "operation_type",
        "title",
        "host",
        "event_visibility",
        "doctrine",
        "formup_system",
        "fc",
        "description",
        "start_time",
        "end_time_mode",
        "duration",
        "end_time",
        "important",
        "enable_repeat",
        "repeat_event",
        "repeat_interval",
        "repeat_times",
        "notification_timings",
        "notification_custom_date",
    ]

    class Meta:
        model = Event
        exclude = [
            "user",
            "eve_character",
            "created_date",
            "external",
            "notifications_sent",
        ]

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

        self.fields["start_time"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["end_time"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["end_time"].required = False
        self.fields["repeat_event"].required = False
        self.fields["repeat_interval"].required = False
        self.fields["repeat_times"].required = False
        self.fields["notification_custom_date"].input_formats = ("%Y-%m-%dT%H:%M",)
        self.fields["host"].queryset = EventHost.objects.filter(external=False)
        self.fields["event_visibility"].required = True
        self.fields["event_visibility"].queryset = EventVisibility.objects.filter(
            is_visible=True, is_active=True
        )

        # Pre-populate non-model fields from the existing instance
        if self.instance and self.instance.pk:
            if self.instance.repeat_event:
                self.initial["enable_repeat"] = True
            self.initial["end_time_mode"] = "custom"

    def clean(self):
        cleaned_data = super().clean()

        # End time: duration or custom
        end_time_mode = cleaned_data.get("end_time_mode")
        start_time = cleaned_data.get("start_time")

        if end_time_mode == "duration":
            duration = cleaned_data.get("duration")
            if not duration:
                self.add_error("duration", "Please select a duration.")
            elif start_time:
                cleaned_data["end_time"] = start_time + timedelta(hours=int(duration))
        else:
            if not cleaned_data.get("end_time"):
                self.add_error("end_time", "End time is required.")

        # Repeat
        if not cleaned_data.get("enable_repeat"):
            cleaned_data["repeat_event"] = ""
            cleaned_data["repeat_times"] = 0

        # Notification custom date
        timings = cleaned_data.get("notification_timings") or []
        if (
            Event.NOTIFY_CUSTOM not in timings
            and "notification_custom_date" in self.errors
        ):
            del self.errors["notification_custom_date"]
            cleaned_data["notification_custom_date"] = None

        return cleaned_data


class SignupForm(forms.Form):
    username = forms.CharField(
        widget=forms.TextInput(
            attrs={"class": "form-control", "placeholder": "Username"}
        )
    )
    password = forms.CharField(
        widget=forms.PasswordInput(
            attrs={"class": "form-control", "placeholder": "Password"}
        )
    )


class AddMemberForm(forms.ModelForm):
    class Meta:
        model = EventMember
        fields = ["character", "status", "comment"]
        widgets = {
            "comment": forms.TextInput(
                attrs={
                    "class": "form-control",
                    "maxlength": 100,
                    "placeholder": "Optional comment",
                }
            ),
        }


class AddCategoryForm(forms.ModelForm):
    class Meta:
        model = EventCategory
        fields = "__all__"


class EventVisibilityAdminForm(forms.ModelForm):
    class Meta:
        model = EventVisibility
        fields = "__all__"
        widgets = {
            "color": TextInput(attrs={"type": "color"}),
        }


class EventCategoryAdminForm(forms.ModelForm):
    class Meta:
        model = EventCategory
        fields = "__all__"
        widgets = {
            "color": TextInput(attrs={"type": "color"}),
        }


class UserSettingsForm(forms.ModelForm):
    class Meta:
        model = UserSettings
        fields = ["disable_discord_notifications", "use_local_times"]
        labels = {
            "disable_discord_notifications": "Disable all direct discord notifications",
            "use_local_times": "Show all events in local time instead of EVE time",
        }
