/**
 * Shared storage and helpers for the personalized dashboard.
 * Used by both the main Dashboard (add-to-personalized button) and PersonalizedDashboard page.
 */

export const STORAGE_KEY = "personalizedDashboardWidgets";
export const LAYOUT_STORAGE_KEY = "personalizedDashboardLayout";

export const DEFAULT_WIDGET_WIDTH = 320;
export const DEFAULT_WIDGET_HEIGHT = 280;

/** Grid layout: X/Y axis. Looser = fewer cols, taller rows, so placement feels less strict. */
export const GRID_COLS = 18;
export const GRID_ROW_HEIGHT_PX = 100;
export const GRID_COL_WIDTH_PX = 48;

/** Widget ids that can be added to the personalized dashboard. Each has default size and min/max width/height. */
export const WIDGET_OPTIONS = [

  { id: "stats",
    label: "Summary stats (Total Audits, Compliance, Findings, Answers)",
    description: "Key metrics cards",
    defaultWidth: 720,
    defaultHeight: 200,
    minWidth: 400,
    minHeight: 180,
    maxWidth: 960,
    maxHeight: 400,
  },
  { id: "statTotalAudits",
    label: "Total Audits",
    description: "All audits created (planned and in progress)",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "statComplianceRate",
    label: "Compliance Rate",
    description: "Audit completion rate (form submissions)",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "statCriticalFindings",
    label: "Critical Findings",
    description: "Audits with RPN 32–128",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "statTotalUsers",
    label: "Total Users",
    description: "Total users in the system",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "answersTrend",
    label: "Answers trend (Audits per Month)",
    description: "Form submissions and answers over time",
    defaultWidth: 480,
    defaultHeight: 360,
    minWidth: 400,
    minHeight: 320,
    maxWidth: 960,
    maxHeight: 720,
  },
  { id: "topSites",
    label: "Top Sites by Compliance",
    description: "Sites list with scores",
    defaultWidth: 400,
    defaultHeight: 360,
    minWidth: 360,
    minHeight: 320,
    maxWidth: 960,
    maxHeight: 720,
  },
  { id: "recentActivities",
    label: "Recent Activities",
    description: "Latest activity feed",
    defaultWidth: 400,
    defaultHeight: 360,
    minWidth: 360,
    minHeight: 320,
    maxWidth: 960,
    maxHeight: 720,
  },
  { id: "rpnAuditBar",
    label: "Audits by RPN Value",
    description: "Bar chart of audit counts by RPN (1–128)",
    defaultWidth: 480,
    defaultHeight: 320,
    minWidth: 320,
    minHeight: 280,
    maxWidth: 960,
    maxHeight: 500,
  },
  { id: "severityOfHarm",
    label: "Severity of Harm",
    description: "Pie chart of severity distribution",
    defaultWidth: 340,
    defaultHeight: 320,
    minWidth: 280,
    minHeight: 280,
    maxWidth: 600,
    maxHeight: 500,
  },
  { id: "likelihoodOfHarm",
    label: "Likelihood of Harm",
    description: "Pie chart of likelihood distribution",
    defaultWidth: 340,
    defaultHeight: 320,
    minWidth: 280,
    minHeight: 280,
    maxWidth: 600,
    maxHeight: 500,
  },
  { id: "observationsOpenClosed",
    label: "Observations: Open vs Closed",
    description: "Bar chart of open vs closed observations",
    defaultWidth: 440,
    defaultHeight: 300,
    minWidth: 320,
    minHeight: 280,
    maxWidth: 960,
    maxHeight: 500,
  },
  { id: "sioOioCaPie",
    label: "Observation types (SIO / OIO / CA)",
    description: "Donut chart of SIO, OIO and CA observation counts",
    defaultWidth: 380,
    defaultHeight: 360,
    minWidth: 280,
    minHeight: 320,
    maxWidth: 640,
    maxHeight: 520,
  },
  { id: "sioPctCard",
    label: "SIO %",
    description: "Share of observations that are SIO",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "oioPctCard",
    label: "OIO %",
    description: "Share of observations that are OIO",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "sioPaPctCard",
    label: "SIO PA %",
    description: "Percentage of SIO audits that are closed",
    defaultWidth: 260,
    defaultHeight: 180,
    minWidth: 220,
    minHeight: 160,
    maxWidth: 400,
    maxHeight: 280,
  },
  { id: "raStatsCompleted", 
    label: "RA: Completed", 
    description: "Risk assessments marked as completed", 
    defaultWidth: 260, 
    defaultHeight: 180, 
    minWidth: 220, 
    minHeight: 160, 
    maxWidth: 400, 
    maxHeight: 280 
  },
  { id: "raStatsInProgress", 
    label: "RA: In Progress", 
    description: "Risk assessments currently in progress", 
    defaultWidth: 260, 
    defaultHeight: 180, 
    minWidth: 220, 
    minHeight: 160, 
    maxWidth: 400, 
    maxHeight: 280 
  },
  { id: "raStatsNotStarted", 
    label: "RA: Not Started", 
    description: "Risk assessments not yet started", 
    defaultWidth: 260, 
    defaultHeight: 180, 
    minWidth: 220, 
    minHeight: 160, 
    maxWidth: 400, 
    maxHeight: 280 
  },
  { id: "raStatsTotal", 
    label: "RA: Total", 
    description: "Total number of risk assessments", 
    defaultWidth: 260, 
    defaultHeight: 180, 
    minWidth: 220, 
    minHeight: 160, 
    maxWidth: 400, 
    maxHeight: 280 
  },
  { id: "raRecentAssessments", 
    label: "RA: Recent Assessments", 
    description: "Table of recent risk assessments", 
    defaultWidth: 480, 
    defaultHeight: 360, 
    minWidth: 400, 
    minHeight: 320, 
    maxWidth: 960, 
    maxHeight: 720 
  },
  { id: "raStatusBreakdown", 
    label: "RA: Status Breakdown", 
    description: "Distribution of risk assessments by status", 
    defaultWidth: 400, 
    defaultHeight: 360, 
    minWidth: 320, 
    minHeight: 280, 
    maxWidth: 960, 
    maxHeight: 720 
  },
  { id: "raTrendChart",
    label: "RA: Assessment Trends",
    description: "Area chart of assigned and completed assessments over time",
    defaultWidth: 560,
    defaultHeight: 380,
    minWidth: 400,
    minHeight: 300,
    maxWidth: 960,
    maxHeight: 600,
  },
  { id: "raLocationDrilldown",
    label: "RA: Location Breakdown",
    description: "Pie chart of assessment completion by country, location and department",
    defaultWidth: 640,
    defaultHeight: 460,
    minWidth: 480,
    minHeight: 380,
    maxWidth: 960,
    maxHeight: 720,
  },
  { id: "swiStatsSummary",
    label: "SWI: Summary stats",
    description: "My SWIs, remaining, completed, and location totals",
    defaultWidth: 520,
    defaultHeight: 200,
    minWidth: 360,
    minHeight: 160,
    maxWidth: 720,
    maxHeight: 280,
  },
  { id: "swiLocationChart",
    label: "SWI: Location-wise chart",
    description: "SWI counts grouped by plant location",
    defaultWidth: 420,
    defaultHeight: 320,
    minWidth: 320,
    minHeight: 240,
    maxWidth: 720,
    maxHeight: 480,
  },
  { id: "swiUserStatusChart",
    label: "SWI: Your status chart",
    description: "Your assigned SWIs broken down by status",
    defaultWidth: 420,
    defaultHeight: 320,
    minWidth: 320,
    minHeight: 240,
    maxWidth: 720,
    maxHeight: 480,
  },
  { id: "swiAssignmentTrend",
    label: "SWI: Assignments over time",
    description: "Monthly assignment trend for your SWIs",
    defaultWidth: 560,
    defaultHeight: 340,
    minWidth: 400,
    minHeight: 260,
    maxWidth: 960,
    maxHeight: 520,
  },
  { id: "swiRemaining",
    label: "SWI: Remaining work",
    description: "Remaining vs completed SWIs with progress",
    defaultWidth: 400,
    defaultHeight: 260,
    minWidth: 320,
    minHeight: 200,
    maxWidth: 640,
    maxHeight: 400,
  },
  { id: "swiRecentUndone",
    label: "SWI: Recent undone (5)",
    description: "Latest five SWIs that still need action",
    defaultWidth: 440,
    defaultHeight: 340,
    minWidth: 360,
    minHeight: 260,
    maxWidth: 720,
    maxHeight: 520,
  },
];

