/**
 * Read/write the rmm_settings singleton row.
 *
 * Caches the discovered Overshell component_uid so we don't re-scan
 * components on every dispatch. The discover endpoint repopulates it.
 */

import postgresClient from '@/lib/services/postgres-client';
import { getDattoRMMClient } from '@/lib/services/datto-rmm-factory';

export interface RmmSettings {
  overshellComponentUid: string | null;
  overshellComponentName: string | null;
  overshellVariableName: string;
  discoveredAt: string | null;
  // Phase 4.3 — LogLift component cache.
  logliftComponentUid: string | null;
  logliftComponentName: string | null;
  logliftDiscoveredAt: string | null;
  updatedAt: string;
}

interface RawSettingsRow {
  overshell_component_uid: string | null;
  overshell_component_name: string | null;
  overshell_variable_name: string;
  discovered_at: Date | null;
  loglift_component_uid: string | null;
  loglift_component_name: string | null;
  loglift_discovered_at: Date | null;
  updated_at: Date;
}

function rowToSettings(r: RawSettingsRow): RmmSettings {
  return {
    overshellComponentUid: r.overshell_component_uid,
    overshellComponentName: r.overshell_component_name,
    overshellVariableName: r.overshell_variable_name,
    discoveredAt: r.discovered_at?.toISOString() ?? null,
    logliftComponentUid: r.loglift_component_uid,
    logliftComponentName: r.loglift_component_name,
    logliftDiscoveredAt: r.loglift_discovered_at?.toISOString() ?? null,
    updatedAt: r.updated_at.toISOString(),
  };
}

export async function getRmmSettings(): Promise<RmmSettings> {
  const res = await postgresClient.query<RawSettingsRow>(
    `SELECT overshell_component_uid, overshell_component_name,
            overshell_variable_name, discovered_at,
            loglift_component_uid, loglift_component_name, loglift_discovered_at,
            updated_at
       FROM rmm_settings WHERE id = true LIMIT 1`
  );
  if (res.rowCount === 0) {
    // Defensive: re-seed if the singleton row vanished somehow.
    await postgresClient.query(
      `INSERT INTO rmm_settings (id) VALUES (true) ON CONFLICT DO NOTHING`
    );
    return {
      overshellComponentUid: null,
      overshellComponentName: null,
      overshellVariableName: 'CommandLine',
      discoveredAt: null,
      logliftComponentUid: null,
      logliftComponentName: null,
      logliftDiscoveredAt: null,
      updatedAt: new Date().toISOString(),
    };
  }
  return rowToSettings(res.rows[0]);
}

/**
 * Force-discover the Overshell component via the Datto RMM API and persist
 * the uid + name. Idempotent. Returns the updated settings.
 */
export async function discoverOvershellComponent(): Promise<{
  settings: RmmSettings;
  discovered: { uid: string; name: string } | null;
}> {
  const client = getDattoRMMClient();
  const found = await client.findOvershellComponent();

  if (!found) {
    return { settings: await getRmmSettings(), discovered: null };
  }

  await postgresClient.query(
    `UPDATE rmm_settings
        SET overshell_component_uid = $1,
            overshell_component_name = $2,
            discovered_at = NOW(),
            updated_at = NOW()
      WHERE id = true`,
    [found.uid, found.name]
  );
  const settings = await getRmmSettings();
  return { settings, discovered: found };
}

export async function updateOvershellVariableName(name: string): Promise<RmmSettings> {
  await postgresClient.query(
    `UPDATE rmm_settings
        SET overshell_variable_name = $1,
            updated_at = NOW()
      WHERE id = true`,
    [name]
  );
  return getRmmSettings();
}

/**
 * Resolve the component_uid Pulse should use, discovering on demand if the
 * cache is empty. Throws if the component cannot be found at all.
 */
export async function resolveOvershellComponent(): Promise<{
  componentUid: string;
  variableName: string;
}> {
  let s = await getRmmSettings();
  if (!s.overshellComponentUid) {
    const result = await discoverOvershellComponent();
    if (!result.discovered) {
      throw new Error(
        'Overshell component not found in Datto RMM. Register a component whose name contains "overshell" or update the discovery pattern.'
      );
    }
    s = result.settings;
  }
  return {
    componentUid: s.overshellComponentUid as string,
    variableName: s.overshellVariableName,
  };
}

// =============================================================================
// Phase 4.3 — LogLift component discovery
// =============================================================================

/**
 * Match anything containing "loglift" or "eventlog" in the component
 * name. The user's existing tenant should have a registered Datto
 * component (matching one of these names) that owns the PowerShell
 * collector logic.
 */
const LOGLIFT_PATTERN = /loglift|eventlog/i;

export async function discoverLogliftComponent(): Promise<{
  settings: RmmSettings;
  discovered: { uid: string; name: string } | null;
}> {
  const client = getDattoRMMClient();
  const found = await client.findComponentByName(LOGLIFT_PATTERN);

  if (!found) {
    return { settings: await getRmmSettings(), discovered: null };
  }

  await postgresClient.query(
    `UPDATE rmm_settings
        SET loglift_component_uid = $1,
            loglift_component_name = $2,
            loglift_discovered_at = NOW(),
            updated_at = NOW()
      WHERE id = true`,
    [found.uid, found.name]
  );
  const settings = await getRmmSettings();
  return { settings, discovered: found };
}

/**
 * Resolve the LogLift component_uid Pulse should dispatch. Throws with a
 * helpful message if the component hasn't been discovered yet.
 */
export async function resolveLogliftComponent(): Promise<{ componentUid: string }> {
  let s = await getRmmSettings();
  if (!s.logliftComponentUid) {
    const result = await discoverLogliftComponent();
    if (!result.discovered) {
      throw new Error(
        'LogLift component not found in Datto RMM. Register a component whose name contains "loglift" or "eventlog" and re-run discovery from /admin/rmm-overshell.'
      );
    }
    s = result.settings;
  }
  return { componentUid: s.logliftComponentUid as string };
}
