from django import forms
from django.contrib.auth import get_user_model
from django.forms import inlineformset_factory

from apps.core.authentication.models import Institution
from apps.core.money import DEFAULT_CURRENCY, ISO4217_CHOICES
from apps.rims.grants.models import Award
from apps.rims.operations.models import Partner
from apps.rims.scholarships.models import (
    ConferencePaper,
    Manuscript,
    Presentation,
    ProgressReport,
    Scholar,
    Scholarship,
    SkillsImprovement,
    Stipend,
    SupervisorFeedback,
)

User = get_user_model()


class ScholarshipForm(forms.ModelForm):
    class Meta:
        model = Scholarship
        fields = ["name", "programme_type", "description", "grant_call", "partner", "is_active"]
        widgets = {
            "description": forms.Textarea(attrs={"rows": 4}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["grant_call"].required = False
        self.fields["partner"].queryset = Partner.objects.order_by("name")
        self.fields["partner"].required = False


class ScholarEditForm(forms.ModelForm):
    class Meta:
        model = Scholar
        fields = [
            "scholarship", "institution", "cohort_year", "photo", "notes", "award",
            "degree_level", "degree_name", "thesis_title", "research_abstract",
            "supervisor_1", "supervisor_2", "supervisor_3",
            "university_reg_no", "student_number", "host_university_address",
            "student_type", "intake_year", "expected_graduation",
        ]
        widgets = {
            "notes": forms.Textarea(attrs={"rows": 3}),
            "research_abstract": forms.Textarea(attrs={"rows": 4}),
            "host_university_address": forms.Textarea(attrs={"rows": 2}),
            "expected_graduation": forms.DateInput(attrs={"type": "date"}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["institution"].queryset = Institution.objects.filter(is_active=True).order_by("name")
        self.fields["institution"].required = False
        self.fields["award"].required = False
        inst = kwargs.get("instance")
        if inst and inst.pk:
            self.fields["award"].queryset = Award.objects.filter(
                application__applicant=inst.user
            ).select_related("application__call")
        else:
            self.fields["award"].queryset = Award.objects.none()

    def clean(self):
        cleaned = super().clean()
        award = cleaned.get("award")
        inst = getattr(self, "instance", None)
        if award and inst and inst.pk and inst.user_id:
            if award.application.applicant_id != inst.user_id:
                raise forms.ValidationError({"award": "Award applicant must match this scholar's user."})
        return cleaned


class ScholarEnrolForm(forms.ModelForm):
    user_email = forms.EmailField(
        label="Scholar email",
        help_text="Must be an existing user account.",
    )

    class Meta:
        model = Scholar
        fields = [
            "scholarship", "institution", "cohort_year", "photo", "notes", "award",
            "degree_level", "degree_name", "thesis_title",
            "student_type", "intake_year",
        ]
        widgets = {
            "notes": forms.Textarea(attrs={"rows": 3}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["institution"].queryset = Institution.objects.filter(is_active=True).order_by("name")
        self.fields["institution"].required = False
        self.fields["award"].required = False
        self.fields["award"].queryset = Award.objects.select_related(
            "application__call", "application__applicant"
        ).order_by("-awarded_at")

    def clean_award(self):
        award = self.cleaned_data.get("award")
        if not award:
            return award
        email = (self.data.get("user_email") or "").strip()
        if not email:
            raise forms.ValidationError("Enter scholar email before linking an award.")
        user = User.objects.filter(email__iexact=email).first()
        if user and award.application.applicant_id != user.pk:
            raise forms.ValidationError("Award must belong to the same user as scholar email.")
        return award

    def clean_user_email(self):
        email = self.cleaned_data["user_email"]
        try:
            self._resolved_user = User.objects.get(email=email)
        except User.DoesNotExist:
            raise forms.ValidationError("No account found with this email address.")
        return email

    def save(self, commit=True):
        obj = super().save(commit=False)
        obj.user = self._resolved_user
        if commit:
            obj.save()
        return obj


class ScholarAcademicProfileForm(forms.ModelForm):
    """Self-service form for scholars to update their own academic profile."""

    class Meta:
        model = Scholar
        fields = [
            "degree_level", "degree_name", "thesis_title", "research_abstract",
            "supervisor_1", "supervisor_2", "supervisor_3",
            "university_reg_no", "student_number", "host_university_address",
            "intake_year", "expected_graduation",
        ]
        widgets = {
            "research_abstract": forms.Textarea(attrs={"rows": 5}),
            "host_university_address": forms.Textarea(attrs={"rows": 2}),
            "expected_graduation": forms.DateInput(attrs={"type": "date"}),
        }


class ScholarStatusUpdateForm(forms.Form):
    """Self-service form for a scholar to update their own study status."""

    SELF_SERVICE_STATUSES = [
        (Scholar.Status.ACTIVE,   "Resume / Mark as Active"),
        (Scholar.Status.PAUSED,   "Pause studies"),
        (Scholar.Status.DEFERRED, "Defer to next cohort"),
    ]

    to_status = forms.ChoiceField(choices=SELF_SERVICE_STATUSES, label="New status")
    reason = forms.CharField(
        widget=forms.Textarea(attrs={"rows": 3}),
        required=False,
        label="Reason",
        help_text="Required when pausing or deferring.",
    )

    def clean(self):
        cleaned = super().clean()
        status = cleaned.get("to_status")
        reason = (cleaned.get("reason") or "").strip()
        if status in (Scholar.Status.PAUSED, Scholar.Status.DEFERRED) and not reason:
            raise forms.ValidationError(
                {"reason": "Please provide a reason for pausing or deferring your studies."}
            )
        return cleaned


class ProgressReportForm(forms.ModelForm):
    """Scholar self-service structured progress report."""

    class Meta:
        model = ProgressReport
        fields = [
            "period_label", "semester", "year",
            "title_of_research", "activities_executed", "research_timeframe",
            "technology_championed", "farming_community_type",
            "farmers_or_organisation_count", "none_farmer_actors",
            "location", "critical_issues", "skills_required",
            "additional_information", "areas_university_needs_improvement",
            "file", "notes",
        ]
        widgets = {
            "period_label": forms.TextInput(attrs={"placeholder": "e.g. Semester 1 2026"}),
            "activities_executed": forms.Textarea(attrs={"rows": 4}),
            "research_timeframe": forms.Textarea(attrs={"rows": 2}),
            "technology_championed": forms.Textarea(attrs={"rows": 3}),
            "farming_community_type": forms.Textarea(attrs={"rows": 2}),
            "none_farmer_actors": forms.Textarea(attrs={"rows": 2}),
            "location": forms.Textarea(attrs={"rows": 2}),
            "critical_issues": forms.Textarea(attrs={"rows": 3}),
            "skills_required": forms.Textarea(attrs={"rows": 3}),
            "additional_information": forms.Textarea(attrs={"rows": 3}),
            "areas_university_needs_improvement": forms.Textarea(attrs={"rows": 3}),
            "notes": forms.Textarea(attrs={"rows": 3}),
        }


SupervisorFeedbackFormSet = inlineformset_factory(
    ProgressReport, SupervisorFeedback,
    fields=["name", "title", "area_of_mentorship", "areas_of_achievement", "areas_requiring_attention"],
    widgets={
        "areas_of_achievement": forms.Textarea(attrs={"rows": 2}),
        "areas_requiring_attention": forms.Textarea(attrs={"rows": 2}),
    },
    extra=1, can_delete=True,
)

SkillsImprovementFormSet = inlineformset_factory(
    ProgressReport, SkillsImprovement,
    fields=["skill", "description"],
    widgets={"description": forms.Textarea(attrs={"rows": 2})},
    extra=1, can_delete=True,
)

ManuscriptFormSet = inlineformset_factory(
    ProgressReport, Manuscript,
    fields=["title", "file", "notes"],
    widgets={"notes": forms.Textarea(attrs={"rows": 1})},
    extra=1, can_delete=True,
)

ConferencePaperFormSet = inlineformset_factory(
    ProgressReport, ConferencePaper,
    fields=["title", "file", "notes"],
    widgets={"notes": forms.Textarea(attrs={"rows": 1})},
    extra=1, can_delete=True,
)

PresentationFormSet = inlineformset_factory(
    ProgressReport, Presentation,
    fields=["title", "file", "notes"],
    widgets={"notes": forms.Textarea(attrs={"rows": 1})},
    extra=1, can_delete=True,
)


class StipendForm(forms.ModelForm):
    class Meta:
        model = Stipend
        fields = ["scholar", "amount", "currency", "paid_on", "reference"]
        widgets = {
            "paid_on": forms.DateInput(attrs={"type": "date"}),
            "reference": forms.TextInput(attrs={"placeholder": "Bank reference, mobile money ID, etc."}),
        }

    def __init__(self, *args, **kwargs):
        scholar = kwargs.pop("scholar", None)
        super().__init__(*args, **kwargs)
        self.fields["scholar"].queryset = Scholar.objects.select_related(
            "user", "scholarship"
        ).order_by("user__email")
        if scholar is not None:
            self.fields["scholar"].initial = scholar
            self.fields["scholar"].queryset = Scholar.objects.filter(pk=scholar.pk)
        self.fields["currency"].initial = DEFAULT_CURRENCY
        self.fields["currency"].choices = ISO4217_CHOICES

    def clean_amount(self):
        amount = self.cleaned_data.get("amount")
        if amount is not None and amount <= 0:
            raise forms.ValidationError("Stipend amount must be greater than zero.")
        return amount

    def clean(self):
        cleaned = super().clean()
        scholar = cleaned.get("scholar")
        if scholar is not None and scholar.status == Scholar.Status.WITHDRAWN:
            raise forms.ValidationError(
                "This scholar has been withdrawn — stipends cannot be recorded."
            )
        return cleaned


class GraduationSubmitForm(forms.Form):
    """Scholar self-service graduation submission — triggers GraduationRecord creation."""

    graduated_on = forms.DateField(
        label="Graduation date",
        widget=forms.DateInput(attrs={"type": "date"}),
    )
    certificate_file = forms.FileField(
        label="Upload graduation certificate",
        required=False,
        help_text="PDF or image of your official certificate.",
    )
    notes = forms.CharField(
        widget=forms.Textarea(attrs={"rows": 3}),
        required=False,
        label="Notes",
    )
