import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor

from dcim import models
from netbox.tables import NestedGroupModelTable, NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin

from .template_code import *

__all__ = (
    'BaseInterfaceTable',
    'CableTerminationTable',
    'ConsolePortTable',
    'ConsoleServerPortTable',
    'DeviceBayTable',
    'DeviceConsolePortTable',
    'DeviceConsoleServerPortTable',
    'DeviceDeviceBayTable',
    'DeviceFrontPortTable',
    'DeviceInterfaceTable',
    'DeviceInventoryItemTable',
    'DeviceModuleBayTable',
    'DevicePowerOutletTable',
    'DevicePowerPortTable',
    'DeviceRearPortTable',
    'DeviceRoleTable',
    'DeviceTable',
    'FrontPortTable',
    'InterfaceLAGMemberTable',
    'InterfaceTable',
    'InventoryItemRoleTable',
    'InventoryItemTable',
    'MACAddressTable',
    'ModuleBayTable',
    'PlatformTable',
    'PowerOutletTable',
    'PowerPortTable',
    'RearPortTable',
    'VirtualChassisTable',
    'VirtualDeviceContextTable'
)

MODULEBAY_STATUS = """
{% badge record.installed_module.get_status_display bg_color=record.installed_module.get_status_color %}
"""

MACADDRESS_LINK = """
{% if record.pk %}
    <a href="{{ record.get_absolute_url }}" id="macaddress_{{ record.pk }}">{{ record.mac_address }}</a>
{% endif %}
"""

MACADDRESS_COPY_BUTTON = """
{% copy_content record.pk prefix="macaddress_" %}
"""


#
# Device roles
#

class DeviceRoleTable(NestedGroupModelTable):
    device_count = columns.LinkedCountColumn(
        viewname='dcim:device_list',
        url_params={'role_id': 'pk'},
        verbose_name=_('Devices')
    )
    vm_count = columns.LinkedCountColumn(
        viewname='virtualization:virtualmachine_list',
        url_params={'role_id': 'pk'},
        verbose_name=_('VMs')
    )
    color = columns.ColorColumn()
    vm_role = columns.BooleanColumn(
        verbose_name=_('VM role'),
        false_mark=None
    )
    config_template = tables.Column(
        linkify=True
    )
    tags = columns.TagColumn(
        url_name='dcim:devicerole_list'
    )

    class Meta(NestedGroupModelTable.Meta):
        model = models.DeviceRole
        fields = (
            'pk', 'id', 'name', 'parent', 'device_count', 'vm_count', 'color', 'vm_role', 'config_template',
            'description', 'slug', 'tags', 'actions', 'created', 'last_updated',
        )
        default_columns = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description')


#
# Platforms
#

class PlatformTable(NestedGroupModelTable):
    manufacturer = tables.Column(
        verbose_name=_('Manufacturer'),
        linkify=True
    )
    config_template = tables.Column(
        verbose_name=_('Config Template'),
        linkify=True
    )
    device_count = columns.LinkedCountColumn(
        viewname='dcim:device_list',
        url_params={'platform_id': 'pk'},
        verbose_name=_('Devices')
    )
    vm_count = columns.LinkedCountColumn(
        viewname='virtualization:virtualmachine_list',
        url_params={'platform_id': 'pk'},
        verbose_name=_('VMs')
    )
    tags = columns.TagColumn(
        url_name='dcim:platform_list'
    )

    class Meta(NestedGroupModelTable.Meta):
        model = models.Platform
        fields = (
            'pk', 'id', 'name', 'parent', 'manufacturer', 'device_count', 'vm_count', 'slug', 'config_template',
            'description', 'tags', 'actions', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'name', 'manufacturer', 'device_count', 'vm_count', 'description',
        )


#
# Devices
#

