import { DatabaseModel, OntimeRundown, Settings, URLPreset, ViewSettings } from 'ontime-types';
import { safeMerge } from '../DataProvider.utils.js';

describe('safeMerge', () => {
  const existing = {
    rundown: [],
    project: {
      title: 'existing title',
      description: 'existing description',
      publicUrl: 'existing public URL',
      backstageUrl: 'existing backstageUrl',
      publicInfo: 'existing backstageInfo',
      backstageInfo: 'existing backstageInfo',
    },
    settings: {
      app: 'ontime',
      version: '2.0.0',
      serverPort: 4001,
      editorKey: null,
      operatorKey: null,
      timeFormat: '24',
      language: 'en',
    },
    viewSettings: {
      overrideStyles: false,
      freezeEnd: false,
      endMessage: 'existing endMessage',
      normalColor: '#ffffffcc',
      warningColor: '#FFAB33',
      dangerColor: '#ED3333',
    },
    urlPresets: [],
    customFields: {
      lighting: { type: 'string', label: 'lighting', colour: 'red' },
      vfx: { type: 'string', label: 'vfx', colour: 'blue' },
    },
    osc: {
      portIn: 8888,
      portOut: 9999,
      targetIP: '127.0.0.1',
      enabledIn: false,
      enabledOut: false,
      subscriptions: [],
    },
    http: {
      enabledOut: false,
      subscriptions: [],
    },
  } as DatabaseModel;

  it('returns existing data if new data is not provided', () => {
    const mergedData = safeMerge(existing, {});
    expect(mergedData).toEqual(existing);
  });

  it('merges the rundown key', () => {
    const newData = {
      rundown: [{ title: 'item 1' }, { title: 'item 2' }] as OntimeRundown,
    };
    const mergedData = safeMerge(existing, newData);
    expect(mergedData.rundown).toEqual(newData.rundown);
  });

  it('merges the project key', () => {
    const newData = {
      project: {
        title: 'new title',
        publicInfo: 'new public info',
      },
    };
    // @ts-expect-error -- just testing
    const mergedData = safeMerge(existing, newData);
    expect(mergedData.project).toEqual({
      title: 'new title',
      description: 'existing description',
      publicUrl: 'existing public URL',
      publicInfo: 'new public info',
      backstageUrl: 'existing backstageUrl',
      backstageInfo: 'existing backstageInfo',
    });
  });

  it('merges the settings key', () => {
    const newData = {
      settings: {
        serverPort: 3000,
        language: 'pt',
      } as Settings,
    };
    const mergedData = safeMerge(existing, newData);
    expect(mergedData.settings).toEqual({
      app: 'ontime',
      version: '2.0.0',
      serverPort: 3000,
      operatorKey: null,
      editorKey: null,
      timeFormat: '24',
      language: 'pt',
    });
  });
  it('merges the osc key', () => {
    const newData = {
      osc: {
        portIn: 7777,
        subscriptions: [
          {
            id: 'unique',
            cycle: 'onStart',
            message: 'new message',
            enabled: true,
          },
        ],
      },
    };
    //@ts-expect-error -- testing partial merge
    const mergedData = safeMerge(existing, newData);
    expect(mergedData.osc).toMatchObject({
      portIn: 7777,
      portOut: 9999,
      targetIP: '127.0.0.1',
      enabledIn: false,
      enabledOut: false,
      subscriptions: [
        {
          id: 'unique',
          cycle: 'onStart',
          message: 'new message',
          enabled: true,
        },
      ],
    });
  });

  it('should merge the urlPresets key when present', () => {
    const existingData = {
      rundown: [],
      project: {
        title: '',
        description: '',
        publicUrl: '',
        publicInfo: '',
        backstageUrl: '',
        backstageInfo: '',
      },
      settings: {
        app: 'ontime',
        version: '2.0.0',
        serverPort: 4001,
        operatorKey: null,
        editorKey: null,
        timeFormat: '24',
        language: 'en',
      },
      viewSettings: {
        overrideStyles: false,
        endMessage: '',
      } as ViewSettings,
      urlPresets: [],
      customFields: {},
      osc: {
        portIn: 8888,
        portOut: 9999,
        targetIP: '127.0.0.1',
        enabledIn: false,
        enabledOut: false,
        subscriptions: [],
      },
      http: {
        enabledOut: false,
        subscriptions: [],
      },
    } as DatabaseModel;

    const newData = {
      urlPresets: [
        { enabled: true, alias: 'alias1', pathAndParams: '' },
        { enabled: true, alias: 'alias2', pathAndParams: '' },
      ] as URLPreset[],
    };

    const mergedData = safeMerge(existingData, newData);

    expect(mergedData.urlPresets).toEqual(newData.urlPresets);
  });

  it('merges customFields into existing object', () => {
    const existing = {
      customFields: {
        lighting: { type: 'string', label: 'lighting' },
        sound: { type: 'string', label: 'sound' },
      },
    };

    const newData = {
      customFields: {
        switcher: { type: 'string', label: 'switcher' },
        vfx: { type: 'string', label: 'vfx' },
      },
    };

    const expected = {
      switcher: { type: 'string', label: 'switcher' },
      vfx: { type: 'string', label: 'vfx' },
    };

    //@ts-expect-error -- testing partial merge
    const result = safeMerge(existing, newData);
    expect(result.customFields).toEqual(expected);
  });
});
