// This file was moved from the `server` package to here and `server` has `strictNullChecks` disabled.
// This code was originally written with the assumption that `widget.children` is never undefined, despite the type saying otherwise.
// So we are using `!` to assert that `widget.children` is never undefined.
// Note that `!` does not change the runtime behavior of the code so the code will work the same way as before.

import { cloneDeep } from 'lodash';
import { describe, it, expect } from 'vitest';

import type { PageDSL4and5 } from '../../types/index.js';
import containerV4 from '../../utils/pageFixtures/v4/container.js';
import emptyV4 from '../../utils/pageFixtures/v4/empty.js';
import formV4 from '../../utils/pageFixtures/v4/form.js';
import gridV4 from '../../utils/pageFixtures/v4/grid.js';
import slideoutV4 from '../../utils/pageFixtures/v4/slideout.js';
import tabsV4 from '../../utils/pageFixtures/v4/tabs.js';
import { migrate4to5 } from './v4to5.js';

const positionProps = [
  'leftColumn',
  'rightColumn',
  'topRow',
  'bottomRow',
  'minHeight',
  'parentColumnSpace',
  'parentRowSpace',
  'snapColumns',
  'snapRows'
];

function getStaticProps(widget: Record<string, unknown>) {
  const output: Record<string, unknown> = {};
  positionProps.forEach((key) => {
    output[key] = widget[key];
  });
  return output;
}