class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code=DEVICE_LINK,
        linkify=True,
    )
    status = columns.ChoiceFieldColumn(
        verbose_name=_('Status'),
    )
    region = tables.Column(
        verbose_name=_('Region'),
        accessor=Accessor('site__region'),
        linkify=True
    )
    site_group = tables.Column(
        accessor=Accessor('site__group'),
        linkify=True,
        verbose_name=_('Site Group')
    )
    site = tables.Column(
        verbose_name=_('Site'),
        linkify=True
    )
    location = tables.Column(
        verbose_name=_('Location'),
        linkify=True
    )
    rack = tables.Column(
        verbose_name=_('Rack'),
        linkify=True
    )
    position = columns.TemplateColumn(
        verbose_name=_('Position'),
        template_code='{{ value|floatformat }}'
    )
    role = columns.ColoredLabelColumn(
        verbose_name=_('Role')
    )
    manufacturer = tables.Column(
        verbose_name=_('Manufacturer'),
        accessor=Accessor('device_type__manufacturer'),
        linkify=True
    )
    device_type = tables.Column(
        linkify=True,
        verbose_name=_('Type')
    )
    u_height = columns.TemplateColumn(
        accessor=tables.A('device_type__u_height'),
        verbose_name=_('U Height'),
        template_code='{{ value|floatformat }}'
    )
    platform = tables.Column(
        linkify=True,
        verbose_name=_('Platform')
    )
    primary_ip = tables.Column(
        linkify=True,
        order_by=('primary_ip4', 'primary_ip6'),
        verbose_name=_('IP Address')
    )
    primary_ip4 = tables.Column(
        linkify=True,
        verbose_name=_('IPv4 Address')
    )
    primary_ip6 = tables.Column(
        linkify=True,
        verbose_name=_('IPv6 Address')
    )
    oob_ip = tables.Column(
        linkify=True,
        verbose_name='OOB IP'
    )
    cluster = tables.Column(
        verbose_name=_('Cluster'),
        linkify=True
    )
    virtual_chassis = tables.Column(
        verbose_name=_('Virtual Chassis'),
        linkify=True
    )
    vc_position = tables.Column(
        verbose_name=_('VC Position')
    )
    vc_priority = tables.Column(
        verbose_name=_('VC Priority')
    )
    config_template = tables.Column(
        verbose_name=_('Config Template'),
        linkify=True
    )
    parent_device = tables.Column(
        verbose_name=_('Parent Device'),
        linkify=True,
        accessor='parent_bay__device'
    )
    device_bay_position = tables.Column(
        verbose_name=_('Position (Device Bay)'),
        accessor='parent_bay',
        linkify=True
    )
    tags = columns.TagColumn(
        url_name='dcim:device_list'
    )
    console_port_count = tables.Column(
        verbose_name=_('Console ports')
    )
    console_server_port_count = tables.Column(
        verbose_name=_('Console server ports')
    )
    power_port_count = tables.Column(
        verbose_name=_('Power ports')
    )
    power_outlet_count = tables.Column(
        verbose_name=_('Power outlets')
    )
    interface_count = tables.Column(
        verbose_name=_('Interfaces')
    )
    front_port_count = tables.Column(
        verbose_name=_('Front ports')
    )
    rear_port_count = tables.Column(
        verbose_name=_('Rear ports')
    )
    device_bay_count = tables.Column(
        verbose_name=_('Device bays')
    )
    module_bay_count = tables.Column(
        verbose_name=_('Module bays')
    )
    inventory_item_count = tables.Column(
        verbose_name=_('Inventory items')
    )

    class Meta(PrimaryModelTable.Meta):
        model = models.Device
        fields = (
            'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'role', 'manufacturer', 'device_type',
            'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'parent_device',
            'device_bay_position', 'position', 'face', 'latitude', 'longitude', 'airflow', 'primary_ip', 'primary_ip4',
            'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
            'config_template', 'comments', 'contacts', 'tags', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'role', 'manufacturer', 'device_type',
            'primary_ip',
        )


#
# Device components
#

class DeviceComponentTable(NetBoxTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify=True
    )
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True,
    )
    device_location = tables.Column(
        accessor=tables.A('device__location'),
        verbose_name=_('Device Location'),
        linkify=True,
    )
    device_site = tables.Column(
        accessor=tables.A('device__site'),
        verbose_name=_('Device Site'),
        linkify=True,
    )
    device_status = columns.ChoiceFieldColumn(
        accessor=tables.A('device__status'),
        verbose_name=_('Device Status'),
        color=lambda x: x.device.get_status_color(),
    )

    class Meta(NetBoxTable.Meta):
        order_by = ('device', 'name')


