import django_tables2 as tables
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor

from dcim.models import Cable, CableBundle
from netbox.tables import PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin

from .template_code import CABLE_LENGTH

__all__ = (
    'CableBundleTable',
    'CableTable',
)


class CableTerminationsColumn(tables.Column):
    """
    Args:
        cable_end: Which side of the cable to report on (A or B)
        attr: The CableTermination attribute to return for each instance (returns the termination object by default)
    """
    def __init__(self, cable_end, attr='termination', *args, **kwargs):
        self.cable_end = cable_end
        self.attr = attr
        super().__init__(accessor=Accessor('terminations'), *args, **kwargs)

    def _get_terminations(self, manager):
        terminations = set()
        for cabletermination in manager.all():
            if cabletermination.cable_end == self.cable_end:
                if termination := getattr(cabletermination, self.attr, None):
                    terminations.add(termination)

        return terminations

    def render(self, value):
        links = [
            f'<a href="{term.get_absolute_url()}">{escape(term)}</a>' for term in self._get_terminations(value)
        ]
        return mark_safe('<br />'.join(links) or '&mdash;')

    def value(self, value):
        return ','.join([str(t) for t in self._get_terminations(value)])


#
# Cables
#

class CableTable(TenancyColumnsMixin, PrimaryModelTable):
    a_terminations = CableTerminationsColumn(
        cable_end='A',
        orderable=False,
        verbose_name=_('Termination A')
    )
    b_terminations = CableTerminationsColumn(
        cable_end='B',
        orderable=False,
        verbose_name=_('Termination B')
    )
    device_a = CableTerminationsColumn(
        cable_end='A',
        attr='_device',
        orderable=False,
        verbose_name=_('Device A')
    )
    device_b = CableTerminationsColumn(
        cable_end='B',
        attr='_device',
        orderable=False,
        verbose_name=_('Device B')
    )
    location_a = CableTerminationsColumn(
        cable_end='A',
        attr='_location',
        orderable=False,
        verbose_name=_('Location A')
    )
    location_b = CableTerminationsColumn(
        cable_end='B',
        attr='_location',
        orderable=False,
        verbose_name=_('Location B')
    )
    rack_a = CableTerminationsColumn(
        cable_end='A',
        attr='_rack',
        orderable=False,
        verbose_name=_('Rack A')
    )
    rack_b = CableTerminationsColumn(
        cable_end='B',
        attr='_rack',
        orderable=False,
        verbose_name=_('Rack B')
    )
    site_a = CableTerminationsColumn(
        cable_end='A',
        attr='_site',
        orderable=False,
        verbose_name=_('Site A')
    )
    site_b = CableTerminationsColumn(
        cable_end='B',
        attr='_site',
        orderable=False,
        verbose_name=_('Site B')
    )
    status = columns.ChoiceFieldColumn()
    profile = columns.ChoiceFieldColumn()
    length = columns.TemplateColumn(
        template_code=CABLE_LENGTH,
        order_by=('_abs_length')
    )
    color = columns.ColorColumn()
    color_name = tables.Column(
        verbose_name=_('Color Name'),
        orderable=False
    )
    bundle = tables.Column(
        verbose_name=_('Bundle'),
        linkify=True,
    )
    tags = columns.TagColumn(
        url_name='dcim:cable_list'
    )

    class Meta(PrimaryModelTable.Meta):
        model = Cable
        fields = (
            'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b',
            'location_a', 'location_b', 'site_a', 'site_b', 'status', 'profile', 'type', 'tenant', 'tenant_group',
            'color', 'color_name', 'bundle', 'length', 'description', 'comments', 'tags', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'status', 'type',
        )


class CableBundleTable(PrimaryModelTable):
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True,
    )
    cable_count = tables.Column(
        verbose_name=_('Cables'),
    )
    tags = columns.TagColumn(
        url_name='dcim:cablebundle_list'
    )

    class Meta(PrimaryModelTable.Meta):
        model = CableBundle
        fields = (
            'pk', 'id', 'name', 'cable_count', 'description', 'tags', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'id', 'name', 'cable_count', 'description',
        )
