import test from 'node:test';
import assert from 'node:assert/strict';

import { hydrateWorkflowState } from '../src/workflowHydration.js';
import { serializeWorkflowState } from '../src/workflowSerialization.js';

test('serializeWorkflowState keeps only stable workflow fields needed for reload', () => {
  const nodes = [
    {
      id: '1',
      type: 'custom',
      position: { x: 100, y: 200 },
      dragHandle: '.node-header',
      selected: true,
      width: 320,
      data: {
        label: 'Demo Label',
        className: 'DemoNode',
        widgetValues: { threshold: 0.42, mode: 'fast' },
        definition: { input: { required: { threshold: ['FLOAT', { default: 0.5 }] } } },
        previewImage: 'data:image/png;base64,abc',
        tableRows: [{ a: 1 }],
        meshData: { vertices: [1, 2, 3] },
        overlay: { active: true },
      },
    },
    {
      id: '2',
      position: { x: 10, y: 20 },
      data: {
        className: 'NoLabelNode',
      },
    },
  ];

  const edges = [
    {
      id: 'e1-2',
      source: '1',
      sourceHandle: 'output::0::IMAGE',
      target: '2',
      targetHandle: 'input::image::IMAGE',
      style: { stroke: '#fff', strokeWidth: 2 },
      selected: true,
      animated: true,
    },
  ];

  const serialized = serializeWorkflowState(nodes, edges);

  assert.deepEqual(serialized, {
    version: 1,
    nodes: [
      {
        id: '1',
        type: 'custom',
        position: { x: 100, y: 200 },
        dragHandle: '.node-header',
        data: {
          label: 'Demo Label',
          className: 'DemoNode',
          widgetValues: { threshold: 0.42, mode: 'fast' },
          output: [],
          output_name: [],
        },
      },
      {
        id: '2',
        type: 'custom',
        position: { x: 10, y: 20 },
        dragHandle: '.drag-handle',
        data: {
          label: 'NoLabelNode',
          className: 'NoLabelNode',
          widgetValues: {},
          output: [],
          output_name: [],
        },
      },
    ],
    edges: [
      {
        id: 'e1-2',
        source: '1',
        sourceHandle: 'output::0::IMAGE',
        target: '2',
        targetHandle: 'input::image::IMAGE',
        style: { stroke: '#fff', strokeWidth: 2 },
      },
    ],
  });

  assert.equal('definition' in serialized.nodes[0].data, false);
  assert.equal('previewImage' in serialized.nodes[0].data, false);
  assert.equal('selected' in serialized.edges[0], false);
});

test('hydrateWorkflowState clears shared path widgets and uses registry definitions', () => {
  const saved = {
    version: 1,
    nodes: [
      {
        id: '12',
        position: { x: 40, y: 80 },
        data: {
          className: 'Image',
          widgetValues: { filename: 'scan.ibw', colormap: 'viridis' },
          output: ['DATA_FIELD', 'DATA_FIELD'],
          output_name: ['Height', 'Phase'],
          previewImage: 'stale',
        },
      },
    ],
    edges: [
      {
        id: 'e12-3',
        source: '12',
        sourceHandle: 'output::1::DATA_FIELD',
        target: '3',
        targetHandle: 'input::field::DATA_FIELD',
      },
    ],
  };

  const defs = {
    Image: {
      category: 'io',
      input: { required: { filename: ['FILE_PICKER', {}], colormap: [['viridis', 'gray'], {}] } },
      output: ['DATA_FIELD'],
      output_name: ['field'],
      manual_trigger: false,
    },
  };

  const hydrated = hydrateWorkflowState(saved, defs);

  assert.equal(hydrated.nextNodeId, 13);
  assert.deepEqual(hydrated.edges, saved.edges);
  assert.equal(hydrated.nodes[0].type, 'custom');
  assert.equal(hydrated.nodes[0].dragHandle, '.drag-handle');
  assert.equal(hydrated.nodes[0].data.label, 'Image');
  assert.equal(hydrated.nodes[0].data.previewImage, null);
  assert.equal(hydrated.nodes[0].data.widgetValues.filename, '');
  assert.equal(hydrated.nodes[0].data.widgetValues.colormap, 'viridis');
  assert.deepEqual(hydrated.nodes[0].data.definition.output, ['DATA_FIELD']);
  assert.deepEqual(hydrated.nodes[0].data.definition.output_name, ['field']);
  assert.deepEqual(hydrated.nodes[0].data.definition.input, defs.Image.input);
});

test('serializeWorkflowState and hydrateWorkflowState clear path-like widgets without restoring saved outputs', () => {
  const nodes = [
    {
      id: '7',
      position: { x: 10, y: 20 },
      data: {
        label: 'Image',
        className: 'Image',
        widgetValues: { filename: 'scan.gwy', colormap: 'gray' },
        definition: {
          category: 'io',
          input: { required: { filename: ['FILE_PICKER', {}], colormap: [['gray', 'viridis'], {}] } },
          output: ['DATA_FIELD', 'DATA_FIELD', 'DATA_FIELD'],
          output_name: ['Topography', 'Error', 'Mask'],
        },
        previewImage: 'data:image/png;base64,stale',
      },
    },
  ];
  const edges = [
    {
      id: 'e7-9',
      source: '7',
      sourceHandle: 'output::2::DATA_FIELD',
      target: '9',
      targetHandle: 'input::field::DATA_FIELD',
    },
  ];
  const defs = {
    Image: {
      category: 'io',
      input: { required: { filename: ['FILE_PICKER', {}], colormap: [['gray', 'viridis'], {}] } },
      output: ['DATA_FIELD'],
      output_name: ['field'],
    },
  };

  const serialized = serializeWorkflowState(nodes, edges);
  const hydrated = hydrateWorkflowState(serialized, defs);

  assert.deepEqual(hydrated.nodes[0].data.widgetValues, { filename: '', colormap: 'gray' });
  assert.deepEqual(hydrated.nodes[0].data.definition.output, ['DATA_FIELD']);
  assert.deepEqual(hydrated.nodes[0].data.definition.output_name, ['field']);
  assert.deepEqual(hydrated.edges, edges);
});

test('hydrateWorkflowState clears saved folder selections on shared workflows', () => {
  const saved = {
    version: 1,
    nodes: [
      {
        id: '21',
        position: { x: 0, y: 0 },
        data: {
          className: 'Folder',
          widgetValues: { folder: '/Users/alice/Desktop/shared-dataset' },
          output: ['PATH', 'PATH'],
          output_name: ['scan1.png', 'scan2.png'],
        },
      },
    ],
    edges: [],
  };

  const defs = {
    Folder: {
      category: 'io',
      input: { required: { folder: ['FOLDER_PICKER', {}] } },
      output: ['PATH'],
      output_name: ['path'],
    },
  };

  const hydrated = hydrateWorkflowState(saved, defs);

  assert.equal(hydrated.nodes[0].data.widgetValues.folder, '');
  assert.deepEqual(hydrated.nodes[0].data.definition.output, ['PATH']);
  assert.deepEqual(hydrated.nodes[0].data.definition.output_name, ['path']);
});