class ModularDeviceComponentTable(DeviceComponentTable):
    module_bay = tables.Column(
        verbose_name=_('Module Bay'),
        accessor=Accessor('module__module_bay'),
        linkify={
            'viewname': 'dcim:device_modulebays',
            'args': [Accessor('device_id')],
        }
    )
    module = tables.Column(
        verbose_name=_('Module'),
        linkify=True
    )
    inventory_items = columns.ManyToManyColumn(
        linkify_item=True,
        verbose_name=_('Inventory Items'),
    )

    class Meta(NetBoxTable.Meta):
        pass


class CableTerminationTable(NetBoxTable):
    cable = tables.Column(
        verbose_name=_('Cable'),
        linkify=True
    )
    cable_color = columns.ColorColumn(
        accessor='cable__color',
        orderable=False,
        verbose_name=_('Cable Color')
    )
    link_peer = columns.TemplateColumn(
        accessor='link_peers',
        template_code=LINKTERMINATION,
        orderable=False,
        verbose_name=_('Link Peers')
    )
    mark_connected = columns.BooleanColumn(
        verbose_name=_('Mark Connected'),
        false_mark=None
    )

    class Meta:
        row_attrs = {
            'data-name': lambda record: record.name,
            'data-mark-connected': lambda record: "true" if record.mark_connected else "false",
            'data-cable-status': lambda record: record.cable.status if record.cable else "",
            'data-type': lambda record: record.type
        }

    def value_link_peer(self, value):
        return ', '.join([
            f"{termination.parent_object} > {termination}" for termination in value
        ])


class PathEndpointTable(CableTerminationTable):
    connection = columns.TemplateColumn(
        accessor='_path__destinations',
        template_code=LINKTERMINATION,
        verbose_name=_('Connection'),
        orderable=False
    )

    def value_connection(self, value):
        if value:
            connections = []
            for termination in value:
                if hasattr(termination, 'parent_object'):
                    connections.append(f'{termination.parent_object} > {termination}')
                else:
                    connections.append(str(termination))
            return ', '.join(connections)
        return None


class ConsolePortTable(ModularDeviceComponentTable, PathEndpointTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_consoleports',
            'args': [Accessor('device_id')],
        }
    )
    tags = columns.TagColumn(
        url_name='dcim:consoleport_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.ConsolePort
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
            'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created',
            'last_updated',
        )
        default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description')


class DeviceConsolePortTable(ConsolePortTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-console"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=CONSOLEPORT_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.ConsolePort
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
            'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions'
        )
        default_columns = ('pk', 'name', 'label', 'type', 'speed', 'description', 'cable', 'connection')


class ConsoleServerPortTable(ModularDeviceComponentTable, PathEndpointTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_consoleserverports',
            'args': [Accessor('device_id')],
        }
    )
    tags = columns.TagColumn(
        url_name='dcim:consoleserverport_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.ConsoleServerPort
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
            'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items', 'tags', 'created',
            'last_updated',
        )
        default_columns = ('pk', 'name', 'device', 'label', 'type', 'speed', 'description')


class DeviceConsoleServerPortTable(ConsoleServerPortTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-console-network-outline"></i> '
                      '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=CONSOLESERVERPORT_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.ConsoleServerPort
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
            'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
        )
        default_columns = ('pk', 'name', 'label', 'type', 'speed', 'description', 'cable', 'connection')


