from django import forms
from django.core.exceptions import ValidationError

from apps.employees.models import Employee
from .models import AttendanceRecord


class AttendanceRecordForm(forms.ModelForm):
    class Meta:
        model = AttendanceRecord
        fields = ["employee", "work_date", "check_in", "check_out", "status", "remarks"]
        widgets = {
            "work_date": forms.DateInput(attrs={"type": "date"}),
            "check_in": forms.DateTimeInput(attrs={"type": "datetime-local"}, format="%Y-%m-%dT%H:%M"),
            "check_out": forms.DateTimeInput(attrs={"type": "datetime-local"}, format="%Y-%m-%dT%H:%M"),
            "remarks": forms.Textarea(attrs={"rows": 2}),
        }

    def __init__(self, *args, **kwargs):
        employee_queryset = kwargs.pop("employee_queryset", None)
        super().__init__(*args, **kwargs)
        self.fields["check_in"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M:%S"]
        self.fields["check_out"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M:%S"]
        if employee_queryset is not None:
            self.fields["employee"].queryset = employee_queryset

    def clean(self):
        cleaned = super().clean()
        employee = cleaned.get("employee")
        work_date = cleaned.get("work_date")
        if employee and work_date:
            from .services import employee_in_service_on
            if not employee_in_service_on(employee, work_date):
                self.add_error("work_date", "Attendance date must fall within the employee service period.")
        check_in = cleaned.get("check_in")
        check_out = cleaned.get("check_out")
        status = cleaned.get("status")
        if check_in and check_out and check_out <= check_in:
            raise ValidationError("Check-out must be later than check-in.")
        no_punch_statuses = {
            AttendanceRecord.Status.ABSENT, AttendanceRecord.Status.LEAVE,
            AttendanceRecord.Status.HOLIDAY, AttendanceRecord.Status.WEEKLY_OFF,
        }
        if status in no_punch_statuses and (check_in or check_out):
            raise ValidationError("Absent/Leave/Holiday/Weekly Off records cannot contain check-in or check-out timestamps.")
        if check_out and not check_in:
            raise ValidationError("Check-in is required when check-out is entered.")
        if status in {AttendanceRecord.Status.PRESENT, AttendanceRecord.Status.LATE} and not check_in:
            raise ValidationError("Present/Late attendance requires a check-in timestamp.")
        return cleaned


class AttendanceAdjustmentForm(forms.Form):
    new_check_in = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(attrs={"type": "datetime-local"}),
        input_formats=["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M:%S"],
    )
    new_check_out = forms.DateTimeField(
        required=False,
        widget=forms.DateTimeInput(attrs={"type": "datetime-local"}),
        input_formats=["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M:%S"],
    )
    new_status = forms.ChoiceField(choices=AttendanceRecord.Status.choices)
    reason = forms.CharField(widget=forms.Textarea(attrs={"rows": 3}))

    def clean(self):
        cleaned = super().clean()
        check_in = cleaned.get("new_check_in")
        check_out = cleaned.get("new_check_out")
        status = cleaned.get("new_status")
        if check_in and check_out and check_out <= check_in:
            raise ValidationError("Corrected check-out must be later than corrected check-in.")
        no_punch_statuses = {
            AttendanceRecord.Status.ABSENT, AttendanceRecord.Status.LEAVE,
            AttendanceRecord.Status.HOLIDAY, AttendanceRecord.Status.WEEKLY_OFF,
        }
        if status in no_punch_statuses and (check_in or check_out):
            raise ValidationError("Absent/Leave/Holiday/Weekly Off corrections cannot contain punch timestamps.")
        if check_out and not check_in:
            raise ValidationError("Corrected check-in is required when corrected check-out is entered.")
        if status in {AttendanceRecord.Status.PRESENT, AttendanceRecord.Status.LATE} and not check_in:
            raise ValidationError("Present/Late correction requires a check-in timestamp.")
        return cleaned

from .models import AttendanceDevice, DeviceEmployeeMap


class AttendanceDeviceForm(forms.ModelForm):
    def __init__(self, *args, company_queryset=None, **kwargs):
        super().__init__(*args, **kwargs)
        if company_queryset is not None:
            self.fields["company"].queryset = company_queryset
        if getattr(self.instance, "pk", None):
            self.fields["company"].disabled = True
            self.fields["company"].help_text = "Attendance-device company cannot be changed after creation."
            company_id = self.instance.company_id
        else:
            company_id = self.data.get("company") if self.is_bound else None
        if company_id:
            self.fields["branch"].queryset = self.fields["branch"].queryset.filter(company_id=company_id, is_active=True)
        else:
            self.fields["branch"].queryset = self.fields["branch"].queryset.none()

    class Meta:
        model = AttendanceDevice
        fields = [
            "company", "branch", "name", "vendor", "model", "serial_number",
            "connection_mode", "ip_address", "port", "comm_key", "adms_url", "is_active",
        ]

    def clean(self):
        cleaned = super().clean()
        company = cleaned.get("company")
        branch = cleaned.get("branch")
        if company and branch and branch.company_id != company.id:
            self.add_error("branch", "Selected branch does not belong to the selected company.")
        return cleaned


class DeviceEmployeeMapForm(forms.ModelForm):
    class Meta:
        model = DeviceEmployeeMap
        fields = ["employee", "device_user_id", "is_active"]

    def __init__(self, *args, device=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.device = device
        if device is not None:
            self.fields["employee"].queryset = Employee.objects.filter(company=device.company).order_by("employee_code")

    def clean_device_user_id(self):
        value = (self.cleaned_data.get("device_user_id") or "").strip()
        if not value:
            raise ValidationError("Machine/User ID is required.")
        if self.device and DeviceEmployeeMap.objects.filter(device=self.device, device_user_id=value).exclude(pk=self.instance.pk).exists():
            raise ValidationError("This Machine/User ID is already mapped on the device.")
        return value


class PunchCSVImportForm(forms.Form):
    csv_file = forms.FileField(help_text="CSV columns: device_user_id,punch_time,punch_type. UTF-8 recommended.")


class AttendancePeriodForm(forms.Form):
    company = forms.ModelChoiceField(queryset=None)
    year = forms.IntegerField(min_value=2020, max_value=2100)
    month = forms.IntegerField(min_value=1, max_value=12)

    def __init__(self, *args, company_queryset=None, **kwargs):
        super().__init__(*args, **kwargs)
        from apps.organization.models import Company
        self.fields["company"].queryset = company_queryset if company_queryset is not None else Company.objects.none()


class AttendancePeriodReopenForm(forms.Form):
    reason = forms.CharField(widget=forms.Textarea(attrs={"rows": 3}), min_length=5)
