import { existsSync, readdirSync, readFileSync } from "node:fs";
import { basename, join } from "node:path";

import {
  type ArticleSample,
  type LoadedArticleSamples,
  supportedPlatforms,
  type SamplePlatform,
} from "./types";

interface RawSample {
  name?: unknown;
  input?: {
    title?: unknown;
    body?: unknown;
    image_lines?: unknown;
    platform?: unknown;
    user_instructions?: unknown;
  };
  expectedHardFailures?: unknown;
  expectedWarnings?: unknown;
}

export function loadArticleSamples(samplesDir: string): LoadedArticleSamples {
  if (!existsSync(samplesDir)) {
    return { valid: [], invalid: [] };
  }

  const files = readdirSync(samplesDir)
    .filter((fileName) => fileName.endsWith(".json"))
    .sort((left, right) => left.localeCompare(right));

  const valid: ArticleSample[] = [];
  const invalid: LoadedArticleSamples["invalid"] = [];

  for (const fileName of files) {
    const filePath = join(samplesDir, fileName);
    try {
      const raw = JSON.parse(readFileSync(filePath, "utf8")) as RawSample;
      const sample = normalizeSample(raw, filePath, fileName);
      valid.push(sample);
    } catch (error) {
      invalid.push({
        filePath,
        fileName,
        reason:
          error instanceof Error ? error.message : "sample could not be parsed",
      });
    }
  }

  return { valid, invalid };
}

function normalizeSample(
  raw: RawSample,
  filePath: string,
  fileName: string,
): ArticleSample {
  if (!raw || typeof raw !== "object") {
    throw new Error("sample must be a JSON object");
  }
  if (!raw.input || typeof raw.input !== "object") {
    throw new Error("input must be an object");
  }
  if (typeof raw.input.body !== "string" || raw.input.body.trim().length === 0) {
    throw new Error("input.body must be a non-empty string");
  }
  if (!isSupportedPlatform(raw.input.platform)) {
    throw new Error(
      `input.platform must be one of ${supportedPlatforms.join(", ")}`,
    );
  }

  return {
    filePath,
    fileName,
    slug: slugFromFileName(fileName),
    name:
      typeof raw.name === "string" && raw.name.trim().length > 0
        ? raw.name.trim()
        : basename(fileName, ".json"),
    input: {
      title: stringOrEmpty(raw.input.title),
      body: raw.input.body,
      image_lines: stringOrEmpty(raw.input.image_lines),
      platform: raw.input.platform,
      user_instructions: stringOrEmpty(raw.input.user_instructions),
    },
    expectedHardFailures: stringArrayOrEmpty(raw.expectedHardFailures),
    expectedWarnings: stringArrayOrEmpty(raw.expectedWarnings),
  };
}

function isSupportedPlatform(value: unknown): value is SamplePlatform {
  return (
    typeof value === "string" &&
    supportedPlatforms.includes(value as SamplePlatform)
  );
}

function stringOrEmpty(value: unknown) {
  return typeof value === "string" ? value : "";
}

function stringArrayOrEmpty(value: unknown) {
  return Array.isArray(value)
    ? value.filter((item): item is string => typeof item === "string")
    : [];
}

function slugFromFileName(fileName: string) {
  return basename(fileName, ".json")
    .toLowerCase()
    .replace(/[^a-z0-9-]+/g, "-")
    .replace(/^-+|-+$/g, "");
}
