import type { ReactNode } from 'react';
import { getTodayGadgetFeatureOrder } from '@/components/today/today-gadget-order';

/** Dashboard grid is always 4 columns (at lg+). Widgets use fixed width/height units. */
export type TodayDashboardWidth = 1 | 2;
export type TodayDashboardHeight = 1 | 2 | 3;

export interface TodayDashboardLayout {
  width: TodayDashboardWidth;
  height: TodayDashboardHeight;
}

/** Shared layout presets — assign when registering a dashboard widget. */
export const TODAY_DASHBOARD_LAYOUT = {
  kpi: { width: 1, height: 1 },
  subscription: { width: 1, height: 2 },
  upcoming: { width: 2, height: 3 },
  /** Week area charts (appointments, lab task activity). */
  chartArea: { width: 2, height: 2 },
  /** Vertical / horizontal bar charts. */
  chartBar: { width: 2, height: 3 },
  /** @deprecated Prefer chartArea (height 2) or chartBar (height 3). */
  chart: { width: 2, height: 3 },
  /** @deprecated Use chartArea or chartBar */
  chartMedium: { width: 2, height: 2 },
} as const satisfies Record<string, TodayDashboardLayout>;

export interface TodayDashboardCell {
  id: string;
  layout: TodayDashboardLayout;
  content: ReactNode;
}

export interface PackedDashboardCell extends TodayDashboardCell {
  gridColumn: string;
  gridRow: string;
}

export function compareDashboardLayout(
  a: TodayDashboardLayout,
  b: TodayDashboardLayout,
): number {
  if (a.width !== b.width) return a.width - b.width;
  return a.height - b.height;
}

export function sortDashboardCells<T extends { layout: TodayDashboardLayout; id: string }>(
  cells: T[],
): T[] {
  return [...cells].sort((a, b) => {
    const byLayout = compareDashboardLayout(a.layout, b.layout);
    if (byLayout !== 0) return byLayout;

    const byFeature = getTodayGadgetFeatureOrder(a.id) - getTodayGadgetFeatureOrder(b.id);
    if (byFeature !== 0) return byFeature;

    return a.id.localeCompare(b.id);
  });
}

/** Wide widgets (width > 1) anchor to column pairs — never straddle the grid center. */
export function allowedStartColumns(
  width: number,
  columns: number,
): number[] {
  if (width <= 1) {
    return Array.from({ length: columns }, (_, index) => index);
  }

  if (width === 2 && columns === 4) {
    return [0, 2];
  }

  return Array.from({ length: columns - width + 1 }, (_, index) => index);
}

/**
 * First-fit placement in ascending layout order (top-left scan).
 * Multi-column widgets may only start at aligned column pairs (1–2 or 3–4 on a 4-col grid).
 */
export function packDashboardCells(
  cells: TodayDashboardCell[],
  columns = 4,
): PackedDashboardCell[] {
  const sorted = sortDashboardCells(cells);
  const occupied = new Set<string>();

  function canPlace(row: number, col: number, width: number, height: number): boolean {
    if (col + width > columns) return false;
    for (let r = row; r < row + height; r += 1) {
      for (let c = col; c < col + width; c += 1) {
        if (occupied.has(`${r}-${c}`)) return false;
      }
    }
    return true;
  }

  function mark(row: number, col: number, width: number, height: number) {
    for (let r = row; r < row + height; r += 1) {
      for (let c = col; c < col + width; c += 1) {
        occupied.add(`${r}-${c}`);
      }
    }
  }

  const placed: PackedDashboardCell[] = [];

  for (const cell of sorted) {
    const { width, height } = cell.layout;
    let found = false;
    const startColumns = allowedStartColumns(width, columns);

    for (let row = 0; !found; row += 1) {
      for (const col of startColumns) {
        if (!canPlace(row, col, width, height)) continue;
        mark(row, col, width, height);
        placed.push({
          ...cell,
          gridColumn: `${col + 1} / span ${width}`,
          gridRow: `${row + 1} / span ${height}`,
        });
        found = true;
        break;
      }
    }
  }

  return placed;
}

export function packedCellClassName(layout: TodayDashboardLayout): string {
  const rowSpan =
    layout.height === 3 ? 'row-span-3' : layout.height === 2 ? 'row-span-2' : 'row-span-1';

  const colSpan =
    layout.width === 2
      ? 'col-span-2 max-sm:col-span-1'
      : 'col-span-1';

  return `${colSpan} ${rowSpan} min-h-0 min-w-0 overflow-hidden flex flex-col max-lg:${colSpan}`;
}

export const TODAY_DASHBOARD_GRID_CLASS =
  'today-dashboard-grid grid grid-cols-4 max-lg:grid-cols-2 max-sm:grid-cols-1 gap-4';