/**
 * Get min/max width and height for a widget from WIDGET_OPTIONS.
 * @param {string} widgetId
 * @returns {{ minWidth: number, minHeight: number, maxWidth: number, maxHeight: number }}
 */
export function getWidgetSizeLimits(widgetId) {
  const option = WIDGET_OPTIONS.find((w) => w.id === widgetId);
  return {
    minWidth: option?.minWidth ?? 280,
    minHeight: option?.minHeight ?? 200,
    maxWidth: option?.maxWidth ?? 960,
    maxHeight: option?.maxHeight ?? 720,
  };
}

/**
 * Get default width/height for a widget. Uses per-widget defaults from WIDGET_OPTIONS when set, otherwise global defaults. Clamped to widget's min/max.
 * @param {string} widgetId
 * @returns {{ width: number, height: number }}
 */
export function getDefaultWidgetSize(widgetId) {
  const option = WIDGET_OPTIONS.find((w) => w.id === widgetId);
  const w = option?.defaultWidth ?? DEFAULT_WIDGET_WIDTH;
  const h = option?.defaultHeight ?? DEFAULT_WIDGET_HEIGHT;
  const { minWidth, minHeight, maxWidth, maxHeight } = getWidgetSizeLimits(widgetId);
  return {
    width: Math.min(maxWidth, Math.max(minWidth, w)),
    height: Math.min(maxHeight, Math.max(minHeight, h)),
  };
}