class PowerPortTable(ModularDeviceComponentTable, PathEndpointTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_powerports',
            'args': [Accessor('device_id')],
        }
    )
    maximum_draw = tables.Column(
        verbose_name=_('Maximum draw (W)')
    )
    allocated_draw = tables.Column(
        verbose_name=_('Allocated draw (W)')
    )
    tags = columns.TagColumn(
        url_name='dcim:powerport_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.PowerPort
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'mark_connected',
            'maximum_draw', 'allocated_draw', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items',
            'tags', 'created', 'last_updated',
        )
        default_columns = ('pk', 'name', 'device', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')


class DevicePowerPortTable(PowerPortTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-power-plug-outline"></i> <a href="{{ record.get_absolute_url }}">'
                      '{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=POWERPORT_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.PowerPort
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'maximum_draw', 'allocated_draw',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
        )
        default_columns = (
            'pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable', 'connection',
        )


class PowerOutletTable(ModularDeviceComponentTable, PathEndpointTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_poweroutlets',
            'args': [Accessor('device_id')],
        }
    )
    power_port = tables.Column(
        verbose_name=_('Power Port'),
        linkify=True
    )
    status = columns.ChoiceFieldColumn(
        verbose_name=_('Status'),
    )
    color = columns.ColorColumn()
    tags = columns.TagColumn(
        url_name='dcim:poweroutlet_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.PowerOutlet
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'power_port',
            'color', 'feed_leg', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'inventory_items',
            'tags', 'created', 'last_updated', 'status',
        )
        default_columns = (
            'pk', 'name', 'device', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'description',
        )


class DevicePowerOutletTable(PowerOutletTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-power-socket"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=POWEROUTLET_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.PowerOutlet
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'color', 'power_port', 'feed_leg',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
            'status',
        )
        default_columns = (
            'pk', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'description', 'cable',
            'connection',
        )


class BaseInterfaceTable(NetBoxTable):
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True,
        order_by=('_name',)
    )
    enabled = columns.BooleanColumn(
        verbose_name=_('Enabled'),
    )
    ip_addresses = tables.TemplateColumn(
        template_code=INTERFACE_IPADDRESSES,
        orderable=False,
        verbose_name=_('IP Addresses')
    )
    primary_mac_address = tables.Column(
        verbose_name=_('Primary MAC'),
        linkify=True
    )
    mac_addresses = columns.ManyToManyColumn(
        orderable=False,
        linkify_item=True,
        verbose_name=_('MAC Addresses')
    )
    fhrp_groups = tables.TemplateColumn(
        accessor=Accessor('fhrp_group_assignments'),
        template_code=INTERFACE_FHRPGROUPS,
        orderable=False,
        verbose_name=_('FHRP Groups')
    )
    l2vpn = tables.Column(
        accessor=tables.A('l2vpn_termination__l2vpn'),
        linkify=True,
        orderable=False,
        verbose_name=_('L2VPN')
    )
    tunnel = tables.Column(
        accessor=tables.A('tunnel_termination__tunnel'),
        linkify=True,
        orderable=False,
        verbose_name=_('Tunnel')
    )
    untagged_vlan = tables.Column(
        verbose_name=_('Untagged VLAN'),
        linkify=True
    )
    tagged_vlans = columns.TemplateColumn(
        template_code=INTERFACE_TAGGED_VLANS,
        orderable=False,
        verbose_name=_('Tagged VLANs')
    )
    qinq_svlan = tables.Column(
        verbose_name=_('Q-in-Q SVLAN'),
        linkify=True
    )

    def value_ip_addresses(self, value):
        return ",".join([str(obj.address) for obj in value.all()])

    def value_tagged_vlans(self, value):
        return ",".join([str(obj) for obj in value.all()])


