import { isRecord } from "../../model/config/schema.js";
import type { PilotConfigDiagnostic } from "../../pilot/config/types.js";

export type CronConfig = {
  enabled: boolean;
  timezone: string;
  maxConcurrentRuns: number;
};

export function defaultCronConfig(): CronConfig {
  return {
    enabled: true,
    timezone: "UTC",
    maxConcurrentRuns: 1,
  };
}

const ALLOWED_KEYS = new Set(["enabled", "timezone", "maxConcurrentRuns"]);

export function parseCronConfig(
  raw: unknown,
  diagnostics: PilotConfigDiagnostic[],
): CronConfig | undefined {
  if (raw === undefined) {
    return undefined;
  }
  if (!isRecord(raw)) {
    diagnostics.push({
      code: "CRON_CONFIG_INVALID",
      severity: "fatal",
      message: "cron config must be an object.",
      path: "cron",
      recoverable: false,
    });
    return undefined;
  }

  const result = defaultCronConfig();
  result.enabled = booleanField(raw, "enabled", result.enabled);
  result.timezone = nonEmptyString(raw.timezone, result.timezone, "cron.timezone", diagnostics);
  result.maxConcurrentRuns = positiveInteger(
    raw.maxConcurrentRuns,
    result.maxConcurrentRuns,
    "cron.maxConcurrentRuns",
    diagnostics,
  );

  for (const key of Object.keys(raw)) {
    if (!ALLOWED_KEYS.has(key)) {
      diagnostics.push({
        code: "CRON_UNKNOWN_FIELD",
        severity: "warning",
        message: `Unknown cron config field ${key}.`,
        path: `cron.${key}`,
        recoverable: true,
      });
    }
  }

  return result;
}

function booleanField(record: Record<string, unknown>, key: string, fallback: boolean): boolean {
  const value = record[key];
  return typeof value === "boolean" ? value : fallback;
}

function nonEmptyString(
  value: unknown,
  fallback: string,
  path: string,
  diagnostics: PilotConfigDiagnostic[],
): string {
  if (value === undefined) return fallback;
  if (typeof value === "string" && value.trim().length > 0) {
    return value.trim();
  }
  diagnostics.push({
    code: "CRON_STRING_INVALID",
    severity: "warning",
    message: `${path} must be a non-empty string; falling back to ${fallback}.`,
    path,
    recoverable: true,
  });
  return fallback;
}

function positiveInteger(
  value: unknown,
  fallback: number,
  path: string,
  diagnostics: PilotConfigDiagnostic[],
): number {
  if (value === undefined) return fallback;
  if (
    typeof value !== "number" ||
    !Number.isFinite(value) ||
    !Number.isInteger(value) ||
    value <= 0
  ) {
    diagnostics.push({
      code: "CRON_NUMBER_INVALID",
      severity: "warning",
      message: `${path} must be a positive integer; falling back to ${fallback}.`,
      path,
      recoverable: true,
    });
    return fallback;
  }
  return value;
}