import axios from 'axios';
import https from 'https';

export class OpnsenseService {
  private baseUrl: string;
  private apiKey: string;
  private apiSecret: string;
  private client: any;

  constructor(ipAddress: string, apiKey: string, apiSecret: string) {
    // Assuming HTTPS access to OPNsense, might need to adjust port if custom
    this.baseUrl = `https://${ipAddress}/api`;
    this.apiKey = apiKey;
    this.apiSecret = apiSecret;

    // OPNsense uses basic auth with API Key and Secret
    // We ignore SSL errors because OPNsense often has self-signed certs
    const httpsAgent = new https.Agent({ rejectUnauthorized: false });
    
    this.client = axios.create({
      baseURL: this.baseUrl,
      auth: {
        username: this.apiKey,
        password: this.apiSecret,
      },
      httpsAgent,
    });
  }

  /**
   * Health check to test API connectivity
   */
  async testConnection(): Promise<boolean> {
    try {
      // Fetching core firmware info as a simple ping
      const response = await this.client.get('/core/firmware/info');
      return response.status === 200;
    } catch (error) {
      console.error('OPNsense API Connection Error:', error);
      return false;
    }
  }

  /**
   * Captive Portal: Add or update a voucher/user session
   * This allows the hotspot system to authenticate a user automatically via API
   */
  async authHotspotUser(zoneId: string, username: string, ipAddress: string): Promise<any> {
    try {
      // POST /api/captiveportal/session/connect/
      const payload = {
        zoneid: zoneId,
        user: username,
        ip: ipAddress,
      };
      
      // OPNsense expects URL encoded form data or specific JSON structure depending on the endpoint
      // Using generic captiveportal session connect endpoint
      const response = await this.client.post(`/captiveportal/session/connect`, payload);
      return response.data;
    } catch (error) {
      console.error('Error authenticating hotspot user:', error);
      throw new Error('Could not authenticate hotspot user on OPNsense');
    }
  }

  /**
   * Captive Portal: Disconnect a user
   */
  async disconnectHotspotUser(zoneId: string, sessionId: string): Promise<any> {
    try {
      const payload = {
        zoneid: zoneId,
        sessionid: sessionId
      };
      const response = await this.client.post(`/captiveportal/session/disconnect`, payload);
      return response.data;
    } catch (error) {
      console.error('Error disconnecting hotspot user:', error);
      throw new Error('Could not disconnect hotspot user on OPNsense');
    }
  }

  /**
   * Traffic Shaper: Add a rule (e.g. for speed limits)
   */
  async addShaperRule(ruleData: any): Promise<any> {
    try {
      const response = await this.client.post('/trafficshaper/rule/addRule', { rule: ruleData });
      
      // Apply the changes (shaper requires an explicit apply call)
      await this.client.post('/trafficshaper/service/reconfigure');
      
      return response.data;
    } catch (error) {
      console.error('Error adding shaper rule:', error);
      throw new Error('Could not add traffic shaper rule on OPNsense');
    }
  }
}