/**
 * Get default grid size (w, h) in grid units for a widget. Clamped to grid limits.
 * @param {string} widgetId
 * @returns {{ w: number, h: number }}
 */
export function getDefaultGridSize(widgetId) {
  const { width, height } = getDefaultWidgetSize(widgetId);
  const { minW, minH, maxW, maxH } = getWidgetGridLimits(widgetId);
  const w = Math.min(maxW, Math.max(minW, Math.round(width / GRID_COL_WIDTH_PX)));
  const h = Math.min(maxH, Math.max(minH, Math.round(height / GRID_ROW_HEIGHT_PX)));
  return { w, h };
}

/**
 * Get min/max grid size (w, h) in grid units for a widget.
 * @param {string} widgetId
 * @returns {{ minW: number, minH: number, maxW: number, maxH: number }}
 */
export function getWidgetGridLimits(widgetId) {
  const { minWidth, minHeight, maxWidth, maxHeight } = getWidgetSizeLimits(widgetId);
  return {
    minW: Math.max(1, Math.round(minWidth / GRID_COL_WIDTH_PX)),
    minH: Math.max(1, Math.round(minHeight / GRID_ROW_HEIGHT_PX)),
    maxW: Math.min(GRID_COLS, Math.round(maxWidth / GRID_COL_WIDTH_PX)),
    maxH: Math.max(1, Math.round(maxHeight / GRID_ROW_HEIGHT_PX)),
  };
}

/**
 * Find next free (x, y) in grid so a box of size minW x minH fits. Row-major order.
 * @param {Array<{ x: number, y: number, w: number, h: number }>} occupied
 * @param {number} minW
 * @param {number} minH
 * @returns {{ x: number, y: number }}
 */
export function findNextGridPosition(occupied, minW = 1, minH = 1) {
  const overlaps = (x, y, w, h) =>
    occupied.some(
      (o) =>
        x < o.x + o.w &&
        x + w > o.x &&
        y < o.y + o.h &&
        y + h > o.y
    );
  for (let y = 0; y < 200; y++) {
    for (let x = 0; x <= GRID_COLS - minW; x++) {
      if (!overlaps(x, y, minW, minH)) return { x, y };
    }
  }
  return { x: 0, y: 0 };
}

/**
 * Reposition overlapping widgets so none overlap. Processes in top-left order and moves overlapping ones to next free slot.
 * @param {Record<string, { x: number, y: number, w: number, h: number }>} layout
 * @param {string[]} widgetIds
 * @returns {Record<string, { x: number, y: number, w: number, h: number }>}
 */
export function resolveOverlaps(layout, widgetIds) {
  const result = { ...layout };
  const placed = [];
  const ids = widgetIds && widgetIds.length ? widgetIds : Object.keys(result);
  const sorted = [...ids].sort((a, b) => {
    const pa = result[a];
    const pb = result[b];
    if (!pa || !pb) return 0;
    if (pa.y !== pb.y) return pa.y - pb.y;
    return pa.x - pb.x;
  });
  for (const id of sorted) {
    let box = result[id];
    if (!box || !Number.isFinite(box.x)) {
      const { w, h } = getDefaultGridSize(id);
      box = { x: 0, y: 0, w, h };
    }
    const w = Math.max(1, box.w ?? 1);
    const h = Math.max(1, box.h ?? 1);
    const overlaps = placed.some(
      (p) =>
        box.x < p.x + p.w &&
        box.x + w > p.x &&
        box.y < p.y + p.h &&
        box.y + h > p.y
    );
    if (overlaps) {
      const limits = getWidgetGridLimits(id);
      const cw = Math.min(limits.maxW, Math.max(limits.minW, w));
      const ch = Math.min(limits.maxH, Math.max(limits.minH, h));
      const next = findNextGridPosition(placed, cw, ch);
      box = { x: next.x, y: next.y, w: cw, h: ch };
      result[id] = box;
    }
    placed.push({ x: box.x, y: box.y, w: box.w ?? 1, h: box.h ?? 1 });
  }
  return result;
}

