/**
 * MCP Server for Omada Controller
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import {
  OmadaClient,
  DevicesService,
  NetworksService,
  SitesService,
  FirewallService,
  SwitchService,
  RouterService,
  DeviceType,
} from 'omada-api';

export interface OmadaServerConfig {
  baseUrl: string;
  clientId: string;
  clientSecret: string;
  siteId?: string;
  verifySSL?: boolean;
}

export class OmadaServer {
  private server: Server;
  private client: OmadaClient;
  private devicesService: DevicesService;
  private networksService: NetworksService;
  private sitesService: SitesService;
  private firewallService: FirewallService;
  private switchService: SwitchService;
  private routerService: RouterService;

  constructor(config: OmadaServerConfig) {
    this.server = new Server(
      {
        name: 'omada-server',
        version: '1.0.0',
      }
    );

    this.client = new OmadaClient(config);
    this.devicesService = new DevicesService(this.client);
    this.networksService = new NetworksService(this.client);
    this.sitesService = new SitesService(this.client);
    this.firewallService = new FirewallService(this.client);
    this.switchService = new SwitchService(this.client);
    this.routerService = new RouterService(this.client);

    this.setupToolHandlers();
  }

  private setupToolHandlers() {
    // List tools
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'omada_list_devices',
          description: 'List all Omada devices (routers, switches, access points)',
          inputSchema: {
            type: 'object',
            properties: {
              deviceType: {
                type: 'string',
                enum: ['router', 'switch', 'ap', 'all'],
                description: 'Filter by device type',
                default: 'all',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional, uses default if not provided)',
              },
            },
          },
        },
        {
          name: 'omada_get_device',
          description: 'Get detailed information about a specific device',
          inputSchema: {
            type: 'object',
            properties: {
              deviceId: {
                type: 'string',
                description: 'Device ID',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['deviceId'],
          },
        },
        {
          name: 'omada_list_vlans',
          description: 'List all VLANs configured in the Omada Controller',
          inputSchema: {
            type: 'object',
            properties: {
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
          },
        },
        {
          name: 'omada_get_vlan',
          description: 'Get VLAN configuration details',
          inputSchema: {
            type: 'object',
            properties: {
              vlanId: {
                type: 'string',
                description: 'VLAN ID',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['vlanId'],
          },
        },
        {
          name: 'omada_reboot_device',
          description: 'Reboot a device',
          inputSchema: {
            type: 'object',
            properties: {
              deviceId: {
                type: 'string',
                description: 'Device ID to reboot',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['deviceId'],
          },
        },
        {
          name: 'omada_get_device_statistics',
          description: 'Get device statistics (CPU, memory, traffic)',
          inputSchema: {
            type: 'object',
            properties: {
              deviceId: {
                type: 'string',
                description: 'Device ID',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['deviceId'],
          },
        },
        {
          name: 'omada_list_firewall_rules',
          description: 'List firewall rules',
          inputSchema: {
            type: 'object',
            properties: {
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
          },
        },
        {
          name: 'omada_get_switch_ports',
          description: 'Get switch port configuration (for SG218R and other switches)',
          inputSchema: {
            type: 'object',
            properties: {
              deviceId: {
                type: 'string',
                description: 'Switch device ID',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['deviceId'],
          },
        },
        {
          name: 'omada_get_router_wan',
          description: 'Get router WAN port configuration (for ER605 and other routers)',
          inputSchema: {
            type: 'object',
            properties: {
              deviceId: {
                type: 'string',
                description: 'Router device ID',
              },
              siteId: {
                type: 'string',
                description: 'Site ID (optional)',
              },
            },
            required: ['deviceId'],
          },
        },
        {
          name: 'omada_list_sites',
          description: 'List all sites in the Omada Controller',
          inputSchema: {
            type: 'object',
            properties: {},
          },
        },
      ],
    }));

    // Handle tool calls
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      try {
        switch (name) {
          case 'omada_list_devices': {
            const deviceType = args?.deviceType as string || 'all';
            const siteId = args?.siteId as string | undefined;

            let devices;
            if (deviceType === 'all') {
              devices = await this.devicesService.listDevices({ siteId });
            } else {
              devices = await this.devicesService.listDevices({
                siteId,
                type: deviceType as DeviceType,
              });
            }

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(devices, null, 2),
                },
              ],
            };
          }

          case 'omada_get_device': {
            const deviceId = args?.deviceId as string;
            const siteId = args?.siteId as string | undefined;

            if (!deviceId) {
              throw new Error('deviceId is required');
            }

            const device = await this.devicesService.getDevice(deviceId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(device, null, 2),
                },
              ],
            };
          }

          case 'omada_list_vlans': {
            const siteId = args?.siteId as string | undefined;
            const vlans = await this.networksService.listVLANs(siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(vlans, null, 2),
                },
              ],
            };
          }

          case 'omada_get_vlan': {
            const vlanId = args?.vlanId as string;
            const siteId = args?.siteId as string | undefined;

            if (!vlanId) {
              throw new Error('vlanId is required');
            }

            const vlan = await this.networksService.getVLAN(vlanId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(vlan, null, 2),
                },
              ],
            };
          }

          case 'omada_reboot_device': {
            const deviceId = args?.deviceId as string;
            const siteId = args?.siteId as string | undefined;

            if (!deviceId) {
              throw new Error('deviceId is required');
            }

            await this.devicesService.rebootDevice(deviceId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: `Device ${deviceId} reboot initiated successfully`,
                },
              ],
            };
          }

          case 'omada_get_device_statistics': {
            const deviceId = args?.deviceId as string;
            const siteId = args?.siteId as string | undefined;

            if (!deviceId) {
              throw new Error('deviceId is required');
            }

            const stats = await this.devicesService.getDeviceStatistics(deviceId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(stats, null, 2),
                },
              ],
            };
          }

          case 'omada_list_firewall_rules': {
            const siteId = args?.siteId as string | undefined;
            const rules = await this.firewallService.listFirewallRules(siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(rules, null, 2),
                },
              ],
            };
          }

          case 'omada_get_switch_ports': {
            const deviceId = args?.deviceId as string;
            const siteId = args?.siteId as string | undefined;

            if (!deviceId) {
              throw new Error('deviceId is required');
            }

            const ports = await this.switchService.getSwitchPorts(deviceId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(ports, null, 2),
                },
              ],
            };
          }

          case 'omada_get_router_wan': {
            const deviceId = args?.deviceId as string;
            const siteId = args?.siteId as string | undefined;

            if (!deviceId) {
              throw new Error('deviceId is required');
            }

            const wanPorts = await this.routerService.getWANPorts(deviceId, siteId);

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(wanPorts, null, 2),
                },
              ],
            };
          }

          case 'omada_list_sites': {
            const sites = await this.sitesService.listSites();

            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify(sites, null, 2),
                },
              ],
            };
          }

          default:
            throw new Error(`Unknown tool: ${name}`);
        }
      } catch (error) {
        const errorMessage =
          error instanceof Error ? error.message : String(error);
        return {
          content: [
            {
              type: 'text',
              text: `Error: ${errorMessage}`,
            },
          ],
          isError: true,
        };
      }
    });
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('Omada MCP server running on stdio');
  }
}

