import { rootPath } from "./config";
import { createYamlFieldReader, readYamlRecord } from "./platform-infra-ops-library";

export const staticSiteConfigPath = rootPath("config", "platform-infra", "hwpod-home.yaml");
export const staticSiteConfigLabel = "config/platform-infra/hwpod-home.yaml";

const y = createYamlFieldReader(staticSiteConfigLabel);

export interface StaticSiteExposure {
  readonly hostname: string;
  readonly expectedA: string;
  readonly upstream: string;
  readonly healthPath: string;
}

export interface StaticSiteTarget {
  readonly id: string;
  readonly route: string;
  readonly namespace: string;
  readonly enabled: boolean;
  readonly replicas: number;
  readonly publicExposures: {
    readonly apex: StaticSiteExposure;
    readonly www: StaticSiteExposure;
  };
}

export interface StaticSiteConfig {
  readonly metadata: { readonly id: string; readonly owner: string };
  readonly defaults: { readonly targetId: string };
  readonly application: {
    readonly repository: string;
    readonly remote: string;
    readonly branch: string;
    readonly sourceRoot: string;
    readonly sourceConfigPath: string;
    readonly dockerfile: string;
  };
  readonly image: { readonly repository: string; readonly pullPolicy: "Always" | "IfNotPresent" | "Never" };
  readonly delivery: {
    readonly enabled: boolean;
    readonly pipeline: {
      readonly namespace: string;
      readonly name: string;
      readonly runPrefix: string;
      readonly serviceAccountName: string;
      readonly timeout: string;
      readonly workspaceSize: string;
      readonly toolsImage: string;
      readonly buildkitImage: string;
      readonly sourceSnapshotPrefix: string;
    };
    readonly build: {
      readonly networkMode: "host";
      readonly proxy: { readonly http: string; readonly https: string; readonly all: string; readonly noProxy: string[] };
    };
    readonly gitops: {
      readonly readUrl: string;
      readonly writeUrl: string;
      readonly branch: string;
      readonly manifestPath: string;
      readonly releaseStatePath: string;
      readonly maxPushAttempts: number;
      readonly author: { readonly name: string; readonly email: string };
      readonly application: {
        readonly name: string;
        readonly namespace: string;
        readonly project: string;
        readonly path: string;
        readonly destinationNamespace: string;
        readonly automated: boolean;
      };
    };
  };
  readonly targets: StaticSiteTarget[];
  readonly runtime: {
    readonly deploymentName: string;
    readonly serviceName: string;
    readonly containerPort: number;
    readonly servicePort: number;
    readonly nodePort: number;
    readonly probes: {
      readonly healthPath: string;
      readonly initialDelaySeconds: number;
      readonly periodSeconds: number;
      readonly timeoutSeconds: number;
      readonly failureThreshold: number;
    };
    readonly resources: {
      readonly requests: { readonly cpu: string; readonly memory: string };
      readonly limits: { readonly cpu: string; readonly memory: string };
    };
  };
}

