import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { ResultReferenceResolver } from "../../src/results/resolver.js";
import {
  RESULT_REFERENCE_KIND,
  RESULT_REFERENCE_SOURCE,
  ResultReferenceStore,
} from "../../src/results/store.js";

describe("ResultReferenceResolver", () => {
  let tempDir: string;
  let store: ResultReferenceStore;
  let resolver: ResultReferenceResolver;

  beforeEach(async () => {
    tempDir = await mkdtemp(join(tmpdir(), "tjwater-result-ref-"));
    store = new ResultReferenceStore(tempDir, 60_000);
    resolver = new ResultReferenceResolver(store);
    await store.initialize();
  });

  afterEach(async () => {
    await rm(tempDir, { force: true, recursive: true });
  });

  it("stores metadata for render refs and resolves them", async () => {
    const record = await resolver.register({
      actorKey: "actor-1",
      clientSessionId: "client-1",
      data: {
        node_area_map: {
          J1: "DMA-1",
          J2: "DMA-2",
        },
      },
      kind: RESULT_REFERENCE_KIND.renderJunctionsPayload,
      projectId: "project-1",
      projectKey: "project-key-1",
      schemaVersion: 1,
      sessionId: "session-1",
      source: RESULT_REFERENCE_SOURCE.agentGenerated,
      traceId: "trace-1",
    });

    expect(record.kind).toBe(RESULT_REFERENCE_KIND.renderJunctionsPayload);
    expect(record.schemaVersion).toBe(1);
    expect(record.source).toBe(RESULT_REFERENCE_SOURCE.agentGenerated);

    const result = await resolver.getFullAuthorized(
      record.resultRef,
      {
        actorKey: "actor-1",
        projectId: "project-1",
      },
    );

    expect(result).not.toBeNull();
    expect(result?.kind).toBe(RESULT_REFERENCE_KIND.renderJunctionsPayload);
    expect(result?.schema_version).toBe(1);
    expect(result?.source).toBe(RESULT_REFERENCE_SOURCE.agentGenerated);
    expect(result?.data).toEqual({
      node_area_map: {
        J1: "DMA-1",
        J2: "DMA-2",
      },
    });
  });

  it("rejects malformed refs and auth mismatches", async () => {
    const malformedRef = "res-bbbbbbbbbbbbbbbb";
    await writeFile(
      join(tempDir, `${malformedRef}.json`),
      JSON.stringify(
        {
          resultRef: malformedRef,
          createdAt: "2026-05-21T00:00:00.000Z",
          data: { value: 1 },
          preview: {
            count: 1,
            fields: ["value"],
            sample: { value: 1 },
            summary: "object<1 fields>",
          },
          projectId: "project-1",
          projectKey: "project-key-1",
          sessionId: "session-1",
          sizeBytes: 10,
          traceId: "trace-1",
        },
        null,
        2,
      ),
      "utf8",
    );

    const malformed = await store.getAuthorizedRecord(malformedRef, {
      actorKey: "actor-1",
      projectId: "project-1",
    });
    expect(malformed).toBeNull();

    const renderRecord = await resolver.register({
      actorKey: "actor-2",
      clientSessionId: "client-2",
      data: {
        node_area_map: {
          J1: "DMA-1",
        },
      },
      kind: RESULT_REFERENCE_KIND.renderJunctionsPayload,
      projectId: "project-2",
      projectKey: "project-key-2",
      schemaVersion: 1,
      sessionId: "session-2",
      source: RESULT_REFERENCE_SOURCE.agentGenerated,
      traceId: "trace-2",
    });

    const wrongActor = await resolver.getFullAuthorized(renderRecord.resultRef, {
      actorKey: "actor-other",
      projectId: "project-2",
    });
    expect(wrongActor).toBeNull();
  });

  it("registers render refs from local wrapper files and normalizes payloads", async () => {
    const filePath = join(tempDir, "render-wrapper.json");
    await writeFile(
      filePath,
      JSON.stringify(
        {
          metadata: {
            createdAt: "2026-05-21T00:00:00.000Z",
            projectId: "project-3",
          },
          location: {
            file_path: filePath,
          },
          data: {
            node_area_map: {
              J1: "DMA-1",
              J2: 2,
            },
            area_ids: ["DMA-1", " DMA-2 "],
            area_colors: {
              "DMA-1": "#ff0000",
              "DMA-2": "#00ff00",
            },
          },
          createdAt: "2026-05-21T00:00:00.000Z",
        },
        null,
        2,
      ),
      "utf8",
    );

    const record = await resolver.registerRenderPayloadFile(filePath, {
      actorKey: "actor-3",
      clientSessionId: "client-3",
      projectId: "project-3",
      projectKey: "project-key-3",
      sessionId: "session-3",
      source: RESULT_REFERENCE_SOURCE.agentGenerated,
      traceId: "trace-3",
    });

    expect(record.kind).toBe(RESULT_REFERENCE_KIND.renderJunctionsPayload);
    expect(record.source).toBe(RESULT_REFERENCE_SOURCE.agentGenerated);

    const result = await resolver.getFullAuthorized(
      record.resultRef,
      {
        actorKey: "actor-3",
        projectId: "project-3",
      },
      {
        expectedKind: RESULT_REFERENCE_KIND.renderJunctionsPayload,
      },
    );

    expect(result?.data).toEqual({
      node_area_map: {
        J1: "DMA-1",
        J2: "2",
      },
      area_ids: ["DMA-1", "DMA-2"],
      area_colors: {
        "DMA-1": "#ff0000",
        "DMA-2": "#00ff00",
      },
    });
  });

});
