/**
 * Step Executor: enrich_vspc
 * Queries Veeam VSPC (API + local DB) for backup status of a device.
 *
 * Config:
 *   lookup_by: 'device_name' | 'organization_uid'
 *   source_field: template string for the lookup value
 *
 * Outputs to context:
 *   vspc_found, vspc_agent_jobs, vspc_server_jobs, vspc_workloads,
 *   vspc_last_job_status, vspc_last_success, vspc_failure_message,
 *   vspc_restore_points, vspc_backed_up_size, vspc_free_space,
 *   vspc_alarms, vspc_summary
 */

import { registerStepExecutor } from '../pipeline-engine';
import { postgresClient } from '../postgres-client';
import { StepExecutorResult, PipelineStep, PipelineContext } from '../../types/pipeline';

registerStepExecutor('enrich_vspc', async (
  step: PipelineStep,
  context: PipelineContext,
  executionId: number
): Promise<StepExecutorResult> => {
  const config = step.config as {
    lookup_by?: string;
    source_field?: string;
  };

  const lookupBy = config.lookup_by || 'device_name';
  const sourceValue = config.source_field || '';

  if (!sourceValue) {
    return { success: false, output: { vspc_found: false }, error: 'source_field is required' };
  }

  try {
    // ---- 1. Query local DB for backup agent jobs matching this device ----
    let agentJobs: any[] = [];
    let serverJobs: any[] = [];
    let workloads: any[] = [];
    let alarms: any[] = [];

    if (lookupBy === 'device_name') {
      // Match by agent name (agent name often = hostname)
      const agentResult = await postgresClient.query(
        `SELECT baj.*, ba.name as agent_name, ba.status as agent_status,
                ba.agent_platform, ba.version as agent_version,
                vo.name as org_name, vo.company_id
         FROM veeam_backup_agent_jobs baj
         LEFT JOIN veeam_backup_agents ba ON ba.instance_uid = baj.backup_agent_uid
         LEFT JOIN veeam_organizations vo ON vo.instance_uid = baj.organization_uid
         WHERE LOWER(ba.name) LIKE LOWER($1)
            OR LOWER(baj.name) LIKE LOWER($1)
         ORDER BY baj.last_run DESC NULLS LAST`,
        [`%${sourceValue}%`]
      );
      agentJobs = agentResult.rows;

      // Check protected workloads (VM-level)
      const workloadResult = await postgresClient.query(
        `SELECT pw.*, bj.name as job_name, bj.status as job_status,
                bj.last_run as job_last_run, bj.failure_message as job_failure_message
         FROM veeam_protected_workloads pw
         LEFT JOIN veeam_backup_jobs bj ON bj.instance_uid = pw.job_uid
         WHERE LOWER(pw.name) LIKE LOWER($1)
         ORDER BY pw.latest_restore_point_date DESC NULLS LAST`,
        [`%${sourceValue}%`]
      );
      workloads = workloadResult.rows;

      // Check backup server jobs that might reference this device
      const serverJobResult = await postgresClient.query(
        `SELECT bj.*, vo.name as org_name, vo.company_id
         FROM veeam_backup_jobs bj
         LEFT JOIN veeam_organizations vo ON vo.instance_uid = bj.organization_uid
         WHERE LOWER(bj.name) LIKE LOWER($1)
            OR LOWER(bj.destination) LIKE LOWER($1)
         ORDER BY bj.last_run DESC NULLS LAST`,
        [`%${sourceValue}%`]
      );
      serverJobs = serverJobResult.rows;

      // Check active alarms for this device
      const alarmResult = await postgresClient.query(
        `SELECT * FROM veeam_alarms
         WHERE LOWER(object_name) LIKE LOWER($1)
            OR LOWER(object_computer_name) LIKE LOWER($1)
         ORDER BY last_activation_time DESC NULLS LAST`,
        [`%${sourceValue}%`]
      );
      alarms = alarmResult.rows;
    }

    // ---- 2. Build summary ----
    const allJobs = [...agentJobs, ...serverJobs];
    const latestJob = allJobs[0] || null;
    const failedJobs = allJobs.filter(j => j.status === 'Failed');
    const warningJobs = allJobs.filter(j => j.status === 'Warning');
    const successJobs = allJobs.filter(j => j.status === 'Success');

    // Find last successful backup across all job types
    const lastSuccess = allJobs.find(j => j.status === 'Success');
    const lastSuccessDate = lastSuccess?.last_run || lastSuccess?.last_end_time || null;

    // Calculate hours since last success
    let hoursSinceSuccess: number | null = null;
    if (lastSuccessDate) {
      hoursSinceSuccess = Math.round((Date.now() - new Date(lastSuccessDate).getTime()) / 3600000);
    }

    // Aggregate restore points and sizes
    const totalRestorePoints = agentJobs.reduce((sum, j) => sum + (j.restore_points || 0), 0)
      + workloads.reduce((sum, w) => sum + (w.restore_points || 0), 0);

    const totalBackedUpSize = agentJobs.reduce((sum, j) => sum + (j.backed_up_size || 0), 0);

    const summary = [
      `Device: ${sourceValue}`,
      `Agent Jobs: ${agentJobs.length} (${successJobs.length} success, ${failedJobs.length} failed, ${warningJobs.length} warning)`,
      `Server Jobs: ${serverJobs.length}`,
      `Protected Workloads: ${workloads.length}`,
      `Active Alarms: ${alarms.length}`,
      `Total Restore Points: ${totalRestorePoints}`,
      latestJob ? `Latest Job: "${latestJob.name}" — ${latestJob.status} at ${latestJob.last_run || 'never'}` : 'No jobs found',
      latestJob?.failure_message ? `Failure: ${latestJob.failure_message}` : null,
      lastSuccessDate ? `Last Success: ${lastSuccessDate} (${hoursSinceSuccess}h ago)` : 'No successful backup found',
      alarms.length > 0 ? `Alarms: ${alarms.map((a: any) => `${a.alarm_area}: ${a.last_activation_message}`).join('; ')}` : null,
    ].filter(Boolean).join('\n');

    const found = agentJobs.length > 0 || serverJobs.length > 0 || workloads.length > 0;

    return {
      success: true,
      output: {
        vspc_found: found,
        vspc_agent_jobs: agentJobs.map(j => ({
          name: j.name,
          status: j.status,
          last_run: j.last_run,
          last_end_time: j.last_end_time,
          last_duration: j.last_duration,
          failure_message: j.failure_message,
          backup_mode: j.backup_mode,
          destination: j.destination,
          restore_points: j.restore_points,
          backed_up_size: j.backed_up_size,
          free_space: j.free_space,
          is_enabled: j.is_enabled,
          agent_name: j.agent_name,
          agent_status: j.agent_status,
          org_name: j.org_name,
        })),
        vspc_server_jobs: serverJobs.map(j => ({
          name: j.name,
          status: j.status,
          last_run: j.last_run,
          failure_message: j.failure_message,
          type: j.type,
          destination: j.destination,
          bottleneck: j.bottleneck,
          backup_chain_size: j.backup_chain_size,
        })),
        vspc_workloads: workloads.map(w => ({
          name: w.name,
          restore_points: w.restore_points,
          latest_restore_point_date: w.latest_restore_point_date,
          latest_restore_point_size: w.latest_restore_point_size,
          malware_state: w.malware_state,
          job_name: w.job_name,
          job_status: w.job_status,
        })),
        vspc_alarms: alarms.map(a => ({
          area: a.alarm_area,
          message: a.last_activation_message,
          status: a.last_activation_status,
          time: a.last_activation_time,
          object_name: a.object_name,
        })),
        vspc_last_job_status: latestJob?.status || null,
        vspc_last_success: lastSuccessDate,
        vspc_hours_since_success: hoursSinceSuccess,
        vspc_failure_message: latestJob?.failure_message || null,
        vspc_restore_points: totalRestorePoints,
        vspc_backed_up_size: totalBackedUpSize,
        vspc_alarm_count: alarms.length,
        vspc_failed_job_count: failedJobs.length,
        vspc_summary: summary,
      },
    };
  } catch (error) {
    const msg = error instanceof Error ? error.message : String(error);
    return { success: false, output: { vspc_found: false }, error: `VSPC enrichment failed: ${msg}` };
  }
});