export function readStaticSiteConfig(): StaticSiteConfig {
  const root = readYamlRecord<Record<string, unknown>>(staticSiteConfigPath, "platform-infra-static-site");
  if (y.integerField(root, "version", "") !== 1) throw new Error(`${staticSiteConfigLabel}.version must be 1`);
  if (y.stringField(root, "kind", "") !== "platform-infra-static-site") throw new Error(`${staticSiteConfigLabel}.kind must be platform-infra-static-site`);
  const metadata = y.objectField(root, "metadata", "");
  const defaults = y.objectField(root, "defaults", "");
  const application = y.objectField(root, "application", "");
  const image = y.objectField(root, "image", "");
  const delivery = y.objectField(root, "delivery", "");
  const pipeline = y.objectField(delivery, "pipeline", "delivery");
  const build = y.objectField(delivery, "build", "delivery");
  const proxy = y.objectField(build, "proxy", "delivery.build");
  const gitops = y.objectField(delivery, "gitops", "delivery");
  const author = y.objectField(gitops, "author", "delivery.gitops");
  const argo = y.objectField(gitops, "application", "delivery.gitops");
  const runtime = y.objectField(root, "runtime", "");
  const probes = y.objectField(runtime, "probes", "runtime");
  const resources = y.objectField(runtime, "resources", "runtime");
  const requests = y.objectField(resources, "requests", "runtime.resources");
  const limits = y.objectField(resources, "limits", "runtime.resources");
  const targetId = y.stringField(defaults, "targetId", "defaults");
  const targets = parseTargets(root.targets);
  if (!targets.some((target) => target.id === targetId)) throw new Error(`${staticSiteConfigLabel}.targets must include defaults.targetId ${targetId}`);
  return {
    metadata: { id: y.stringField(metadata, "id", "metadata"), owner: y.stringField(metadata, "owner", "metadata") },
    defaults: { targetId },
    application: {
      repository: y.stringField(application, "repository", "application"),
      remote: y.stringField(application, "remote", "application"),
      branch: y.stringField(application, "branch", "application"),
      sourceRoot: y.absolutePathField(application, "sourceRoot", "application"),
      sourceConfigPath: y.stringField(application, "sourceConfigPath", "application"),
      dockerfile: y.stringField(application, "dockerfile", "application"),
    },
    image: {
      repository: y.stringField(image, "repository", "image"),
      pullPolicy: y.enumField(image, "pullPolicy", "image", ["Always", "IfNotPresent", "Never"] as const),
    },
    delivery: {
      enabled: y.booleanField(delivery, "enabled", "delivery"),
      pipeline: {
        namespace: y.kubernetesNameField(pipeline, "namespace", "delivery.pipeline"),
        name: y.kubernetesNameField(pipeline, "name", "delivery.pipeline"),
        runPrefix: y.kubernetesNameField(pipeline, "runPrefix", "delivery.pipeline"),
        serviceAccountName: y.kubernetesNameField(pipeline, "serviceAccountName", "delivery.pipeline"),
        timeout: y.stringField(pipeline, "timeout", "delivery.pipeline"),
        workspaceSize: y.stringField(pipeline, "workspaceSize", "delivery.pipeline"),
        toolsImage: y.stringField(pipeline, "toolsImage", "delivery.pipeline"),
        buildkitImage: y.stringField(pipeline, "buildkitImage", "delivery.pipeline"),
        sourceSnapshotPrefix: y.stringField(pipeline, "sourceSnapshotPrefix", "delivery.pipeline"),
      },
      build: {
        networkMode: y.enumField(build, "networkMode", "delivery.build", ["host"] as const),
        proxy: {
          http: y.stringField(proxy, "http", "delivery.build.proxy"),
          https: y.stringField(proxy, "https", "delivery.build.proxy"),
          all: y.stringField(proxy, "all", "delivery.build.proxy"),
          noProxy: y.stringArrayField(proxy, "noProxy", "delivery.build.proxy"),
        },
      },
      gitops: {
        readUrl: y.stringField(gitops, "readUrl", "delivery.gitops"),
        writeUrl: y.stringField(gitops, "writeUrl", "delivery.gitops"),
        branch: y.stringField(gitops, "branch", "delivery.gitops"),
        manifestPath: y.stringField(gitops, "manifestPath", "delivery.gitops"),
        releaseStatePath: y.stringField(gitops, "releaseStatePath", "delivery.gitops"),
        maxPushAttempts: y.integerField(gitops, "maxPushAttempts", "delivery.gitops"),
        author: { name: y.stringField(author, "name", "delivery.gitops.author"), email: y.stringField(author, "email", "delivery.gitops.author") },
        application: {
          name: y.kubernetesNameField(argo, "name", "delivery.gitops.application"),
          namespace: y.kubernetesNameField(argo, "namespace", "delivery.gitops.application"),
          project: y.stringField(argo, "project", "delivery.gitops.application"),
          path: y.stringField(argo, "path", "delivery.gitops.application"),
          destinationNamespace: y.kubernetesNameField(argo, "destinationNamespace", "delivery.gitops.application"),
          automated: y.booleanField(argo, "automated", "delivery.gitops.application"),
        },
      },
    },
    targets,
    runtime: {
      deploymentName: y.kubernetesNameField(runtime, "deploymentName", "runtime"),
      serviceName: y.kubernetesNameField(runtime, "serviceName", "runtime"),
      containerPort: y.portField(runtime, "containerPort", "runtime"),
      servicePort: y.portField(runtime, "servicePort", "runtime"),
      nodePort: y.portField(runtime, "nodePort", "runtime"),
      probes: {
        healthPath: y.stringField(probes, "healthPath", "runtime.probes"),
        initialDelaySeconds: y.integerField(probes, "initialDelaySeconds", "runtime.probes"),
        periodSeconds: y.integerField(probes, "periodSeconds", "runtime.probes"),
        timeoutSeconds: y.integerField(probes, "timeoutSeconds", "runtime.probes"),
        failureThreshold: y.integerField(probes, "failureThreshold", "runtime.probes"),
      },
      resources: {
        requests: { cpu: y.stringField(requests, "cpu", "runtime.resources.requests"), memory: y.stringField(requests, "memory", "runtime.resources.requests") },
        limits: { cpu: y.stringField(limits, "cpu", "runtime.resources.limits"), memory: y.stringField(limits, "memory", "runtime.resources.limits") },
      },
    },
  };
}

export function resolveStaticSiteTarget(config: StaticSiteConfig, targetId: string | null): StaticSiteTarget {
  const selected = targetId ?? config.defaults.targetId;
  const target = config.targets.find((item) => item.id === selected);
  if (target === undefined) throw new Error(`unknown static-site target ${selected}`);
  if (!target.enabled) throw new Error(`static-site target ${selected} is disabled`);
  return target;
}

function parseTargets(value: unknown): StaticSiteTarget[] {
  if (!Array.isArray(value) || value.length === 0) throw new Error(`${staticSiteConfigLabel}.targets must be a non-empty array`);
  return value.map((item, index) => {
    const path = `targets[${index}]`;
    const target = y.asRecord(item, path);
    const publicExposures = y.objectField(target, "publicExposures", path);
    return {
      id: y.stringField(target, "id", path),
      route: y.stringField(target, "route", path),
      namespace: y.kubernetesNameField(target, "namespace", path),
      enabled: y.booleanField(target, "enabled", path),
      replicas: y.integerField(target, "replicas", path),
      publicExposures: {
        apex: parseExposure(y.objectField(publicExposures, "apex", `${path}.publicExposures`), `${path}.publicExposures.apex`),
        www: parseExposure(y.objectField(publicExposures, "www", `${path}.publicExposures`), `${path}.publicExposures.www`),
      },
    };
  });
}

function parseExposure(value: Record<string, unknown>, path: string): StaticSiteExposure {
  return {
    hostname: y.stringField(value, "hostname", path),
    expectedA: y.stringField(value, "expectedA", path),
    upstream: y.stringField(value, "upstream", path),
    healthPath: y.stringField(value, "healthPath", path),
  };
}
