import * as plugins from '../plugins.js';
import * as interfaces from '../../ts_interfaces/index.js';
import { appState } from './shared.js';
import { getActionContext } from './login.js';
import { runBackgroundRefresh } from './shared.js';

export interface INetworkState {
  connections: interfaces.data.IConnectionInfo[];
  connectionsByIP: { [ip: string]: number };
  throughputRate: { bytesInPerSecond: number; bytesOutPerSecond: number };
  totalBytes: { in: number; out: number };
  topIPs: Array<{ ip: string; count: number }>;
  topIPsByBandwidth: Array<{ ip: string; count: number; bwIn: number; bwOut: number }>;
  topASNs: interfaces.data.IAsnActivity[];
  throughputByIP: Array<{ ip: string; in: number; out: number }>;
  ipIntelligence: interfaces.data.IIpIntelligenceRecord[];
  domainActivity: interfaces.data.IDomainActivity[];
  throughputHistory: Array<{ timestamp: number; in: number; out: number }>;
  requestsPerSecond: number;
  requestsTotal: number;
  backends: interfaces.data.IBackendInfo[];
  frontendProtocols: interfaces.data.IProtocolDistribution | null;
  backendProtocols: interfaces.data.IProtocolDistribution | null;
  lastUpdated: number;
  isLoading: boolean;
  error: string | null;
}

export const networkStatePart = await appState.getStatePart<INetworkState>(
  'network',
  {
    connections: [],
    connectionsByIP: {},
    throughputRate: { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
    totalBytes: { in: 0, out: 0 },
    topIPs: [],
    topIPsByBandwidth: [],
    topASNs: [],
    throughputByIP: [],
    ipIntelligence: [],
    domainActivity: [],
    throughputHistory: [],
    requestsPerSecond: 0,
    requestsTotal: 0,
    backends: [],
    frontendProtocols: null,
    backendProtocols: null,
    lastUpdated: 0,
    isLoading: false,
    error: null,
  },
  'soft'
);

export function refreshNetworkIpIntelligence(identity: interfaces.data.IIdentity, ipAddresses: string[]): void {
  const ips = [...new Set(ipAddresses.filter(Boolean))].slice(0, 100);
  if (ips.length === 0) return;

  runBackgroundRefresh('networkIpIntelligence', 'IP intelligence refresh failed:', async () => {
    const intelligenceRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_ListIpIntelligence
    >('/typedrequest', 'listIpIntelligence');
    const intelligenceResponse = await intelligenceRequest.fire({
      identity,
      ipAddresses: ips,
      limit: Math.max(100, ips.length),
    });
    networkStatePart.setState({
      ...networkStatePart.getState()!,
      ipIntelligence: intelligenceResponse.records || [],
    });
  });
}


// Fetch Network Stats Action
export const fetchNetworkStatsAction = networkStatePart.createAction(async (statePartArg): Promise<INetworkState> => {
  const context = getActionContext();
  const currentState = statePartArg.getState()!;
  if (!context.identity) return currentState;

  try {
    // Get network stats for throughput and IP data
    const networkStatsRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
      interfaces.requests.IReq_GetNetworkStats
    >('/typedrequest', 'getNetworkStats');

    const networkStatsResponse = await networkStatsRequest.fire({
      identity: context.identity,
    });

    // Use the connections data for the connection list
    // and network stats for throughput and IP analytics
    const connectionsByIP: { [ip: string]: number } = {};
    const throughputByIP = new Map<string, { in: number; out: number }>();
    for (const item of networkStatsResponse.throughputByIP || []) {
      throughputByIP.set(item.ip, { in: item.in, out: item.out });
    }
    
    // Build connectionsByIP from network stats if available
    if (networkStatsResponse.connectionsByIP && Array.isArray(networkStatsResponse.connectionsByIP)) {
      networkStatsResponse.connectionsByIP.forEach((item: { ip: string; count: number }) => {
        connectionsByIP[item.ip] = item.count;
      });
    }

    const connections: interfaces.data.IConnectionInfo[] = Object.entries(connectionsByIP).map(([ip, count]) => {
      const tp = throughputByIP.get(ip);
      return {
        id: `ip-${ip}`,
        remoteAddress: ip,
        localAddress: 'server',
        startTime: 0,
        protocol: 'https',
        state: 'connected',
        bytesReceived: tp?.in || 0,
        bytesSent: tp?.out || 0,
        connectionCount: count,
      };
    });

    refreshNetworkIpIntelligence(context.identity, [
      ...Object.keys(connectionsByIP),
      ...(networkStatsResponse.topIPs || []).map((item) => item.ip),
      ...(networkStatsResponse.topIPsByBandwidth || []).map((item) => item.ip),
    ]);

    return {
      connections,
      connectionsByIP,
      throughputRate: networkStatsResponse.throughputRate || { bytesInPerSecond: 0, bytesOutPerSecond: 0 },
      totalBytes: networkStatsResponse.totalDataTransferred
        ? { in: networkStatsResponse.totalDataTransferred.bytesIn, out: networkStatsResponse.totalDataTransferred.bytesOut }
        : { in: 0, out: 0 },
      topIPs: networkStatsResponse.topIPs || [],
      topIPsByBandwidth: networkStatsResponse.topIPsByBandwidth || [],
      topASNs: networkStatsResponse.topASNs || [],
      throughputByIP: networkStatsResponse.throughputByIP || [],
      ipIntelligence: currentState.ipIntelligence,
      domainActivity: networkStatsResponse.domainActivity || [],
      throughputHistory: networkStatsResponse.throughputHistory || [],
      requestsPerSecond: networkStatsResponse.requestsPerSecond || 0,
      requestsTotal: networkStatsResponse.requestsTotal || 0,
      backends: networkStatsResponse.backends || [],
      frontendProtocols: networkStatsResponse.frontendProtocols || null,
      backendProtocols: networkStatsResponse.backendProtocols || null,
      lastUpdated: Date.now(),
      isLoading: false,
      error: null,
    };
  } catch (error) {
    console.error('Failed to fetch network stats:', error);
    return {
      ...currentState,
      isLoading: false,
      error: error instanceof Error ? error.message : 'Failed to fetch network stats',
    };
  }
});

// ============================================================================