/**
 * Migrate legacy pixel layout to grid layout (x, y, w, h). Fills positions in selectedWidgets order.
 * @param {Record<string, { width?: number, height?: number, x?: number, y?: number, w?: number, h?: number }>} layout
 * @param {string[]} selectedWidgets
 * @returns {Record<string, { x: number, y: number, w: number, h: number }>}
 */
export function migrateLayoutToGrid(layout, selectedWidgets) {
  const out = {};
  const occupied = [];
  const ids = selectedWidgets && selectedWidgets.length ? selectedWidgets : Object.keys(layout || {});
  for (const id of ids) {
    const entry = layout && layout[id];
    let x, y, w, h;
    if (entry && Number.isFinite(entry.x) && Number.isFinite(entry.y) && Number.isFinite(entry.w) && Number.isFinite(entry.h)) {
      const limits = getWidgetGridLimits(id);
      x = entry.x;
      y = entry.y;
      w = Math.min(limits.maxW, Math.max(limits.minW, entry.w));
      h = Math.min(limits.maxH, Math.max(limits.minH, entry.h));
    } else {
      const pixel = entry && Number.isFinite(entry.width) && Number.isFinite(entry.height)
        ? { width: entry.width, height: entry.height }
        : getDefaultWidgetSize(id);
      const limits = getWidgetGridLimits(id);
      w = Math.min(limits.maxW, Math.max(limits.minW, Math.round(pixel.width / GRID_COL_WIDTH_PX)));
      h = Math.min(limits.maxH, Math.max(limits.minH, Math.round(pixel.height / GRID_ROW_HEIGHT_PX)));
      const next = findNextGridPosition(occupied, w, h);
      x = next.x;
      y = next.y;
    }
    out[id] = { x, y, w, h };
    occupied.push({ x, y, w, h });
  }
  return out;
}

export function loadSelectedWidgets() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parsed.filter((id) => WIDGET_OPTIONS.some((w) => w.id === id)) : [];
  } catch {
    return [];
  }
}

export function saveSelectedWidgets(ids) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
  } catch (_) {}
}

/**
 * Load layout from storage. Returns grid format { id: { x, y, w, h } }. Migrates legacy pixel layout when needed.
 * @param {string[]} [selectedWidgets] - Used to migrate legacy layout and assign positions
 * @returns {Record<string, { x: number, y: number, w: number, h: number }>}
 */
export function loadLayout(selectedWidgets = []) {
  try {
    const raw = localStorage.getItem(LAYOUT_STORAGE_KEY);
    let parsed = {};
    if (raw) {
      const p = JSON.parse(raw);
      if (typeof p === "object" && p !== null) parsed = p;
    }
    const ids = selectedWidgets.length ? selectedWidgets : Object.keys(parsed);
    const migrated = migrateLayoutToGrid(parsed, ids);
    const resolved = resolveOverlaps(migrated, ids);
    if (JSON.stringify(resolved) !== JSON.stringify(migrated)) saveLayout(resolved);
    return resolved;
  } catch {
    return {};
  }
}

export function saveLayout(layout) {
  try {
    localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(layout));
  } catch (_) {}
}

/**
 * Add a widget to the personalized dashboard (persist to localStorage). Assigns next free grid position.
 * @param {string} widgetId - One of WIDGET_OPTIONS[].id
 * @returns {boolean} - true if the widget was added, false if it was already present
 */
export function addWidgetToPersonalizedDashboard(widgetId) {
  if (!WIDGET_OPTIONS.some((w) => w.id === widgetId)) return false;
  const ids = loadSelectedWidgets();
  if (ids.includes(widgetId)) return false;
  const nextIds = [...ids, widgetId];
  saveSelectedWidgets(nextIds);
  const layout = loadLayout(nextIds);
  const { w, h } = getDefaultGridSize(widgetId);
  const occupied = nextIds.filter((id) => id !== widgetId).map((id) => layout[id]).filter(Boolean);
  const { x, y } = findNextGridPosition(occupied, w, h);
  layout[widgetId] = { x, y, w, h };
  saveLayout(layout);
  return true;
}

export function isWidgetInPersonalizedDashboard(widgetId) {
  return loadSelectedWidgets().includes(widgetId);
}
