"""Command line tool to communicate with the NetBox API."""
from typing import Any, Dict, List

import click
import pandas as pd

from gso.services.netbox_client import NetboxClient


def convert_to_table(data: List[Dict[str, Any]], fields: List[str]) -> pd.DataFrame:
    if not data:
        raise ValueError("No data is available for your request")

    df = pd.DataFrame(data)
    if fields:
        df = df[fields]

    return df


@click.group()
def cli() -> None:
    pass


@cli.group()
def create() -> None:
    pass


@create.command()
@click.option("--fqdn", prompt="Enter device name", help="Device name")
@click.option("--model", default="vmx", help="Device model")
def device(fqdn: str, model: str) -> None:
    click.echo(f"Creating device: fqdn={fqdn}, model={model}")
    new_device = NetboxClient().create_device(fqdn, model)
    click.echo(new_device)


@create.command()
@click.option("--name", help="Interface name")
@click.option("--type", default="10gbase-t", help="Interface type, default is 10GBASE-T")
@click.option("--speed", default="1000", help="Interface speed , default is 1000")
@click.option("--fqdn", help="Device where to create interface")
def interface(name: str, type: str, speed: str, fqdn: str) -> None:
    click.echo(f"Creating interface: name={name}, speed={speed}, fqdn={fqdn}")
    new_interface = NetboxClient().create_interface(name, type, speed, fqdn)
    click.echo(new_interface)


@create.command()
@click.option("--name", help="Manufacturer name")
@click.option("--slug", help="Short name for manufacturer")
def manufacturer(name: str, slug: str) -> None:
    click.echo(f"Creating manufacturer: name={name}")
    manufacturer = NetboxClient().create_device_manufacturer(name, slug)
    click.echo(manufacturer)


@create.command()
@click.option("--manufacturer", help="Manufacturer for device")
@click.option("--model", help="Model for device")
@click.option("--slug", help="Short name for manufacturer")
def device_type(manufacturer: str, model: str, slug: str) -> None:
    click.echo(f"Creating device type: manufacturer={manufacturer} model = {model}")
    device_type = NetboxClient().create_device_type(manufacturer, model, slug)
    click.echo(device_type)


@create.command()
@click.option("--name", help="Name for device role")
@click.option("--slug", help="Short name for device role")
def device_role(name: str, slug: str) -> None:
    click.echo(f"Creating device role: name={name}")
    device_role = NetboxClient().create_device_role(name, slug)
    click.echo(device_role)


@create.command()
@click.option("--name", help="Name for device site")
@click.option("--slug", help="Short name for device site")
def device_site(name: str, slug: str) -> None:
    click.echo(f"Creating device site: name={name}")
    device_site = NetboxClient().create_device_site(name, slug)
    click.echo(device_site)


create.add_command(device)
create.add_command(interface)
create.add_command(manufacturer)
create.add_command(device_type)
create.add_command(device_role)
create.add_command(device_site)


# Define list commands here
@cli.group()
def list() -> None:
    pass


@list.command()
@click.option("--fqdn", help="Device name to list interfaces")
@click.option("--speed", default="1000", help="Interface speed to list interfaces (default 1000=1G)")
def interfaces(fqdn: str, speed: str) -> None:
    click.echo(f"Listing all interfaces for: device with fqdn={fqdn}, speed={speed}")
    interface_list = NetboxClient().get_interfaces_by_device(fqdn, speed)
    display_fields = ["name", "enabled", "mark_connected", "custom_fields", "lag", "speed"]
    iface_list = []
    for iface in interface_list:
        iface_list.append(dict(iface))

    table = convert_to_table(iface_list, display_fields)
    click.echo(table)


@list.command()
def devices() -> None:
    click.echo("Listing all devices:")
    device_list = NetboxClient().get_all_devices()
    display_fields = ["name", "device_type"]
    devices = []
    for device in device_list:
        devices.append(dict(device))

    table = convert_to_table(devices, display_fields)
    click.echo(table)


list.add_command(interfaces)
list.add_command(devices)


# Define delete commands here
@cli.group()
def delete() -> None:
    pass


@delete.command()  # type: ignore[no-redef]
@click.option("--fqdn", help="Name of device to delete")
def device(fqdn: str) -> None:
    click.echo(f"Deleting device: device={fqdn}")
    NetboxClient().delete_device(fqdn)


@delete.command()  # type: ignore[no-redef]
@click.option("--fqdn", help="Device name from where to get interface to delete")
@click.option("--iface", help="Name of interface name to delete")
def interface(fqdn: str, iface: str) -> None:
    click.echo(f"Deleting interface: device={fqdn}, interface name={iface}")
    NetboxClient().delete_interface(fqdn, iface)


delete.add_command(device)
delete.add_command(interface)


# The action command
@cli.group()
def action() -> None:
    pass


@action.command()
@click.option("--fqdn", help="Device name from where to get interface to edit")
@click.option("--iface", help="Interface name to edit")
def reserve_interface(fqdn: str, iface: str) -> None:
    click.echo(f"Reserving interface: device ={fqdn}, interface name={iface}")
    reserved_iface = NetboxClient().reserve_interface(fqdn, iface)
    click.echo(reserved_iface)


@action.command()
@click.option("--fqdn", help="Device name from where to get interface to edit")
@click.option("--iface", help="Interface name to edit")
def free_interface(fqdn: str, iface: str) -> None:
    click.echo(f"Freeing interface: device={fqdn}, interface name={iface}")
    freed_iface = NetboxClient().free_interface(fqdn, iface)
    click.echo(freed_iface)


@action.command()
@click.option("--fqdn", help="Device name from where to get interface to edit")
@click.option("--iface", help="Interface name to edit")
def allocate_interface(fqdn: str, iface: str) -> None:
    click.echo(f"Allocating interface: device={fqdn}, interface name={iface}")
    allocated_iface = NetboxClient().allocate_interface(fqdn, iface)
    click.echo(allocated_iface)


@action.command()
@click.option("--fqdn", help="Device name from where to get interface to edit")
@click.option("--iface", help="Interface name to edit")
def deallocate_interface(fqdn: str, iface: str) -> None:
    click.echo(f"Deallocating interface: device={fqdn}, interface name={iface}")
    deallocated_iface = NetboxClient().free_interface(fqdn, iface)
    click.echo(deallocated_iface)


@action.command()
@click.option("--fqdn", help="Device name from where to get physical interface to attach LAG")
@click.option("--lag", help="LAG name to attach physical interface to")
@click.option("--iface", help="Interface name to attach to LAG")
def attach_interface_to_lag(fqdn: str, lag: str, iface: str) -> None:
    click.echo(f"Attaching LAG to physical interface: device={fqdn}, LAG name={lag}, interface name={iface}")
    attached_iface = NetboxClient().attach_interface_to_lag(fqdn, lag, iface)
    click.echo(attached_iface)


action.add_command(reserve_interface)
action.add_command(free_interface)
action.add_command(allocate_interface)
action.add_command(deallocate_interface)
action.add_command(attach_interface_to_lag)


if __name__ == "__main__":
    cli()