/**
 * VCOM Alarm Service
 * 
 * Mục đích: Thu thập cảnh báo từ Meteocontrol V2 API và lưu vào MongoDB
 * 
 * Chức năng:
 * - Kết nối với Meteocontrol V2 API (OAuth)
 * - Thu thập alarms từ endpoint /v2/alarms
 * - Lưu vào MongoDB Alert collection với type 'VCOMAlarm'
 */

import { Project } from '../models/Project';
import { SystemSettings } from '../models/SystemSettings';
import { Alert } from '../models/Alert';
import mongoose from 'mongoose';

const V2_API_BASE_URL = 'https://api.meteocontrol.de/v2';

interface MeteocontrolV2Credentials {
  username: string;
  password: string;
  apiKey: string;
}

// OAuth Token Cache (reuse from kpiCollectorService if possible)
interface TokenCache {
  token: string;
  expiresAt: number;
}

let oauthTokenCache: TokenCache | null = null;
let tokenRequestPromise: Promise<string | null> | null = null;

/**
 * Get OAuth token for V2 API
 */
async function getOAuthToken(credentials: MeteocontrolV2Credentials): Promise<string | null> {
  // Check cache first
  if (oauthTokenCache && oauthTokenCache.expiresAt > Date.now()) {
    return oauthTokenCache.token;
  }

  // If request already in progress, wait for it
  if (tokenRequestPromise) {
    return await tokenRequestPromise;
  }

  // Start new token request
  tokenRequestPromise = (async () => {
    try {
      // console.log('[VCOM Alarm] Requesting new OAuth token...');
      
      const response = await fetch(`${V2_API_BASE_URL}/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'X-API-KEY': credentials.apiKey,
        },
        body: new URLSearchParams({
          grant_type: 'password',
          username: credentials.username,
          password: credentials.password,
          client_id: 'vcom-api',
          client_secret: 'AYB=~9_f-BvNoLt8+x=3maCq)>/?@Nom',
        }),
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`OAuth failed: ${response.status} ${errorText}`);
      }

      const data = (await response.json()) as { expires_in?: number; access_token?: string };
      const expiresIn = data.expires_in ?? 518400; // Default 6 days
      const expiresAt = Date.now() + (expiresIn - 300) * 1000; // Subtract 5 minutes for safety

      oauthTokenCache = {
        token: data.access_token ?? '',
        expiresAt,
      };

      const minutesUntilExpiry = Math.floor((expiresAt - Date.now()) / 1000 / 60);
      // console.log(`[VCOM Alarm] OAuth token cached, expires in ${minutesUntilExpiry} minutes`);

      return data.access_token ?? null;
    } catch (error: any) {
      // console.error('[VCOM Alarm] OAuth failed:', error.message);
      throw error;
    } finally {
      tokenRequestPromise = null;
    }
  })();

  return await tokenRequestPromise;
}

/**
 * Call V2 API with OAuth authentication
 */
async function callV2API(
  endpoint: string,
  credentials: MeteocontrolV2Credentials,
  useOAuth: boolean = true,
  token?: string | null
): Promise<any> {
  const url = `${V2_API_BASE_URL}${endpoint}`;
  
  let accessToken = token;
  if (useOAuth && !accessToken) {
    accessToken = await getOAuthToken(credentials);
  }

  const headers: Record<string, string> = {
    'X-API-KEY': credentials.apiKey,
  };

  if (useOAuth && accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  } else {
    // Basic Auth fallback
    const basicAuth = Buffer.from(`${credentials.username}:${credentials.password}`).toString('base64');
    headers['Authorization'] = `Basic ${basicAuth}`;
  }

  const response = await fetch(url, {
    method: 'GET',
    headers,
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`V2 API error: ${response.status} ${errorText}`);
  }

  return await response.json();
}

/**
 * Map VCOM alarm severity to Alert severity
 */
function mapSeverity(vcomSeverity: string): 'Info' | 'Warning' | 'Critical' {
  switch (vcomSeverity?.toLowerCase()) {
    case 'critical':
      return 'Critical';
    case 'high':
      return 'Warning';
    case 'normal':
    default:
      return 'Info';
  }
}

/**
 * Format alarm message from VCOM alarm data
 */
function formatAlarmMessage(alarm: any): string {
  const componentName = alarm.component?.name || alarm.component?.id || 'Thiết bị';
  const alarmTypeMap: Record<string, string> = {
    'total-outage': 'Mất điện hoàn toàn',
    'data-outage': 'Mất dữ liệu',
    'communication-outage': 'Mất kết nối',
    'misproduction': 'Sản xuất thấp',
    'string-outage': 'Mất chuỗi',
    'sensor-outage': 'Lỗi cảm biến',
    'battery-charge-level': 'Mức pin bất thường',
    'custom': 'Cảnh báo tùy chỉnh',
  };
  const alarmTypeText = alarmTypeMap[alarm.alarmType] || alarm.alarmType || 'Cảnh báo';
  
  let message = `${alarmTypeText} - ${componentName}`;
  if (alarm.affectedPower && alarm.affectedPower > 0) {
    message += ` (Ảnh hưởng ${alarm.affectedPower.toFixed(1)}% công suất)`;
  }
  if (alarm.losses && alarm.losses > 0) {
    message += ` - Ước tính mất ${alarm.losses.toFixed(2)} kWh`;
  }
  
  return message;
}

/**
 * Sync alarms from VCOM V2 API for a project
 */
export async function syncVCOMAlarmsForProject(
  projectId: string,
  options: { status?: 'open' | 'closed'; severity?: 'normal' | 'high' | 'critical' } = {}
): Promise<{ synced: number; errors: number }> {
  try {
    const project = await Project.findById(projectId);
    if (!project) {
      throw new Error(`Project ${projectId} not found`);
    }

    if (!project.meteocontrol?.systemKey) {
      // console.log(`[VCOM Alarm] Project ${projectId} does not have systemKey configured, skipping sync`);
      return { synced: 0, errors: 0 };
    }

    const systemKey = project.meteocontrol.systemKey;

    // Get V2 API credentials from SystemSettings
    const settings = await SystemSettings.findOne();
    if (!settings?.vcomApi?.username || !settings?.vcomApi?.password || !settings?.vcomApi?.apiKey) {
      throw new Error('V2 API credentials not configured in SystemSettings');
    }

    const v2Credentials: MeteocontrolV2Credentials = {
      username: settings.vcomApi.username,
      password: settings.vcomApi.password,
      apiKey: settings.vcomApi.apiKey,
    };

    // Build query parameters
    const queryParams = new URLSearchParams();
    queryParams.append('systemKey', systemKey);
    
    if (options.status) {
      queryParams.append('status', options.status);
    } else {
      queryParams.append('status', 'open'); // Default to open alarms only
    }
    
    if (options.severity) {
      queryParams.append('severity', options.severity);
    }

    // Get alarms from V2 API
    const endpoint = `/alarms?${queryParams.toString()}`;
    // console.log(`[VCOM Alarm] Fetching alarms for system ${systemKey}...`);
    
    const token = await getOAuthToken(v2Credentials);
    const response = await callV2API(endpoint, v2Credentials, true, token);
    
    if (!response?.data || !Array.isArray(response.data)) {
      // console.warn(`[VCOM Alarm] Invalid response format for system ${systemKey}`);
      return { synced: 0, errors: 0 };
    }

    const alarms = response.data;
    // console.log(`[VCOM Alarm] Found ${alarms.length} alarms for system ${systemKey}`);

    let synced = 0;
    let errors = 0;

    // Process each alarm
    for (const alarm of alarms) {
      try {
        // Check if alarm already exists
        const existingAlert = await Alert.findOne({
          type: 'VCOMAlarm',
          vcomAlarmId: alarm.id,
          systemKey: alarm.systemKey,
        });

        const severity = mapSeverity(alarm.severity);
        const message = formatAlarmMessage(alarm);
        const startedAt = alarm.startedAt ? new Date(alarm.startedAt) : undefined;

        const alertData: any = {
          type: 'VCOMAlarm',
          message,
          severity,
          isRead: false,
          vcomAlarmId: alarm.id,
          systemKey: alarm.systemKey,
          alarmType: alarm.alarmType,
          componentId: alarm.component?.id,
          componentType: alarm.component?.type,
          componentName: alarm.component?.name,
          startedAt,
          duration: alarm.duration,
          affectedPower: alarm.affectedPower,
          losses: alarm.losses,
          ticketId: alarm.ticketId,
          link: alarm.ticketId ? `/tickets/${alarm.ticketId}` : undefined,
        };

        if (existingAlert) {
          // Update existing alert
          await Alert.findByIdAndUpdate(existingAlert._id, {
            ...alertData,
            createdAt: existingAlert.createdAt, // Keep original createdAt
          });
        } else {
          // Create new alert
          await Alert.create(alertData);
        }

        synced++;
      } catch (error: any) {
        // console.error(`[VCOM Alarm] Error processing alarm ${alarm.id}:`, error.message);
        errors++;
      }
    }

    // console.log(`[VCOM Alarm] Synced ${synced} alarms for system ${systemKey} (${errors} errors)`);
    return { synced, errors };
  } catch (error: any) {
    // console.error(`[VCOM Alarm] Error syncing alarms for project ${projectId}:`, error.message);
    throw error;
  }
}

/**
 * Get alarms from V2 API (live, without saving to MongoDB)
 */
export async function getVCOMAlarmsLive(
  projectId: string,
  options: { status?: 'open' | 'closed'; severity?: 'normal' | 'high' | 'critical' } = {}
): Promise<any[]> {
  try {
    const project = await Project.findById(projectId);
    if (!project) {
      throw new Error(`Project ${projectId} not found`);
    }

    if (!project.meteocontrol?.systemKey) {
      // console.log(`[VCOM Alarm] Project ${projectId} does not have systemKey configured, returning empty array`);
      return [];
    }

    const systemKey = project.meteocontrol.systemKey;

    // Get V2 API credentials from SystemSettings
    const settings = await SystemSettings.findOne();
    if (!settings?.vcomApi?.username || !settings?.vcomApi?.password || !settings?.vcomApi?.apiKey) {
      throw new Error('V2 API credentials not configured in SystemSettings');
    }

    const v2Credentials: MeteocontrolV2Credentials = {
      username: settings.vcomApi.username,
      password: settings.vcomApi.password,
      apiKey: settings.vcomApi.apiKey,
    };

    // Build query parameters
    const queryParams = new URLSearchParams();
    queryParams.append('systemKey', systemKey);
    
    if (options.status) {
      queryParams.append('status', options.status);
    } else {
      queryParams.append('status', 'open'); // Default to open alarms only
    }
    
    if (options.severity) {
      queryParams.append('severity', options.severity);
    }

    // Get alarms from V2 API
    const endpoint = `/alarms?${queryParams.toString()}`;
    const token = await getOAuthToken(v2Credentials);
    const response = await callV2API(endpoint, v2Credentials, true, token);
    
    if (!response?.data || !Array.isArray(response.data)) {
      return [];
    }

    return response.data;
  } catch (error: any) {
    // console.error(`[VCOM Alarm] Error getting live alarms for project ${projectId}:`, error.message);
    throw error;
  }
}