class InterfaceTable(BaseInterfaceTable, ModularDeviceComponentTable, PathEndpointTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_interfaces',
            'args': [Accessor('device_id')],
        }
    )
    mgmt_only = columns.BooleanColumn(
        verbose_name=_('Management Only'),
        false_mark=None
    )
    speed_formatted = columns.TemplateColumn(
        template_code='{% load helpers %}{{ value|humanize_speed }}',
        accessor=Accessor('speed'),
        verbose_name=_('Speed')
    )
    wireless_link = tables.Column(
        verbose_name=_('Wireless link'),
        linkify=True
    )
    wireless_lans = columns.TemplateColumn(
        template_code=INTERFACE_WIRELESS_LANS,
        orderable=False,
        verbose_name=_('Wireless LANs')
    )
    vdcs = columns.ManyToManyColumn(
        linkify_item=True,
        verbose_name=_('VDCs')
    )
    vrf = tables.Column(
        verbose_name=_('VRF'),
        linkify=True
    )
    virtual_circuit_termination = tables.Column(
        verbose_name=_('Virtual Circuit'),
        linkify=True
    )
    tags = columns.TagColumn(
        url_name='dcim:interface_list'
    )

    # Override PathEndpointTable.connection to accommodate virtual circuits
    connection = columns.TemplateColumn(
        accessor='_path__destinations',
        template_code=INTERFACE_LINKTERMINATION,
        verbose_name=_('Connection'),
        orderable=False
    )

    def value_connection(self, record, value):
        if record.is_virtual and hasattr(record, 'virtual_circuit_termination') and record.virtual_circuit_termination:
            connections = [
                f"{t.interface.parent_object} > {t.interface} via {t.parent_object}"
                for t in record.connected_endpoints
            ]
            return ', '.join(connections)
        return super().value_connection(value)

    class Meta(DeviceComponentTable.Meta):
        model = models.Interface
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu',
            'speed', 'speed_formatted', 'duplex', 'mode', 'mac_addresses', 'primary_mac_address', 'wwn',
            'poe_mode', 'poe_type', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
            'description', 'mark_connected', 'cable', 'cable_color', 'wireless_link', 'wireless_lans', 'link_peer',
            'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups',
            'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'inventory_items', 'created', 'last_updated',
            'vlan_translation_policy',
        )
        default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'type', 'description')


class InterfaceLAGMemberTable(PathEndpointTable, NetBoxTable):
    parent = tables.Column(
        verbose_name=_('Parent'),
        accessor=Accessor('device'),
        linkify=True,
    )
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True,
        order_by=('_name',),
    )
    connection = columns.TemplateColumn(
        accessor='connected_endpoints',
        template_code=INTERFACE_LAG_MEMBERS_LINKTERMINATION,
        verbose_name=_('Peer'),
        orderable=False,
    )
    tags = columns.TagColumn(
        url_name='dcim:interface_list'
    )

    class Meta(NetBoxTable.Meta):
        model = models.Interface
        fields = ('pk', 'parent', 'name', 'type', 'connection')
        default_columns = ('pk', 'parent', 'name', 'type', 'connection')


class DeviceInterfaceTable(InterfaceTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-{% if record.mgmt_only %}wrench{% elif record.is_lag %}reorder-horizontal'
                      '{% elif record.is_virtual %}circle{% elif record.is_wireless %}wifi{% else %}ethernet'
                      '{% endif %}"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        order_by=Accessor('_name'),
        attrs={'td': {'class': 'text-nowrap'}}
    )
    parent = tables.Column(
        verbose_name=_('Parent'),
        linkify=True
    )
    bridge = tables.Column(
        verbose_name=_('Bridge'),
        linkify=True
    )
    lag = tables.Column(
        linkify=True,
        verbose_name=_('LAG')
    )
    actions = columns.ActionsColumn(
        extra_buttons=INTERFACE_BUTTONS
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.Interface
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
            'mgmt_only', 'mtu', 'mode', 'mac_addresses', 'primary_mac_address', 'wwn', 'rf_role', 'rf_channel',
            'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable',
            'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf',
            'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan',
            'actions',
        )
        default_columns = (
            'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses',
            'cable', 'connection',
        )
        row_attrs = {
            'data-name': lambda record: record.name,
            'data-enabled': lambda record: "enabled" if record.enabled else "disabled",
            'data-virtual': lambda record: "true" if record.is_virtual else "false",
            'data-mark-connected': lambda record: "true" if record.mark_connected else "false",
            'data-cable-status': lambda record: record.cable.status if record.cable else "",
        }


class FrontPortTable(ModularDeviceComponentTable, CableTerminationTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_frontports',
            'args': [Accessor('device_id')],
        }
    )
    color = columns.ColorColumn(
        verbose_name=_('Color'),
    )
    mappings = columns.ManyToManyColumn(
        verbose_name=_('Mappings'),
        transform=lambda obj: f'{obj.rear_port}:{obj.rear_port_position}'
    )
    tags = columns.TagColumn(
        url_name='dcim:frontport_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.FrontPort
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'mappings',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'inventory_items', 'tags', 'created',
            'last_updated',
        )
        default_columns = (
            'pk', 'name', 'device', 'label', 'type', 'color', 'positions', 'mappings', 'description',
        )


