// 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.

/* eslint-disable @typescript-eslint/no-explicit-any */

import type { PageDSL4and5 } from '../../types/index.js';

const V4_COLUMN_COUNT = 16;
const ROW_DENSITY_RATIO = 3;
const ROW_HEIGHT = 12;

// This migration code uses strings instead of variables like CANVAS_WIDGET for two reasons:
// 1. These strings will never change, even if we change the types in the future
// 2. We do want to make these types much stricter in the future, but for now
export const migrate4to5 = (widget: PageDSL4and5, maxColumns = 96): PageDSL4and5 => {
  // MAIN_CONTAINER_WIDGET_ID
  if (widget.widgetId === '0') {
    widget.snapColumns = maxColumns;
    widget.bottomRow = Math.floor(widget.bottomRow / ROW_HEIGHT);
    widget.snapRows = widget.bottomRow;
  }
  if (widget.type === 'CANVAS_WIDGET') {
    delete widget.parentColumnSpace;
    delete widget.parentRowSpace;
    delete widget.leftColumn;
    delete widget.rightColumn;
  }
  if (widget.type !== 'CANVAS_WIDGET') {
    delete widget.parentColumnSpace;
    delete widget.parentRowSpace;
    // If we are inside a contained element, maxColumns is scaled by the actual space usage
    // This usually scales up, but can also scale down
    widget.leftColumn = Math.floor(widget.leftColumn! * (maxColumns / V4_COLUMN_COUNT));
    widget.rightColumn = Math.floor(widget.rightColumn! * (maxColumns / V4_COLUMN_COUNT));
    widget.snapColumns = widget.rightColumn - widget.leftColumn;
    maxColumns = widget.rightColumn - widget.leftColumn;
  }

  widget.children?.forEach((child: PageDSL4and5) => {
    if (!child) return;
    if (child.type === 'CANVAS_WIDGET') {
      if (child.bottomRow) {
        if (!widget.shouldScrollContents) {
          // for unscrollable container, we should just use container's height
          // using the max result above will cause unscrollabe tab cutoff on header
          child.bottomRow = widget.bottomRow - widget.topRow;
        } else {
          // Divide by row height
          child.bottomRow = Math.max(Math.ceil(child.bottomRow / ROW_HEIGHT), widget.bottomRow - widget.topRow);
        }
        child.snapRows = child.bottomRow;
      } else {
        child.bottomRow = widget.bottomRow;
        child.snapRows = child.bottomRow;
      }
    } else {
      child.topRow *= ROW_DENSITY_RATIO;
      child.bottomRow *= ROW_DENSITY_RATIO;
    }
    // Based on some trial and error, inputs look better when they are shrunk by 1 row
    // due to the reduced label size. Inputs are not migrated if:
    // a. They are horizontal
    // b. They use a dynamic binding to determine vertical/horizontal (very rare)
    if (
      (child.type === 'INPUT_WIDGET' || child.type === 'DROP_DOWN_WIDGET') &&
      child.isVertical === true &&
      String(child.label).trim().length
    ) {
      child.topRow += 1;
    }

    if (widget.type === 'CANVAS_WIDGET') {
      if (widget.noPad) child.noContainerOffset = true;
    } else {
      child.shouldScrollContents = false;
      child.canExtend = widget.shouldScrollContents;
    }

    // Adjust based on parent widget
    if (
      widget.type === 'CONTAINER_WIDGET' ||
      widget.type === 'FORM_WIDGET' ||
      widget.type === 'GRID_WIDGET' ||
      widget.type === 'TABS_WIDGET'
    ) {
      child.snapColumns = Math.floor((widget.rightColumn! - widget.leftColumn!) / ((widget as any).columnCount ?? 1));
      maxColumns = child.snapColumns;
    } else if (widget.type === 'SLIDEOUT_WIDGET') {
      child.containerStyle = 'none';
      child.minHeight = 800;
      // Seems like some slideouts did not set the bottomRow correctly
      const maxInnerRow = (child.children?.reduce((prev, current) => Math.max(current.bottomRow, prev), 0) ?? 0) * 3;
      child.bottomRow = Math.max(maxInnerRow, Math.ceil(child.minHeight / ROW_HEIGHT));
      child.snapRows = child.bottomRow + 2;
      child.snapColumns = 80; // This produces ~12px wide columns
      maxColumns = child.snapColumns;
    }
    if (widget.type === 'TABS_WIDGET') {
      child.bottomRow -= 3; // the tab header take 3 more rows now.
      child.snapRows! -= 3;
      delete child.minHeight;
    }

    migrate4to5(child, maxColumns);
  });
  return widget;
};
