import django_filters
from dcim.choices import CableLengthUnitChoices
from dcim.models import Cable, Device, Location, Manufacturer, Module, Site
from django.db import models
from django.utils.translation import gettext_lazy as _
from netbox.filtersets import NetBoxModelFilterSet
from tenancy.models import Tenant

from .choices import (
    ArmorTypeChoices,
    ConstructionChoices,
    DeploymentChoices,
    FiberCircuitStatusChoices,
    FiberTypeChoices,
    FireRatingChoices,
    SheathMaterialChoices,
    SplicePlanStatusChoices,
    StorageMethodChoices,
)
from .models import (
    BufferTube,
    BufferTubeTemplate,
    CableElement,
    CableElementTemplate,
    ClosureCableEntry,
    FiberCable,
    FiberCableType,
    FiberCircuit,
    FiberStrand,
    Ribbon,
    RibbonTemplate,
    SlackLoop,
    SplicePlan,
    SplicePlanEntry,
    SpliceProject,
)


class FiberCableTypeFilterSet(NetBoxModelFilterSet):
    manufacturer_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Manufacturer.objects.all(),
        field_name="manufacturer",
        label=_("Manufacturer (ID)"),
    )
    manufacturer = django_filters.ModelMultipleChoiceFilter(
        queryset=Manufacturer.objects.all(),
        field_name="manufacturer__slug",
        to_field_name="slug",
        label=_("Manufacturer (slug)"),
    )
    construction = django_filters.MultipleChoiceFilter(choices=ConstructionChoices)
    fiber_type = django_filters.MultipleChoiceFilter(choices=FiberTypeChoices)
    sheath_material = django_filters.MultipleChoiceFilter(choices=SheathMaterialChoices)
    is_armored = django_filters.BooleanFilter()
    armor_type = django_filters.MultipleChoiceFilter(choices=ArmorTypeChoices)
    deployment = django_filters.MultipleChoiceFilter(choices=DeploymentChoices)
    fire_rating = django_filters.MultipleChoiceFilter(choices=FireRatingChoices)
    strand_count = django_filters.NumberFilter()

    class Meta:
        model = FiberCableType
        fields = (
            "id",
            "manufacturer_id",
            "model",
            "part_number",
            "construction",
            "fiber_type",
            "strand_count",
            "sheath_material",
            "is_armored",
            "armor_type",
            "deployment",
            "fire_rating",
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            models.Q(model__icontains=value)
            | models.Q(part_number__icontains=value)
            | models.Q(notes__icontains=value)
            | models.Q(manufacturer__name__icontains=value)
        )


class BufferTubeTemplateFilterSet(NetBoxModelFilterSet):
    fiber_cable_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCableType.objects.all(),
        field_name="fiber_cable_type",
        label=_("Fiber Cable Type (ID)"),
    )

    class Meta:
        model = BufferTubeTemplate
        fields = ("id", "fiber_cable_type_id", "name", "fiber_count")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value) | models.Q(description__icontains=value))


class RibbonTemplateFilterSet(NetBoxModelFilterSet):
    fiber_cable_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCableType.objects.all(),
        field_name="fiber_cable_type",
        label=_("Fiber Cable Type (ID)"),
    )
    buffer_tube_template_id = django_filters.ModelMultipleChoiceFilter(
        queryset=BufferTubeTemplate.objects.all(),
        field_name="buffer_tube_template",
        label=_("Buffer Tube Template (ID)"),
    )

    class Meta:
        model = RibbonTemplate
        fields = ("id", "fiber_cable_type_id", "buffer_tube_template_id", "name", "fiber_count")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value) | models.Q(description__icontains=value))


class CableElementTemplateFilterSet(NetBoxModelFilterSet):
    fiber_cable_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCableType.objects.all(),
        field_name="fiber_cable_type",
        label=_("Fiber Cable Type (ID)"),
    )

    class Meta:
        model = CableElementTemplate
        fields = ("id", "fiber_cable_type_id", "name", "element_type")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value) | models.Q(description__icontains=value))


class FiberCableFilterSet(NetBoxModelFilterSet):
    fiber_cable_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCableType.objects.all(),
        field_name="fiber_cable_type",
        label=_("Fiber Cable Type (ID)"),
    )
    cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Cable.objects.all(),
        label=_("Cable (ID)"),
    )
    install_date = django_filters.DateFilter()

    class Meta:
        model = FiberCable
        fields = ("id", "cable_id", "fiber_cable_type_id", "serial_number", "install_date")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            models.Q(serial_number__icontains=value)
            | models.Q(notes__icontains=value)
            | models.Q(cable__label__icontains=value)
            | models.Q(fiber_cable_type__model__icontains=value)
        )


class BufferTubeFilterSet(NetBoxModelFilterSet):
    fiber_cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCable.objects.all(),
        field_name="fiber_cable",
        label=_("Fiber Cable (ID)"),
    )

    class Meta:
        model = BufferTube
        fields = ("id", "fiber_cable_id", "name", "position")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value))


