import { getCardDef } from "./widgets/cardRegistry";

export const DASHBOARD_GRID_COLUMNS = 12;

export type LayoutItem = {
  i: string;
  x: number;
  y: number;
  w: number;
  h: number;
  minW?: number;
  minH?: number;
  maxW?: number;
  maxH?: number;
};

type NormalizedLayoutResult = {
  layout: LayoutItem[];
  didUpgradeLegacyLayout: boolean;
};

type LegacyBlueprintItem = {
  i: string;
  rowIndex: number;
  x: number;
  w: number;
  h: number;
};

function buildLegacyBlueprint(cards: string[]): LegacyBlueprintItem[] {
  const blueprint: LegacyBlueprintItem[] = [];
  let x = 0;
  let rowIndex = 0;

  cards.forEach((cardId) => {
    const def = getCardDef(cardId);
    if (!def) return;

    if (x + def.defaultW > DASHBOARD_GRID_COLUMNS) {
      x = 0;
      rowIndex += 1;
    }

    blueprint.push({
      i: cardId,
      rowIndex,
      x,
      w: def.defaultW,
      h: def.defaultH,
    });

    x += def.defaultW;

    if (x >= DASHBOARD_GRID_COLUMNS) {
      x = 0;
      rowIndex += 1;
    }
  });

  return blueprint;
}

function stretchRowToFillWidth(items: LayoutItem[]): LayoutItem[] {
  const stretched = items.map((item) => ({ ...item }));
  let remainingWidth = DASHBOARD_GRID_COLUMNS - stretched.reduce((total, item) => total + item.w, 0);

  while (remainingWidth > 0) {
    let expandedAnyItem = false;

    for (const item of stretched) {
      if (remainingWidth === 0) break;

      const maxWidth = item.maxW ?? DASHBOARD_GRID_COLUMNS;
      if (item.w >= maxWidth) continue;

      item.w += 1;
      remainingWidth -= 1;
      expandedAnyItem = true;
    }

    if (!expandedAnyItem) break;
  }

  let currentX = 0;
  return stretched.map((item) => {
    const nextItem = { ...item, x: currentX };
    currentX += item.w;
    return nextItem;
  });
}

export function enrichDashboardLayout(layout: LayoutItem[]): LayoutItem[] {
  return layout.map((item) => {
    const def = getCardDef(item.i);

    return {
      ...item,
      minW: def?.minW ?? item.minW ?? 2,
      minH: def?.minH ?? item.minH ?? 2,
      maxW: def?.maxW ?? item.maxW,
      maxH: def?.maxH ?? item.maxH,
    };
  });
}

export function generateLegacyDashboardLayout(cards: string[]): LayoutItem[] {
  return buildLegacyBlueprint(cards).map((item) => {
    const def = getCardDef(item.i);

    return {
      i: item.i,
      x: item.x,
      y: item.rowIndex * 3,
      w: item.w,
      h: item.h,
      minW: def?.minW,
      minH: def?.minH,
      maxW: def?.maxW,
      maxH: def?.maxH,
    };
  });
}

export function generateDashboardLayout(cards: string[]): LayoutItem[] {
  const rows: LayoutItem[][] = [];
  let currentRow: LayoutItem[] = [];
  let currentRowWidth = 0;

  cards.forEach((cardId) => {
    const def = getCardDef(cardId);
    if (!def) return;

    const nextItem: LayoutItem = {
      i: cardId,
      x: 0,
      y: 0,
      w: def.defaultW,
      h: def.defaultH,
      minW: def.minW,
      minH: def.minH,
      maxW: def.maxW,
      maxH: def.maxH,
    };

    if (currentRow.length > 0 && currentRowWidth + nextItem.w > DASHBOARD_GRID_COLUMNS) {
      rows.push(stretchRowToFillWidth(currentRow));
      currentRow = [nextItem];
      currentRowWidth = nextItem.w;
      return;
    }

    currentRow.push(nextItem);
    currentRowWidth += nextItem.w;

    if (currentRowWidth >= DASHBOARD_GRID_COLUMNS) {
      rows.push(stretchRowToFillWidth(currentRow));
      currentRow = [];
      currentRowWidth = 0;
    }
  });

  if (currentRow.length > 0) {
    rows.push(stretchRowToFillWidth(currentRow));
  }

  let currentY = 0;

  return rows.flatMap((row) => {
    const rowHeight = Math.max(...row.map((item) => item.h), 1);
    const positionedRow = row.map((item) => ({ ...item, y: currentY }));
    currentY += rowHeight;
    return positionedRow;
  });
}

export function shouldUpgradeLegacyDashboardLayout(cards: string[], layout: LayoutItem[]): boolean {
  const legacyBlueprint = buildLegacyBlueprint(cards);
  if (legacyBlueprint.length === 0 || legacyBlueprint.length !== layout.length) {
    return false;
  }

  const layoutById = new Map(layout.map((item) => [item.i, item]));
  const uniqueRows = [...new Set(layout.map((item) => item.y))].sort((a, b) => a - b);
  const rowRankByY = new Map(uniqueRows.map((y, index) => [y, index]));

  return legacyBlueprint.every((expected) => {
    const saved = layoutById.get(expected.i);
    if (!saved) return false;

    return (
      saved.x === expected.x &&
      saved.w === expected.w &&
      saved.h === expected.h &&
      rowRankByY.get(saved.y) === expected.rowIndex
    );
  });
}

export function normalizeSavedDashboardLayout(cards: string[], layout: LayoutItem[]): NormalizedLayoutResult {
  const didUpgradeLegacyLayout = shouldUpgradeLegacyDashboardLayout(cards, layout);

  return {
    layout: didUpgradeLegacyLayout ? generateDashboardLayout(cards) : enrichDashboardLayout(layout),
    didUpgradeLegacyLayout,
  };
}