/**
 * RMM Device Resolver
 * Matches Veeam backup agent jobs to their Datto RMM device via:
 *   veeam_organizations.company_id → datto_rmm_sites.autotask_company_id (org match)
 *   veeam_backup_agents.name      ≈ datto_rmm_devices.hostname            (hostname match)
 *
 * Scoped to Desktop/Laptop device categories only — server jobs are handled separately.
 * Reusable by any service that needs to correlate Veeam jobs with RMM device state.
 */

import postgresClient from './postgres-client';

export interface RmmDeviceInfo {
  hostname: string;
  site_name: string;
  device_type_category: string;
  last_seen: Date | null;
  online: boolean;
}

/**
 * Bulk-resolve Veeam backup agent jobs to their matching Datto RMM devices.
 * Returns a Map keyed by job instance_uid. Jobs with no RMM match are absent.
 */
export async function resolveRmmDevicesForJobs(
  jobInstanceUids: string[]
): Promise<Map<string, RmmDeviceInfo>> {
  if (jobInstanceUids.length === 0) return new Map();

  // datto_rmm_sites.autotask_company_id is not reliably populated from the API,
  // so join via companies.company_name = datto_rmm_sites.name instead.
  // Datto sites are often named "Company - Location" while company_name is "Company",
  // so match exact OR site name starts with "company - ".
  // DISTINCT ON (job) prevents fanout when a company has multiple matching sites,
  // preferring the device with the most recent last_seen.
  const res = await postgresClient.query(`
    SELECT DISTINCT ON (j.instance_uid)
      j.instance_uid        AS job_instance_uid,
      rmm.hostname,
      rs.name               AS site_name,
      rmm.device_type_category,
      rmm.last_seen,
      rmm.online
    FROM veeam_backup_agent_jobs j
    JOIN veeam_backup_agents ba  ON ba.instance_uid  = j.backup_agent_uid
    JOIN veeam_organizations vo  ON vo.instance_uid  = j.organization_uid
    JOIN companies c             ON c.id             = vo.company_id
    JOIN datto_rmm_sites rs      ON LOWER(rs.name) = LOWER(c.company_name)
                                 OR LOWER(rs.name) LIKE LOWER(c.company_name) || ' - %'
    JOIN datto_rmm_devices rmm
      ON  rmm.site_id              = rs.id
      AND LOWER(rmm.hostname)      = LOWER(ba.name)
      AND rmm.device_type_category IN ('Desktop', 'Laptop')
      AND rmm.deleted              = false
    WHERE j.instance_uid = ANY($1)
    ORDER BY j.instance_uid, rmm.last_seen DESC NULLS LAST
  `, [jobInstanceUids]);

  const map = new Map<string, RmmDeviceInfo>();
  for (const row of res.rows) {
    map.set(row.job_instance_uid, {
      hostname:             row.hostname,
      site_name:            row.site_name,
      device_type_category: row.device_type_category,
      last_seen:            row.last_seen ? new Date(row.last_seen) : null,
      online:               row.online,
    });
  }
  return map;
}

/**
 * Returns true when the device should suppress RPO alerting.
 * A device is considered suppressed if it has been offline longer than one full
 * backup interval — meaning it was already offline when the backup was due to run.
 * No last_seen → not suppressed (device exists in RMM but has never reported; alert normally).
 */
export function isDeviceOfflineSuppressed(info: RmmDeviceInfo, intervalHours: number): boolean {
  if (!info.last_seen) return false;
  const hoursOffline = (Date.now() - info.last_seen.getTime()) / 3_600_000;
  return hoursOffline > intervalHours;
}

/**
 * Returns hours since the device was last seen by RMM, or null if never seen.
 */
export function hoursOffline(info: RmmDeviceInfo): number | null {
  if (!info.last_seen) return null;
  return (Date.now() - info.last_seen.getTime()) / 3_600_000;
}