class RibbonFilterSet(NetBoxModelFilterSet):
    fiber_cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCable.objects.all(),
        field_name="fiber_cable",
        label=_("Fiber Cable (ID)"),
    )
    buffer_tube_id = django_filters.ModelMultipleChoiceFilter(
        queryset=BufferTube.objects.all(),
        field_name="buffer_tube",
        label=_("Buffer Tube (ID)"),
    )

    class Meta:
        model = Ribbon
        fields = ("id", "fiber_cable_id", "buffer_tube_id", "name", "position")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value))


class FiberStrandFilterSet(NetBoxModelFilterSet):
    fiber_cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCable.objects.all(),
        field_name="fiber_cable",
        label=_("Fiber Cable (ID)"),
    )
    buffer_tube_id = django_filters.ModelMultipleChoiceFilter(
        queryset=BufferTube.objects.all(),
        field_name="buffer_tube",
        label=_("Buffer Tube (ID)"),
    )
    ribbon_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Ribbon.objects.all(),
        field_name="ribbon",
        label=_("Ribbon (ID)"),
    )
    has_front_port_a = django_filters.BooleanFilter(
        field_name="front_port_a",
        lookup_expr="isnull",
        exclude=True,
        label=_("Has front port A"),
    )
    has_front_port_b = django_filters.BooleanFilter(
        field_name="front_port_b",
        lookup_expr="isnull",
        exclude=True,
        label=_("Has front port B"),
    )

    class Meta:
        model = FiberStrand
        fields = ("id", "fiber_cable_id", "buffer_tube_id", "ribbon_id", "name", "position")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value))


class CableElementFilterSet(NetBoxModelFilterSet):
    fiber_cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCable.objects.all(),
        field_name="fiber_cable",
        label=_("Fiber Cable (ID)"),
    )

    class Meta:
        model = CableElement
        fields = ("id", "fiber_cable_id", "name", "element_type")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value))


class SpliceProjectFilterSet(NetBoxModelFilterSet):
    class Meta:
        model = SpliceProject
        fields = ("id", "name")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value) | models.Q(description__icontains=value))


class SplicePlanFilterSet(NetBoxModelFilterSet):
    closure_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Device.objects.all(),
        field_name="closure",
        label=_("Closure (ID)"),
    )
    project_id = django_filters.ModelMultipleChoiceFilter(
        queryset=SpliceProject.objects.all(),
        field_name="project",
        label=_("Project (ID)"),
    )
    status = django_filters.MultipleChoiceFilter(choices=SplicePlanStatusChoices)

    class Meta:
        model = SplicePlan
        fields = ("id", "closure_id", "project_id", "name", "status")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(name__icontains=value) | models.Q(description__icontains=value))


class SplicePlanEntryFilterSet(NetBoxModelFilterSet):
    plan_id = django_filters.ModelMultipleChoiceFilter(
        queryset=SplicePlan.objects.all(),
        field_name="plan",
        label=_("Plan (ID)"),
    )
    tray_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Module.objects.all(),
        field_name="tray",
        label=_("Tray (ID)"),
    )

    class Meta:
        model = SplicePlanEntry
        fields = ("id", "plan_id", "tray_id", "fiber_a", "fiber_b")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(plan__name__icontains=value))


class ClosureCableEntryFilterSet(NetBoxModelFilterSet):
    closure_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Device.objects.all(),
        field_name="closure",
        label=_("Closure (ID)"),
    )

    class Meta:
        model = ClosureCableEntry
        fields = ("id", "closure_id", "fiber_cable", "entrance_label")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(entrance_label__icontains=value) | models.Q(notes__icontains=value))


class SlackLoopFilterSet(NetBoxModelFilterSet):
    fiber_cable_id = django_filters.ModelMultipleChoiceFilter(
        queryset=FiberCable.objects.all(),
        field_name="fiber_cable",
        label=_("Fiber Cable (ID)"),
    )
    site_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Site.objects.all(),
        field_name="site",
        label=_("Site (ID)"),
    )
    location_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Location.objects.all(),
        field_name="location",
        label=_("Location (ID)"),
    )
    length_unit = django_filters.MultipleChoiceFilter(choices=CableLengthUnitChoices)
    storage_method = django_filters.MultipleChoiceFilter(choices=StorageMethodChoices)

    class Meta:
        model = SlackLoop
        fields = ("id", "fiber_cable_id", "site_id", "location_id", "length_unit", "storage_method")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(models.Q(notes__icontains=value))


class FiberCircuitFilterSet(NetBoxModelFilterSet):
    status = django_filters.MultipleChoiceFilter(choices=FiberCircuitStatusChoices)
    tenant_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Tenant.objects.all(),
        field_name="tenant",
        label=_("Tenant (ID)"),
    )

    class Meta:
        model = FiberCircuit
        fields = ("id", "name", "cid", "status", "strand_count", "tenant")

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            models.Q(name__icontains=value) | models.Q(cid__icontains=value) | models.Q(description__icontains=value)
        )
