import * as interfaces from '../ts_interfaces/index.js';
import type { DcRouterApiClient } from './classes.dcrouterapiclient.js';

// =====================
// Sub-managers
// =====================

export class RadiusClientManager {
  private clientRef: DcRouterApiClient;

  constructor(clientRef: DcRouterApiClient) {
    this.clientRef = clientRef;
  }

  public async list(): Promise<Array<{
    name: string;
    ipRange: string;
    description?: string;
    enabled: boolean;
  }>> {
    const response = await this.clientRef.request<interfaces.requests.IReq_GetRadiusClients>(
      'getRadiusClients',
      this.clientRef.buildRequestPayload() as any,
    );
    return response.clients;
  }

  public async set(client: {
    name: string;
    ipRange: string;
    secret: string;
    description?: string;
    enabled: boolean;
  }): Promise<void> {
    const response = await this.clientRef.request<interfaces.requests.IReq_SetRadiusClient>(
      'setRadiusClient',
      this.clientRef.buildRequestPayload({ client }) as any,
    );
    if (!response.success) {
      throw new Error(response.message || 'Failed to set RADIUS client');
    }
  }

  public async remove(name: string): Promise<void> {
    const response = await this.clientRef.request<interfaces.requests.IReq_RemoveRadiusClient>(
      'removeRadiusClient',
      this.clientRef.buildRequestPayload({ name }) as any,
    );
    if (!response.success) {
      throw new Error(response.message || 'Failed to remove RADIUS client');
    }
  }
}

export class RadiusVlanManager {
  private clientRef: DcRouterApiClient;

  constructor(clientRef: DcRouterApiClient) {
    this.clientRef = clientRef;
  }

  public async list(): Promise<interfaces.requests.IReq_GetVlanMappings['response']> {
    return this.clientRef.request<interfaces.requests.IReq_GetVlanMappings>(
      'getVlanMappings',
      this.clientRef.buildRequestPayload() as any,
    );
  }

  public async set(mapping: {
    mac: string;
    vlan: number;
    description?: string;
    enabled: boolean;
  }): Promise<void> {
    const response = await this.clientRef.request<interfaces.requests.IReq_SetVlanMapping>(
      'setVlanMapping',
      this.clientRef.buildRequestPayload({ mapping }) as any,
    );
    if (!response.success) {
      throw new Error(response.message || 'Failed to set VLAN mapping');
    }
  }

  public async remove(mac: string): Promise<void> {
    const response = await this.clientRef.request<interfaces.requests.IReq_RemoveVlanMapping>(
      'removeVlanMapping',
      this.clientRef.buildRequestPayload({ mac }) as any,
    );
    if (!response.success) {
      throw new Error(response.message || 'Failed to remove VLAN mapping');
    }
  }

  public async updateConfig(options: {
    defaultVlan?: number;
    allowUnknownMacs?: boolean;
  }): Promise<{ defaultVlan: number; allowUnknownMacs: boolean }> {
    const response = await this.clientRef.request<interfaces.requests.IReq_UpdateVlanConfig>(
      'updateVlanConfig',
      this.clientRef.buildRequestPayload(options) as any,
    );
    if (!response.success) {
      throw new Error('Failed to update VLAN config');
    }
    return response.config;
  }

  public async testAssignment(mac: string): Promise<interfaces.requests.IReq_TestVlanAssignment['response']> {
    return this.clientRef.request<interfaces.requests.IReq_TestVlanAssignment>(
      'testVlanAssignment',
      this.clientRef.buildRequestPayload({ mac }) as any,
    );
  }
}

export class RadiusSessionManager {
  private clientRef: DcRouterApiClient;

  constructor(clientRef: DcRouterApiClient) {
    this.clientRef = clientRef;
  }

  public async list(filter?: {
    username?: string;
    nasIpAddress?: string;
    vlanId?: number;
  }): Promise<interfaces.requests.IReq_GetRadiusSessions['response']> {
    return this.clientRef.request<interfaces.requests.IReq_GetRadiusSessions>(
      'getRadiusSessions',
      this.clientRef.buildRequestPayload({ filter }) as any,
    );
  }

  public async disconnect(sessionId: string, reason?: string): Promise<void> {
    const response = await this.clientRef.request<interfaces.requests.IReq_DisconnectRadiusSession>(
      'disconnectRadiusSession',
      this.clientRef.buildRequestPayload({ sessionId, reason }) as any,
    );
    if (!response.success) {
      throw new Error(response.message || 'Failed to disconnect session');
    }
  }
}

// =====================
// Main RADIUS Manager
// =====================

export class RadiusManager {
  private clientRef: DcRouterApiClient;

  public clients: RadiusClientManager;
  public vlans: RadiusVlanManager;
  public sessions: RadiusSessionManager;

  constructor(clientRef: DcRouterApiClient) {
    this.clientRef = clientRef;
    this.clients = new RadiusClientManager(clientRef);
    this.vlans = new RadiusVlanManager(clientRef);
    this.sessions = new RadiusSessionManager(clientRef);
  }

  public async getAccountingSummary(
    startTime: number,
    endTime: number,
  ): Promise<interfaces.requests.IReq_GetRadiusAccountingSummary['response']['summary']> {
    const response = await this.clientRef.request<interfaces.requests.IReq_GetRadiusAccountingSummary>(
      'getRadiusAccountingSummary',
      this.clientRef.buildRequestPayload({ startTime, endTime }) as any,
    );
    return response.summary;
  }

  public async getStatistics(): Promise<interfaces.requests.IReq_GetRadiusStatistics['response']> {
    return this.clientRef.request<interfaces.requests.IReq_GetRadiusStatistics>(
      'getRadiusStatistics',
      this.clientRef.buildRequestPayload() as any,
    );
  }
}