describe('version 4 to version 5', () => {
  it('should migrate the top-level app', () => {
    const migrated = migrate4to5(cloneDeep(emptyV4) as PageDSL4and5);

    expect(getStaticProps(migrated)).toEqual({
      topRow: 0,
      bottomRow: 104,
      minHeight: 1292,
      snapColumns: 96,
      snapRows: 104
    });
  });

  it('should migrate a grid component and its children', () => {
    const migrated = migrate4to5(cloneDeep(gridV4) as unknown as PageDSL4and5);

    const grid = migrated.children![0];
    expect(getStaticProps(grid)).toEqual({
      snapColumns: 11 * 6,
      leftColumn: 1 * 6,
      rightColumn: 12 * 6,
      topRow: 4 * 3,
      bottomRow: 21 * 3
    });

    const gridCanvas = grid.children![0];
    expect(getStaticProps(gridCanvas)).toEqual({
      minHeight: 680,
      topRow: 0,
      snapColumns: 22,
      bottomRow: 51,
      snapRows: 51
    });

    const gridContainer = gridCanvas.children![0];
    expect(getStaticProps(gridContainer)).toEqual({
      leftColumn: 0,
      rightColumn: 22,
      topRow: 0,
      bottomRow: 7 * 3,
      snapColumns: 22,
      snapRows: undefined
    });

    const gridCanvas2 = gridContainer.children![0];
    expect(getStaticProps(gridCanvas2)).toEqual({
      topRow: 0,
      leftColumn: undefined,
      minHeight: undefined,
      parentColumnSpace: undefined,
      parentRowSpace: undefined,
      rightColumn: undefined,
      snapColumns: 22,
      bottomRow: 21,
      snapRows: 21
    });

    const gridImage = gridCanvas2.children![0];
    expect(getStaticProps(gridImage)).toEqual({
      leftColumn: 0,
      rightColumn: 22,
      snapColumns: 22,
      topRow: 0,
      bottomRow: 4 * 3
    });
  });

  it('should migrate a slideout component and its children', () => {
    const migrated = migrate4to5(cloneDeep(slideoutV4) as PageDSL4and5);

    const slideout = migrated.children![0];
    expect(getStaticProps(slideout)).toEqual({
      snapColumns: 6,
      snapRows: undefined,
      leftColumn: 3 * 6,
      rightColumn: 4 * 6,
      topRow: 0,
      bottomRow: 1 * 3
    });

    const slideoutCanvas = slideout.children![0];
    expect(getStaticProps(slideoutCanvas)).toEqual({
      snapColumns: 80,
      topRow: 0,
      snapRows: 69,
      bottomRow: 67,
      minHeight: 800
    });

    const slideoutTitle = slideoutCanvas.children![0];
    expect(getStaticProps(slideoutTitle)).toEqual({
      snapColumns: 50,
      leftColumn: 0,
      rightColumn: 50, // Scaled up from before
      topRow: 0,
      bottomRow: 3
    });
  });

  it('should migrate a tabs component and its children', () => {
    const migrated = migrate4to5(cloneDeep(tabsV4) as PageDSL4and5);

    const tabs = migrated.children![0];
    expect(getStaticProps(tabs)).toEqual({
      snapColumns: 8 * 6,
      leftColumn: 1 * 6,
      rightColumn: 9 * 6,
      topRow: 2 * 3,
      bottomRow: 9 * 3
    });

    const firstTab = tabs.children![0];
    expect(getStaticProps(firstTab)).toEqual({
      snapColumns: 48,
      topRow: 0,
      bottomRow: 18,
      snapRows: 18
    });

    const elementInTab = firstTab.children![0];
    expect(getStaticProps(elementInTab)).toEqual({
      snapColumns: 72 - 18,
      leftColumn: 18,
      rightColumn: 72,
      topRow: 0,
      bottomRow: 45,
      snapRows: undefined
    });
  });

  it('should migrate a form component and its children', () => {
    const migrated = migrate4to5(cloneDeep(formV4) as PageDSL4and5);

    const form = migrated.children![0];
    expect(getStaticProps(form)).toEqual({
      snapColumns: 7 * 6,
      snapRows: undefined,
      leftColumn: 3 * 6,
      rightColumn: 10 * 6,
      topRow: 8 * 3,
      bottomRow: 21 * 3
    });

    const formCanvas = form.children![0];
    expect(getStaticProps(formCanvas)).toEqual({
      snapColumns: 42,
      topRow: 0,
      bottomRow: 39,
      snapRows: 39,
      minHeight: 520
    });

    const formTitle = formCanvas.children![0];
    expect(getStaticProps(formTitle)).toEqual({
      leftColumn: 0,
      rightColumn: 31,
      snapColumns: 31,
      topRow: 0,
      bottomRow: 3
    });

    const formInput = formCanvas.children![3];
    expect(getStaticProps(formInput)).toEqual({
      leftColumn: 0,
      rightColumn: 7,
      snapColumns: 7,
      // Normally would be topRow: 3, but there is an adjustment for inputs
      topRow: 4,
      bottomRow: 9
    });

    const formInputNoLabel = formCanvas.children![4];
    expect(getStaticProps(formInputNoLabel)).toEqual({
      leftColumn: 0,
      rightColumn: 7,
      snapColumns: 7,
      // This input has a missing label so it gets migrated at full height
      topRow: 3,
      bottomRow: 9
    });
  });

  it('should migrate a complex app using containers', () => {
    const migrated = migrate4to5(cloneDeep(containerV4) as PageDSL4and5);

    expect(getStaticProps(migrated)).toEqual({
      topRow: 0,
      bottomRow: 140,
      minHeight: 1292,
      snapColumns: 96,
      snapRows: 140
    });

    const containerElement = migrated.children![0];
    expect(getStaticProps(containerElement)).toEqual({
      topRow: 6,
      bottomRow: 120,
      leftColumn: 0,
      rightColumn: 96,
      snapColumns: 96
    });

    const containerCanvas = containerElement.children![0];
    expect(getStaticProps(containerCanvas)).toEqual({
      topRow: 0,
      bottomRow: 114,
      snapRows: 114,
      minHeight: 400,
      snapColumns: 96
    });

    const tabComponent = containerCanvas.children![0];
    expect(getStaticProps(tabComponent)).toEqual({
      topRow: 0,
      leftColumn: 0,
      bottomRow: 108,
      rightColumn: 96,
      snapColumns: 96
    });

    const tabCanvas = tabComponent.children![1];
    expect(getStaticProps(tabCanvas)).toEqual({
      bottomRow: 105,
      snapRows: 105,
      snapColumns: 96,
      topRow: 0
    });

    const tabTitle = tabCanvas.children![0];
    expect(getStaticProps(tabTitle)).toEqual({
      topRow: 0,
      bottomRow: 3,
      leftColumn: 30,
      rightColumn: 60,
      snapColumns: 30
    });
  });
});
