from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone

from apps.accounts.permissions import (
    ROLE_HR_ADMIN, ROLE_SUPER_ADMIN, accessible_company_ids, require_roles, scope_queryset_by_company,
)
from apps.audit.services import log_event
from .forms import BranchForm, CompanyForm, CompanyPolicyForm, DepartmentForm, DesignationForm, HolidayForm, ShiftForm, MasterLifecycleForm
from .models import Branch, Company, CompanyPolicy, Department, Designation, Holiday, Shift


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def policy_list(request):
    policies = scope_queryset_by_company(request.user, CompanyPolicy.objects.select_related("company"), "company")
    return render(request, "organization/policy_list.html", {"policies": policies.order_by("company__name", "-effective_from")})


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def policy_create(request):
    form = CompanyPolicyForm(request.POST or None)
    form.fields["company"].queryset = Company.objects.filter(pk__in=accessible_company_ids(request.user), is_active=True)
    if request.method == "POST" and form.is_valid():
        policy = form.save()
        log_event(user=request.user, action="CREATE_POLICY", module="organization", object_id=policy.pk, object_repr=str(policy), new_values={
            "effective_from": str(policy.effective_from), "salary_day_divisor": str(policy.salary_day_divisor),
            "monthly_working_hours": str(policy.monthly_working_hours), "proration": policy.salary_proration_method,
        })
        messages.success(request, "Company policy saved. Historical policies remain unchanged.")
        return redirect("organization:policy-list")
    return render(request, "organization/policy_form.html", {"form": form, "title": "Add Company Policy"})


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def policy_edit(request, pk):
    policy = get_object_or_404(scope_queryset_by_company(request.user, CompanyPolicy.objects.all(), "company"), pk=pk)
    if policy.effective_from <= timezone.localdate():
        messages.error(
            request,
            "An effective/current policy version is immutable. Add a new policy version with a new Effective From date instead."
        )
        return redirect("organization:policy-list")
    form = CompanyPolicyForm(request.POST or None, instance=policy)
    form.fields["company"].queryset = Company.objects.filter(pk__in=accessible_company_ids(request.user), is_active=True)
    if request.method == "POST" and form.is_valid():
        policy = form.save()
        log_event(user=request.user, action="UPDATE_POLICY", module="organization", object_id=policy.pk, object_repr=str(policy), new_values={
            "effective_from": str(policy.effective_from), "salary_day_divisor": str(policy.salary_day_divisor),
            "monthly_working_hours": str(policy.monthly_working_hours), "proration": policy.salary_proration_method,
        })
        messages.success(request, "Company policy updated with audit trail.")
        return redirect("organization:policy-list")
    return render(request, "organization/policy_form.html", {"form": form, "title": "Edit Company Policy"})


MASTER_CONFIG = {
    "company": (Company, CompanyForm, "Company"),
    "branch": (Branch, BranchForm, "Branch"),
    "department": (Department, DepartmentForm, "Department"),
    "designation": (Designation, DesignationForm, "Designation"),
    "shift": (Shift, ShiftForm, "Shift"),
    "holiday": (Holiday, HolidayForm, "Holiday"),
}


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def master_list(request):
    ids = accessible_company_ids(request.user)
    context = {
        "companies": Company.objects.filter(pk__in=ids).order_by("name"),
        "branches": Branch.objects.filter(company_id__in=ids).select_related("company").order_by("company__name", "name"),
        "departments": Department.objects.filter(company_id__in=ids).select_related("company").order_by("company__name", "name"),
        "designations": Designation.objects.filter(company_id__in=ids).select_related("company").order_by("company__name", "name"),
        "shifts": Shift.objects.filter(company_id__in=ids).select_related("company").order_by("company__name", "name"),
        "holidays": Holiday.objects.filter(company_id__in=ids).select_related("company", "branch").order_by("-holiday_date")[:200],
        "can_create_company": request.user.is_superuser,
    }
    return render(request, "organization/master_list.html", context)


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def master_edit(request, kind, pk=None):
    if kind not in MASTER_CONFIG:
        from django.http import Http404
        raise Http404("Unknown master type")
    model, form_class, label = MASTER_CONFIG[kind]
    ids = accessible_company_ids(request.user)
    company_qs = Company.objects.filter(pk__in=ids, is_active=True)
    instance = None
    if pk:
        qs = model.objects.all()
        if model is Company:
            qs = qs.filter(pk__in=ids)
        else:
            qs = qs.filter(company_id__in=ids)
        instance = get_object_or_404(qs, pk=pk)
    elif model is Company and not request.user.is_superuser:
        messages.error(request, "Only Super Admin can create an additional company.")
        return redirect("organization:master-list")

    kwargs = {"instance": instance}
    if model is not Company:
        kwargs["company_queryset"] = company_qs
    form = form_class(request.POST or None, **kwargs)
    if instance is not None and "is_active" in form.fields:
        form.fields["is_active"].disabled = True
        form.fields["is_active"].help_text = "Use the controlled Activate/Deactivate action so a reason and audit trail are recorded."
    if request.method == "POST" and form.is_valid():
        obj = form.save()
        company = obj if model is Company else obj.company
        log_event(
            user=request.user, company=company, action="UPDATE_MASTER" if instance else "CREATE_MASTER",
            module="organization_master", object_id=obj.pk, object_repr=f"{label}: {obj}",
            new_values={"type": kind, "active": getattr(obj, "is_active", True)}, request=request,
        )
        messages.success(request, f"{label} saved with audit trail.")
        return redirect("organization:master-list")
    return render(request, "organization/master_form.html", {"form": form, "title": f"{'Edit' if instance else 'Add'} {label}"})


@require_roles(ROLE_SUPER_ADMIN, ROLE_HR_ADMIN)
def master_lifecycle(request, kind, pk):
    if kind not in MASTER_CONFIG:
        from django.http import Http404
        raise Http404("Unknown master type")
    model, _form_class, label = MASTER_CONFIG[kind]
    ids = accessible_company_ids(request.user)
    qs = model.objects.all()
    if model is Company:
        if not request.user.is_superuser:
            messages.error(request, "Only Super Admin can change company lifecycle status.")
            return redirect("organization:master-list")
        qs = qs.filter(pk__in=ids)
    else:
        qs = qs.filter(company_id__in=ids)
    obj = get_object_or_404(qs, pk=pk)
    form = MasterLifecycleForm(request.POST or None)
    target_active = not obj.is_active
    if request.method == "POST" and form.is_valid():
        old = obj.is_active
        obj.is_active = target_active
        obj.save(update_fields=["is_active", "updated_at"])
        company = obj if model is Company else obj.company
        log_event(
            user=request.user, company=company, action="REACTIVATE_MASTER" if target_active else "DEACTIVATE_MASTER",
            module="organization_master", object_id=obj.pk, object_repr=f"{label}: {obj}",
            old_values={"is_active": old}, new_values={"is_active": target_active},
            reason=form.cleaned_data["reason"], request=request,
        )
        messages.success(request, f"{label} {'reactivated' if target_active else 'deactivated'} with audit reason.")
        return redirect("organization:master-list")
    return render(request, "organization/master_lifecycle.html", {
        "form": form, "object": obj, "label": label, "target_active": target_active,
    })
