import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { nexusSettingsSchema, nexusSettingsService } from "../services/nexus-settings.js";

// A minimal valid PaletteRole for testing
const validPaletteRole = {
  name: "background",
  dark: { oklch: "oklch(0.14 0.01 262)", hex: "#07090d", wcagAA: true },
  light: { oklch: "oklch(0.94 0.005 262)", hex: "#e9ebef", wcagAA: true },
};

// A full valid custom theme (7 roles, but tests use partial arrays for brevity — Zod accepts any array length)
const validCustomTheme = {
  seedHex: "#1e66f5",
  palette: [validPaletteRole],
};

describe("nexusSettingsSchema with customTheme", () => {
  it("parses {} successfully — customTheme is optional", () => {
    expect(() => nexusSettingsSchema.parse({})).not.toThrow();
  });

  it("parsed {} has undefined customTheme", () => {
    const result = nexusSettingsSchema.parse({});
    expect(result.customTheme).toBeUndefined();
  });

  it("parses with valid customTheme successfully", () => {
    const result = nexusSettingsSchema.parse({ customTheme: validCustomTheme });
    expect(result.customTheme).toBeDefined();
    expect(result.customTheme?.seedHex).toBe("#1e66f5");
    expect(result.customTheme?.palette).toHaveLength(1);
  });

  it("parses customTheme palette role fields correctly", () => {
    const result = nexusSettingsSchema.parse({ customTheme: validCustomTheme });
    const role = result.customTheme?.palette[0]!;
    expect(role.name).toBe("background");
    expect(role.dark.oklch).toBe("oklch(0.14 0.01 262)");
    expect(role.dark.hex).toBe("#07090d");
    expect(role.dark.wcagAA).toBe(true);
    expect(role.light.wcagAA).toBe(true);
  });

  it("fails validation when customTheme is missing seedHex", () => {
    const result = nexusSettingsSchema.safeParse({
      customTheme: { palette: [validPaletteRole] },
    });
    expect(result.success).toBe(false);
  });

  it("fails validation when customTheme is missing palette", () => {
    const result = nexusSettingsSchema.safeParse({
      customTheme: { seedHex: "#1e66f5" },
    });
    expect(result.success).toBe(false);
  });

  it("fails validation when palette role is missing dark variant", () => {
    const result = nexusSettingsSchema.safeParse({
      customTheme: {
        seedHex: "#1e66f5",
        palette: [{ name: "background", light: validPaletteRole.light }],
      },
    });
    expect(result.success).toBe(false);
  });

  it("existing fields still work with customTheme present", () => {
    const result = nexusSettingsSchema.parse({
      mode: "personal_ai",
      voiceEnabled: true,
      customTheme: validCustomTheme,
    });
    expect(result.mode).toBe("personal_ai");
    expect(result.voiceEnabled).toBe(true);
    expect(result.customTheme?.seedHex).toBe("#1e66f5");
  });
});

describe("nexusSettingsService with customTheme", () => {
  let tmpDir: string;
  let originalHome: string | undefined;

  beforeEach(async () => {
    tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "nexus-settings-custom-theme-"));
    originalHome = process.env.PAPERCLIP_HOME;
    process.env.PAPERCLIP_HOME = tmpDir;
  });

  afterEach(async () => {
    if (originalHome !== undefined) {
      process.env.PAPERCLIP_HOME = originalHome;
    } else {
      delete process.env.PAPERCLIP_HOME;
    }
    await fs.rm(tmpDir, { recursive: true, force: true });
  });

  it("get() returns undefined customTheme when not set", async () => {
    const service = nexusSettingsService();
    const settings = await service.get();
    expect(settings.customTheme).toBeUndefined();
  });

  it("set() with customTheme persists and get() retrieves it", async () => {
    const service = nexusSettingsService();

    await service.set({ customTheme: validCustomTheme });

    const retrieved = await service.get();
    expect(retrieved.customTheme).toBeDefined();
    expect(retrieved.customTheme?.seedHex).toBe("#1e66f5");
    expect(retrieved.customTheme?.palette).toHaveLength(1);
    expect(retrieved.customTheme?.palette[0].name).toBe("background");
  });

  it("set() with customTheme does not overwrite other fields", async () => {
    const service = nexusSettingsService();

    // First set mode
    await service.set({ mode: "project_builder" });
    // Then set customTheme
    await service.set({ customTheme: validCustomTheme });

    const retrieved = await service.get();
    expect(retrieved.mode).toBe("project_builder");
    expect(retrieved.customTheme?.seedHex).toBe("#1e66f5");
  });

  it("set() can clear customTheme by setting undefined", async () => {
    const service = nexusSettingsService();

    await service.set({ customTheme: validCustomTheme });
    await service.set({ customTheme: undefined });

    const retrieved = await service.get();
    expect(retrieved.customTheme).toBeUndefined();
  });

  it("settings file on disk contains customTheme when set", async () => {
    const service = nexusSettingsService();
    await service.set({ customTheme: validCustomTheme });

    const settingsPath = path.join(tmpDir, "instances", "default", "data", "nexus-settings.json");
    const raw = await fs.readFile(settingsPath, "utf-8");
    const parsed = JSON.parse(raw);
    expect(parsed.customTheme.seedHex).toBe("#1e66f5");
  });
});