class DeviceFrontPortTable(FrontPortTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
                      '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=FRONTPORT_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.FrontPort
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'mappings',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions',
        )
        default_columns = (
            'pk', 'name', 'label', 'type', 'color', 'positions', 'mappings', 'description', 'cable', 'link_peer',
        )


class RearPortTable(ModularDeviceComponentTable, CableTerminationTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_rearports',
            'args': [Accessor('device_id')],
        }
    )
    color = columns.ColorColumn(
        verbose_name=_('Color'),
    )
    mappings = columns.ManyToManyColumn(
        verbose_name=_('Mappings'),
        transform=lambda obj: f'{obj.front_port}:{obj.front_port_position}'
    )
    tags = columns.TagColumn(
        url_name='dcim:rearport_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.RearPort
        fields = (
            'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'mappings',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'inventory_items', 'tags', 'created',
            'last_updated',
        )
        default_columns = (
            'pk', 'name', 'device', 'label', 'type', 'color', 'positions', 'mappings', 'description',
        )


class DeviceRearPortTable(RearPortTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-square-rounded{% if not record.cable %}-outline{% endif %}"></i> '
                      '<a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    actions = columns.ActionsColumn(
        extra_buttons=REARPORT_BUTTONS
    )

    class Meta(CableTerminationTable.Meta, DeviceComponentTable.Meta):
        model = models.RearPort
        fields = (
            'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'mappings',
            'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions',
        )
        default_columns = (
            'pk', 'name', 'label', 'type', 'color', 'positions', 'mappings', 'description', 'cable', 'link_peer',
        )


class DeviceBayTable(DeviceComponentTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_devicebays',
            'args': [Accessor('device_id')],
        }
    )
    enabled = columns.BooleanColumn(
        verbose_name=_('Enabled'),
    )
    status = tables.TemplateColumn(
        verbose_name=_('Status'),
        template_code=DEVICEBAY_STATUS,
        order_by=Accessor('installed_device__status')
    )
    installed_device = tables.Column(
        verbose_name=_('Installed Device'),
        linkify=True
    )
    installed_role = columns.ColoredLabelColumn(
        accessor=Accessor('installed_device__role'),
        verbose_name=_('Installed Role')
    )
    installed_device_type = tables.Column(
        accessor=Accessor('installed_device__device_type'),
        linkify=True,
        verbose_name=_('Installed Type')
    )
    installed_description = tables.Column(
        accessor=Accessor('installed_device__description'),
        verbose_name=_('Installed Description')
    )
    installed_serial = tables.Column(
        accessor=Accessor('installed_device__serial'),
        verbose_name=_('Installed Serial')
    )
    installed_asset_tag = tables.Column(
        accessor=Accessor('installed_device__asset_tag'),
        verbose_name=_('Installed Asset Tag')
    )
    tags = columns.TagColumn(
        url_name='dcim:devicebay_list'
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.DeviceBay
        fields = (
            'pk', 'id', 'name', 'device', 'label', 'enabled', 'status', 'description', 'installed_device',
            'installed_role', 'installed_device_type', 'installed_description', 'installed_serial',
            'installed_asset_tag', 'tags', 'created', 'last_updated',
        )

        default_columns = ('pk', 'name', 'device', 'label', 'enabled', 'status', 'installed_device', 'description')


class DeviceDeviceBayTable(DeviceBayTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<i class="mdi mdi-circle{% if record.installed_device %}slice-8{% else %}outline{% endif %}'
                      '"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )
    enabled = columns.BooleanColumn(
        verbose_name=_('Enabled'),
    )
    actions = columns.ActionsColumn(
        extra_buttons=DEVICEBAY_BUTTONS
    )

    class Meta(DeviceComponentTable.Meta):
        model = models.DeviceBay
        fields = (
            'pk', 'id', 'name', 'label', 'enabled', 'status', 'installed_device', 'description', 'tags', 'actions',
        )
        default_columns = ('pk', 'name', 'label', 'enabled', 'status', 'installed_device', 'description')


class ModuleBayTable(ModularDeviceComponentTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_modulebays',
            'args': [Accessor('device_id')],
        }
    )
    enabled = columns.BooleanColumn(
        verbose_name=_('Enabled'),
    )
    parent = tables.Column(
        linkify=True,
        verbose_name=_('Parent'),
    )
    installed_module = tables.Column(
        linkify=True,
        verbose_name=_('Installed Module')
    )
    module_serial = tables.Column(
        verbose_name=_('Module Serial'),
        accessor=tables.A('installed_module__serial')
    )
    module_asset_tag = tables.Column(
        verbose_name=_('Module Asset Tag'),
        accessor=tables.A('installed_module__asset_tag')
    )
    tags = columns.TagColumn(
        url_name='dcim:modulebay_list'
    )
    module_status = columns.TemplateColumn(
        accessor=tables.A('installed_module__status'),
        template_code=MODULEBAY_STATUS,
        verbose_name=_('Module Status')
    )

    class Meta(ModularDeviceComponentTable.Meta):
        model = models.ModuleBay
        fields = (
            'pk', 'id', 'name', 'device', 'enabled', 'parent', 'label', 'position', 'installed_module', 'module_status',
            'module_serial', 'module_asset_tag', 'description', 'tags',
        )
        default_columns = (
            'pk', 'name', 'device', 'enabled', 'parent', 'label', 'installed_module', 'module_status', 'description',
        )

    def render_parent_bay(self, value):
        return value.name if value else ''

    def render_installed_module(self, value):
        return value.module_type if value else ''


class DeviceModuleBayTable(ModuleBayTable):
    name = columns.MPTTColumn(
        verbose_name=_('Name'),
        linkify=True,
    )
    enabled = columns.BooleanColumn(
        verbose_name=_('Enabled'),
    )
    actions = columns.ActionsColumn(
        extra_buttons=MODULEBAY_BUTTONS
    )

    class Meta(ModuleBayTable.Meta):
        model = models.ModuleBay
        fields = (
            'pk', 'id', 'parent', 'name', 'label', 'enabled', 'position', 'installed_module', 'module_status',
            'module_serial', 'module_asset_tag', 'description', 'tags', 'actions',
        )
        default_columns = ('pk', 'name', 'label', 'enabled', 'installed_module', 'module_status', 'description')


class InventoryItemTable(DeviceComponentTable):
    device = tables.Column(
        verbose_name=_('Device'),
        linkify={
            'viewname': 'dcim:device_inventory',
            'args': [Accessor('device_id')],
        }
    )
    role = columns.ColoredLabelColumn(
        verbose_name=_('Role'),
    )
    manufacturer = tables.Column(
        verbose_name=_('Manufacturer'),
        linkify=True
    )
    component = tables.Column(
        verbose_name=_('Component'),
        orderable=False,
        linkify=True
    )
    discovered = columns.BooleanColumn(
        verbose_name=_('Discovered'),
        false_mark=None
    )
    status = columns.ChoiceFieldColumn(
        verbose_name=_('Status'),
    )
    parent = tables.Column(
        linkify=True,
        verbose_name=_('Parent'),
    )
    tags = columns.TagColumn(
        url_name='dcim:inventoryitem_list'
    )
    cable = None  # Override DeviceComponentTable

    class Meta(NetBoxTable.Meta):
        model = models.InventoryItem
        fields = (
            'pk', 'id', 'name', 'device', 'parent', 'component', 'label', 'status', 'role', 'manufacturer', 'part_id',
            'serial', 'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'name', 'device', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
        )


class DeviceInventoryItemTable(InventoryItemTable):
    name = tables.TemplateColumn(
        verbose_name=_('Name'),
        template_code='<a href="{{ record.get_absolute_url }}" style="padding-left: {{ record.level }}0px">'
                      '{{ value }}</a>',
        attrs={'td': {'class': 'text-nowrap'}}
    )

    class Meta(NetBoxTable.Meta):
        model = models.InventoryItem
        fields = (
            'pk', 'id', 'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
            'component', 'description', 'discovered', 'tags', 'actions',
        )
        default_columns = (
            'pk', 'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component',
        )


class InventoryItemRoleTable(OrganizationalModelTable):
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True
    )
    inventoryitem_count = columns.LinkedCountColumn(
        viewname='dcim:inventoryitem_list',
        url_params={'role_id': 'pk'},
        verbose_name=_('Items')
    )
    color = columns.ColorColumn(
        verbose_name=_('Color'),
    )
    tags = columns.TagColumn(
        url_name='dcim:inventoryitemrole_list'
    )

    class Meta(OrganizationalModelTable.Meta):
        model = models.InventoryItemRole
        fields = (
            'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'comments', 'tags', 'actions',
        )
        default_columns = ('pk', 'name', 'inventoryitem_count', 'color', 'description')


