/**
 * Resolve which Datto RMM device an RMM Overshell script should run against.
 *
 * For site-anchored scripts: pick the Wulf Nurse Production endpoint
 * (hostname matching `LLLCCCWNPNN` — 6 letters + WNP + 2 digits) for the
 * client. Prefer online devices and lowest numeric suffix (WNP01 over
 * WNP02 etc.) so we hit the canonical endpoint deterministically.
 *
 * For asset-self: caller supplies the device_uid; we look up hostname /
 * online state for telemetry only.
 */

import postgresClient from '@/lib/services/postgres-client';

export interface ResolvedTarget {
  device_uid: string;
  hostname: string | null;
  online: boolean;
}

/**
 * Wulf Nurse Production endpoint pattern.
 *   LLL = location code (3 letters)
 *   CCC = client code (3 letters)
 *   WNP = literal
 *   NN  = numeric suffix
 *   e.g. YNGHYNWNP01 → Youngstown / Hynes / WNP / 01
 */
const WNP_REGEX = /^[A-Z]{3}[A-Z]{3}WNP\d{2}$/i;

interface SiteRow {
  id: number;
  name: string;
  device_count: number;
}

interface DeviceRow {
  uid: string;
  hostname: string | null;
  online: boolean;
  site_id: number;
  site_device_count: number;
}

/**
 * Find every Datto RMM site that maps to the given Autotask company.
 *
 * Two paths because the autotask_company_id FK on datto_rmm_sites isn't
 * always populated — many sites only carry the autotask_company_name. We
 * match on either the FK or a case-insensitive name match against
 * companies.company_name.
 *
 * Multi-site clients (e.g. Hynes Industries: Youngstown + Painesville +
 * Kokomo) return multiple rows; the caller combines WNPs across all of
 * them.
 */
async function findDattoSitesForCompany(
  companyId: string | number
): Promise<SiteRow[]> {
  const res = await postgresClient.query<SiteRow>(
    `SELECT s.id, s.name, COALESCE(s.number_of_devices, 0) AS device_count
       FROM datto_rmm_sites s
       LEFT JOIN companies c ON c.id = $1::bigint
      WHERE s.autotask_company_id = $1::bigint
         OR (
           c.company_name IS NOT NULL
           AND s.autotask_company_name IS NOT NULL
           AND LOWER(s.autotask_company_name) = LOWER(c.company_name)
         )
      ORDER BY device_count DESC, s.name`,
    [companyId]
  );
  return res.rows;
}

async function findWnpDevicesForSites(siteIds: number[]): Promise<DeviceRow[]> {
  if (siteIds.length === 0) return [];
  const res = await postgresClient.query<DeviceRow>(
    `SELECT d.uid, d.hostname, d.online, d.site_id,
            COALESCE(s.number_of_devices, 0) AS site_device_count
       FROM datto_rmm_devices d
       JOIN datto_rmm_sites s ON s.id = d.site_id
      WHERE d.site_id = ANY($1::int[])
        AND d.hostname ~* '^[A-Z]{3}[A-Z]{3}WNP[0-9]{2}$'`,
    [siteIds]
  );
  return res.rows.filter((r) => r.hostname && WNP_REGEX.test(r.hostname));
}

export async function resolveSiteAnchorTarget(
  companyId: string | number
): Promise<ResolvedTarget | null> {
  const sites = await findDattoSitesForCompany(companyId);
  if (sites.length === 0) return null;
  const devices = await findWnpDevicesForSites(sites.map((s) => s.id));
  if (devices.length === 0) return null;
  // Pick: online > offline; site with more devices (proxy for "main
  // location"); lowest numeric suffix (WNP01 over WNP02).
  devices.sort((a, b) => {
    if (a.online !== b.online) return a.online ? -1 : 1;
    if (a.site_device_count !== b.site_device_count) {
      return b.site_device_count - a.site_device_count;
    }
    const suffixA = parseInt((a.hostname ?? '').slice(-2), 10);
    const suffixB = parseInt((b.hostname ?? '').slice(-2), 10);
    if (Number.isNaN(suffixA) || Number.isNaN(suffixB)) return 0;
    return suffixA - suffixB;
  });
  const pick = devices[0];
  return {
    device_uid: pick.uid,
    hostname: pick.hostname,
    online: pick.online,
  };
}

/**
 * Return ALL matching WNPs across every Datto site for the company, with
 * their site context. The site-discovery page can show this so the user
 * sees every available endpoint — Hynes has Youngstown, Kokomo,
 * Painesville WNPs and they're all valid targets for some scripts.
 */
export async function listSiteAnchorTargets(
  companyId: string | number
): Promise<
  Array<
    ResolvedTarget & { site_id: number; site_name: string; site_device_count: number }
  >
> {
  const sites = await findDattoSitesForCompany(companyId);
  if (sites.length === 0) return [];
  const devices = await findWnpDevicesForSites(sites.map((s) => s.id));
  const siteNameById = new Map(sites.map((s) => [s.id, s.name]));
  return devices
    .sort((a, b) => {
      if (a.online !== b.online) return a.online ? -1 : 1;
      return b.site_device_count - a.site_device_count;
    })
    .map((d) => ({
      device_uid: d.uid,
      hostname: d.hostname,
      online: d.online,
      site_id: d.site_id,
      site_name: siteNameById.get(d.site_id) ?? '',
      site_device_count: d.site_device_count,
    }));
}

export async function resolveAssetSelfTarget(
  deviceUid: string
): Promise<ResolvedTarget> {
  const res = await postgresClient.query<DeviceRow>(
    `SELECT uid, hostname, online
       FROM datto_rmm_devices
      WHERE uid = $1
      LIMIT 1`,
    [deviceUid]
  );
  if (res.rowCount === 0) {
    return { device_uid: deviceUid, hostname: null, online: false };
  }
  return {
    device_uid: res.rows[0].uid,
    hostname: res.rows[0].hostname,
    online: res.rows[0].online,
  };
}

/**
 * Resolve a Datto device by hostname (case-insensitive). Used when the
 * caller wants to target the audited Configuration's hostname rather than
 * a known device_uid.
 */
export async function resolveDeviceByHostname(
  hostname: string
): Promise<ResolvedTarget | null> {
  const res = await postgresClient.query<DeviceRow>(
    `SELECT uid, hostname, online
       FROM datto_rmm_devices
      WHERE LOWER(hostname) = LOWER($1)
      LIMIT 1`,
    [hostname]
  );
  if (res.rowCount === 0) return null;
  return {
    device_uid: res.rows[0].uid,
    hostname: res.rows[0].hostname,
    online: res.rows[0].online,
  };
}

export const _TARGET_RESOLVER_INTERNALS = { WNP_REGEX };
