/**
 * SecretsRotationJob — SOC 2 CC9.2 Secrets Rotation monitoring.
 *
 * Runs on a configurable interval (default: 1 hour) and queries for agent
 * credentials that are active and expiring within the next 7 days.
 * For each expiring credential, increments the `agentidp_credentials_expiring_soon_total`
 * Prometheus counter with the owning agent's ID so operators can alert and rotate
 * before secrets expire.
 *
 * The job is designed to be started once at application startup and runs for
 * the lifetime of the process. It does NOT rotate credentials automatically —
 * it only detects and reports expiry to enable proactive rotation workflows.
 *
 * Configuration:
 *   SECRETS_ROTATION_CHECK_INTERVAL_MS — interval in milliseconds (default: 3600000 = 1 hour)
 */

import { Pool, QueryResult } from 'pg';
import { credentialsExpiringSoonTotal } from '../metrics/registry.js';
import { updateControlStatus } from '../services/ComplianceStatusStore.js';

// ============================================================================
// Internal types
// ============================================================================

/** Row returned by the expiring credentials query. */
interface ExpiringCredentialRow {
  credential_id: string;
  client_id: string;
}

// ============================================================================
// Job
// ============================================================================

/** Default check interval: 1 hour in milliseconds. */
const DEFAULT_INTERVAL_MS = 3600000;

/** Number of days before expiry to start alerting. */
const EXPIRY_ALERT_DAYS = 7;

/**
 * Queries for credentials expiring within EXPIRY_ALERT_DAYS days and increments
 * the Prometheus counter for each one.
 *
 * @param pool - PostgreSQL connection pool.
 */
async function runRotationCheck(pool: Pool): Promise<void> {
  try {
    const result: QueryResult<ExpiringCredentialRow> = await pool.query(
      `SELECT credential_id, client_id
       FROM credentials
       WHERE status = 'active'
         AND expires_at IS NOT NULL
         AND expires_at < NOW() + INTERVAL '${EXPIRY_ALERT_DAYS} days'`,
    );

    for (const row of result.rows) {
      credentialsExpiringSoonTotal.inc({ agent_id: row.client_id });
    }

    // Update compliance control status
    updateControlStatus('CC9.2', 'passing');

    // eslint-disable-next-line no-console
    console.log(
      `[SecretsRotationJob] Check complete — ${result.rows.length} credential(s) expiring within ${EXPIRY_ALERT_DAYS} days.`,
    );
  } catch (err) {
    updateControlStatus('CC9.2', 'unknown');
    // eslint-disable-next-line no-console
    console.error('[SecretsRotationJob] Check failed:', err instanceof Error ? err.message : String(err));
  }
}

/**
 * Starts the secrets rotation monitoring job.
 * Schedules a recurring check using `setInterval`.
 * The first check runs after one full interval; to run immediately on startup
 * call this function and allow the interval to fire, or invoke the exported
 * `runRotationCheck` directly in tests.
 *
 * @param pool - PostgreSQL connection pool used for credential queries.
 */
export function startSecretsRotationJob(pool: Pool): void {
  const intervalMs = parseInt(
    process.env['SECRETS_ROTATION_CHECK_INTERVAL_MS'] ?? String(DEFAULT_INTERVAL_MS),
    10,
  );

  // eslint-disable-next-line no-console
  console.log(
    `[SecretsRotationJob] Started — checking for expiring credentials every ${intervalMs / 1000}s.`,
  );

  setInterval(() => {
    void runRotationCheck(pool);
  }, intervalMs);
}
