import { db, ONU, SupportTicket } from '../../database/db';
import { SnmpScraperEngine } from './snmp-scraper';
import { LaserDiagnosticResult, UnregisteredOnuAlert } from './olt.types';

export class OltService {
  /**
   * Scrapes ONU optical laser data across all configured OLT nodes.
   * Updates health status, records warning logs, and executes automated tickets & Telegram alerts on critical faults.
   */
  public static async runLaserDiagnosticsScrape(): Promise<LaserDiagnosticResult[]> {
    const results: LaserDiagnosticResult[] = [];
    const now = new Date().toISOString();

    for (const olt of db.olts) {
      if (olt.status === 'offline') continue;

      const polledMetrics = await SnmpScraperEngine.pollOltOpticalMetrics(
        olt.ip_address,
        olt.brand,
        olt.snmp_community
      );

      for (const metric of polledMetrics) {
        let onu = db.onus.find(o => o.mac_serial === metric.macSerial);
        if (!onu) continue;

        const health = SnmpScraperEngine.calculateLaserHealth(metric.rxPower);
        onu.rx_power_dbm = Number(metric.rxPower.toFixed(2));
        onu.tx_power_dbm = Number(metric.txPower.toFixed(2));
        onu.laser_status = health.status;
        onu.last_scraped_at = now;

        const subscriber = onu.subscriber_id ? db.subscribers.find(s => s.id === onu.subscriber_id) : undefined;
        let ticketIdCreated: string | undefined = undefined;
        let telegramPushed = false;
        let actionTaken = 'Metric Logged Normal';

        if (health.status === 'warning') {
          actionTaken = 'Automated Metric Warning Logged';
          db.logAudit('WORKER', 'LASER_SCRAPER', 'ONU_LASER_WARNING_ATTENUATION', {
            macSerial: onu.mac_serial,
            rxPower: onu.rx_power_dbm,
            subscriber: subscriber?.username
          });
        } else if (health.status === 'critical_fault') {
          // Check if an open critical ticket already exists for this subscriber
          const existingTicket = db.support_tickets.find(
            t => t.subscriber_id === subscriber?.id && t.status === 'open' && t.category === 'Red Light on Router / LOS'
          );

          if (!existingTicket && subscriber) {
            ticketIdCreated = `tick_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`;
            const newTicket: SupportTicket = {
              id: ticketIdCreated,
              ticket_no: `TCK-${Date.now().toString().slice(-4)}`,
              tenant_id: subscriber.tenant_id,
              reseller_id: subscriber.reseller_id,
              subscriber_id: subscriber.id,
              title: `[AUTO-DETECT] Critical Optical Loss (LOS: ${onu.rx_power_dbm} dBm)`,
              category: 'Red Light on Router / LOS',
              severity: 'critical',
              status: 'open',
              description: `Automated Laser Diagnostics Engine detected critical optical power loss on ONU ${onu.mac_serial}. Optical RX reading is ${onu.rx_power_dbm} dBm (threshold: > -27.1 dBm). Address: ${subscriber.address || 'N/A'}. Contact: ${subscriber.phone}.`,
              assigned_to: 'NOC Emergency Dispatch',
              created_at: now,
              updated_at: now
            };
            db.support_tickets.unshift(newTicket);
          }

          // Push Simulated Telegram / WhatsApp Bot Alert
          telegramPushed = true;
          actionTaken = `Critical Line Fault: Created Ticket #${ticketIdCreated || 'Existing'} & Dispatched Telegram NOC Bot Alert`;
          
          db.logAudit('WORKER', 'LASER_SCRAPER', 'CRITICAL_LINE_FAULT_TELEGRAM_PUSH', {
            macSerial: onu.mac_serial,
            rxPower: onu.rx_power_dbm,
            subscriberUsername: subscriber?.username,
            subscriberPhone: subscriber?.phone,
            ticketId: ticketIdCreated,
            telegramPayload: {
              bot: 'NexGenNOCAlertBot',
              targetChat: '@ISP_Field_Engineers',
              text: `🚨 CRITICAL FIBER FAULT: Subscriber ${subscriber?.full_name || 'N/A'} (${subscriber?.username || 'Unassigned'}) - RX: ${onu.rx_power_dbm} dBm. Phone: ${subscriber?.phone}`
            }
          });
        }

        results.push({
          onuId: onu.id,
          macSerial: onu.mac_serial,
          subscriberUsername: subscriber?.username,
          subscriberName: subscriber?.full_name,
          subscriberPhone: subscriber?.phone,
          rxPowerDbm: onu.rx_power_dbm,
          txPowerDbm: onu.tx_power_dbm,
          status: health.status,
          colorCode: health.colorCode,
          label: health.label,
          actionTaken,
          ticketIdCreated,
          telegramAlertPushed: telegramPushed,
          scrapedAt: now
        });
      }
    }

    db.persist();
    return results;
  }

  /**
   * Fetches unconfigured / unregistered ONUs discovered by the background listener
   */
  public static getUnregisteredOnus(): UnregisteredOnuAlert[] {
    const unregs = db.onus.filter(o => !o.is_registered || !o.subscriber_id);
    return unregs.map(onu => {
      const olt = db.olts.find(o => o.id === onu.olt_id);
      const ponPort = db.pon_ports.find(p => p.id === onu.pon_port_id);
      return {
        onuId: onu.id,
        oltId: onu.olt_id,
        oltName: olt ? olt.name : 'Unknown OLT',
        ponPortId: onu.pon_port_id,
        ponPortNumber: ponPort ? ponPort.port_number : 1,
        ponPortName: ponPort ? ponPort.port_name : 'PON Port',
        macSerial: onu.mac_serial,
        rxPowerDbm: onu.rx_power_dbm,
        discoveredAt: onu.discovered_at,
        message: `New Unregistered ONU (${onu.mac_serial}) Found on PON Port ${ponPort?.port_number || 1}`
      };
    });
  }

  /**
   * One-click binds an unregistered ONU hardware serial to an active subscriber profile
   */
  public static async bindOnuToSubscriber(onuId: string, subscriberId: string): Promise<boolean> {
    const onu = db.onus.find(o => o.id === onuId);
    const subscriber = db.subscribers.find(s => s.id === subscriberId);

    if (!onu || !subscriber) {
      throw new Error('Invalid ONU ID or Subscriber ID');
    }

    onu.subscriber_id = subscriber.id;
    onu.is_registered = true;
    subscriber.onu_id = onu.id;

    db.logAudit('SUPER_ADMIN', subscriber.id, 'ONU_BOUND_TO_SUBSCRIBER', {
      onuMac: onu.mac_serial,
      subscriberUsername: subscriber.username,
      ponPortId: onu.pon_port_id
    });

    db.persist();
    return true;
  }

  /**
   * Returns complete OLT hierarchy tree with PON ports and ONUs
   */
  public static getOltInfrastructureTree() {
    return db.olts.map(olt => {
      const ports = db.pon_ports.filter(p => p.olt_id === olt.id).map(port => {
        const boundOnus = db.onus.filter(o => o.pon_port_id === port.id).map(onu => {
          const sub = onu.subscriber_id ? db.subscribers.find(s => s.id === onu.subscriber_id) : undefined;
          return {
            ...onu,
            subscriber_username: sub?.username,
            subscriber_name: sub?.full_name,
            subscriber_status: sub?.status
          };
        });
        return {
          ...port,
          onus: boundOnus
        };
      });
      return {
        ...olt,
        pon_ports: ports
      };
    });
  }
}