#
# Virtual chassis
#

class VirtualChassisTable(PrimaryModelTable):
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True
    )
    master = tables.Column(
        verbose_name=_('Master'),
        linkify=True
    )
    member_count = columns.LinkedCountColumn(
        viewname='dcim:device_list',
        url_params={'virtual_chassis_id': 'pk'},
        verbose_name=_('Members')
    )
    tags = columns.TagColumn(
        url_name='dcim:virtualchassis_list'
    )

    class Meta(PrimaryModelTable.Meta):
        model = models.VirtualChassis
        fields = (
            'pk', 'id', 'name', 'domain', 'master', 'member_count', 'description', 'comments', 'tags', 'created',
            'last_updated',
        )
        default_columns = ('pk', 'name', 'domain', 'master', 'member_count')


class VirtualDeviceContextTable(TenancyColumnsMixin, PrimaryModelTable):
    name = tables.Column(
        verbose_name=_('Name'),
        linkify=True
    )
    device = tables.Column(
        verbose_name=_('Device'),
        order_by=('device__name',),
        linkify=True
    )
    status = columns.ChoiceFieldColumn(
        verbose_name=_('Status'),
    )
    primary_ip = tables.Column(
        linkify=True,
        order_by=('primary_ip4', 'primary_ip6'),
        verbose_name=_('IP Address')
    )
    primary_ip4 = tables.Column(
        linkify=True,
        verbose_name=_('IPv4 Address')
    )
    primary_ip6 = tables.Column(
        linkify=True,
        verbose_name=_('IPv6 Address')
    )
    interface_count = columns.LinkedCountColumn(
        viewname='dcim:interface_list',
        url_params={'vdc_id': 'pk'},
        verbose_name=_('Interfaces')
    )
    tags = columns.TagColumn(
        url_name='dcim:virtualdevicecontext_list'
    )

    class Meta(PrimaryModelTable.Meta):
        model = models.VirtualDeviceContext
        fields = (
            'pk', 'id', 'name', 'status', 'identifier', 'tenant', 'tenant_group', 'primary_ip', 'primary_ip4',
            'primary_ip6', 'comments', 'tags', 'interface_count', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'name', 'identifier', 'status', 'tenant', 'primary_ip',
        )


class MACAddressTable(PrimaryModelTable):
    mac_address = tables.TemplateColumn(
        template_code=MACADDRESS_LINK,
        verbose_name=_('MAC Address')
    )
    assigned_object = tables.Column(
        linkify=True,
        orderable=False,
        verbose_name=_('Interface')
    )
    assigned_object_parent = tables.Column(
        accessor='assigned_object__parent_object',
        linkify=True,
        orderable=False,
        verbose_name=_('Parent')
    )
    is_primary = columns.BooleanColumn(
        verbose_name=_('Primary'),
        orderable=False,
    )
    tags = columns.TagColumn(
        url_name='dcim:macaddress_list'
    )
    actions = columns.ActionsColumn(
        extra_buttons=MACADDRESS_COPY_BUTTON
    )

    class Meta(PrimaryModelTable.Meta):
        model = models.MACAddress
        fields = (
            'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description', 'is_primary',
            'comments', 'tags', 'created', 'last_updated',
        )
        default_columns = (
            'pk', 'mac_address', 'is_primary', 'assigned_object_parent', 'assigned_object', 'description',
        )
