// Resolution-anchored layout geometry for the artifact inventory screen
// (ADR-009). The auto scanner requires borderless 16:9 and derives crop/grid
// coordinates from the client rectangle instead of detecting the panel by colour
// each frame. This module is the single, pure, unit-tested source of that
// geometry; electron/main.ts consumes it for cropping and keeps a colour-based
// detail-rect detector only as a fallback for off-profile setups.
//
// Calibrated from a 1920x1080 English artifact-inventory screenshot and scaled
// by client size: fixed 16:9-relative UI regions first, visual detection only as
// a fallback.

export interface LayoutRect {
  x: number;
  y: number;
  width: number;
  height: number;
}

export interface CropTemplateRect {
  id: string;
  label: string;
  rect: LayoutRect;
}

export interface InventoryGridLayout {
  centers: Array<{ x: number; y: number; row: number; col: number }>;
  rows: number;
  cols: number;
  confidence: number;
  source: "detected" | "missing";
}

const SIXTEEN_NINE = 16 / 9;

export function aspectRatio(size: { width: number; height: number }): number {
  if (!size.height) return 0;
  return size.width / size.height;
}

export function aspectRatioLabel(size: { width: number; height: number }): string {
  const ratio = aspectRatio(size);
  if (ratio === 0) return "unknown";
  return `${ratio.toFixed(2)}:1`;
}

// Genshin's UI is authored for 16:9; other aspect ratios letterbox or reflow and
// the anchored crops no longer line up. Allow a small tolerance for rounding.
export function isSixteenNine(size: { width: number; height: number }, tolerance = 0.02): boolean {
  const ratio = aspectRatio(size);
  if (ratio === 0) return false;
  return Math.abs(ratio - SIXTEEN_NINE) <= SIXTEEN_NINE * tolerance;
}

// Empty when the client is a supported 16:9; otherwise a warning explaining that
// the anchored crops are unreliable off-profile (ADR-009: non-16:9 is explicitly
// unsupported for the auto scanner).
export function layoutSupportWarning(size: { width: number; height: number }): string {
  if (size.width <= 0 || size.height <= 0) return "";
  if (isSixteenNine(size)) return "";
  return `Aufloesung ${size.width}x${size.height} ist nicht 16:9 (${aspectRatioLabel(size)}). Der Auto-Scan ist auf 16:9 im randlosen Fenstermodus ausgelegt; die Erkennung kann daneben liegen.`;
}

export function clampRect(rect: LayoutRect, imageSize: { width: number; height: number }): LayoutRect {
  const x = Math.max(0, Math.min(imageSize.width - 1, rect.x));
  const y = Math.max(0, Math.min(imageSize.height - 1, rect.y));
  const maxWidth = Math.max(1, imageSize.width - x);
  const maxHeight = Math.max(1, imageSize.height - y);
  return {
    x,
    y,
    width: Math.max(1, Math.min(maxWidth, rect.width)),
    height: Math.max(1, Math.min(maxHeight, rect.height)),
  };
}

// Anchored guess for the artifact detail panel on the right of the screen. Used
// as the primary rect for a clean 16:9 client and as the fallback when colour
// detection cannot find the panel.
export function profileDetailRect(imageSize: { width: number; height: number }): LayoutRect {
  const { width, height } = imageSize;
  if (width <= 0 || height <= 0) return { x: 0, y: 0, width: Math.max(1, width), height: Math.max(1, height) };
  return clampRect(
    {
      x: Math.round(width * 0.681),
      y: Math.round(height * 0.111),
      width: Math.round(width * 0.256),
      height: Math.round(height * 0.776),
    },
    imageSize,
  );
}

// OCR crops inside the detail panel, as fractions of the detail rect. These are
// deliberately split-card oriented instead of using the older broad crops:
// small fields get small OCR profiles, while the legacy parser still accepts
// old review samples with artifact-title/artifact-main-stat.
export function detailCropRects(
  detailRect: LayoutRect,
  imageSize: { width: number; height: number },
  options: { sanctified?: boolean; fastProfile?: boolean } = {},
): CropTemplateRect[] {
  const sanctifiedShift = options.sanctified ? 0.0520 : 0;
  const substatsHeight = options.fastProfile ? 0.1841 : 0.2301;
  const templates: CropTemplateRect[] = [
    {
      id: "artifact-name",
      label: "Artifact name",
      rect: {
        x: Math.round(detailRect.x),
        y: Math.round(detailRect.y),
        width: Math.round(detailRect.width),
        height: Math.round(detailRect.height * 0.07),
      },
    },
    {
      id: "artifact-slot",
      label: "Artifact slot",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.0405),
        y: Math.round(detailRect.y + detailRect.height * 0.0772),
        width: Math.round(detailRect.width * 0.4757),
        height: Math.round(detailRect.height * 0.0475),
      },
    },
    {
      id: "artifact-main-stat-label",
      label: "Main stat label",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.0405),
        y: Math.round(detailRect.y + detailRect.height * 0.1722),
        width: Math.round(detailRect.width * 0.4555),
        height: Math.round(detailRect.height * 0.0416),
      },
    },
    {
      id: "artifact-main-stat-value",
      label: "Main stat value",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.055),
        y: Math.round(detailRect.y + detailRect.height * 0.205),
        width: Math.round(detailRect.width * 0.42),
        height: Math.round(detailRect.height * 0.105),
      },
    },
    {
      id: "artifact-level",
      label: "Artifact level",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.0506),
        y: Math.round(detailRect.y + detailRect.height * (0.3634 + sanctifiedShift)),
        width: Math.round(detailRect.width * 0.1417),
        height: Math.round(detailRect.height * 0.0416),
      },
    },
    {
      id: "artifact-substats",
      label: "Substats",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.0605),
        y: Math.round(detailRect.y + detailRect.height * (0.4216 + sanctifiedShift)),
        width: Math.round(detailRect.width * 0.8297),
        height: Math.round(detailRect.height * substatsHeight),
      },
    },
    {
      id: "artifact-set-effects",
      label: "Set effects",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.055),
        y: Math.round(detailRect.y + detailRect.height * 0.655),
        width: Math.round(detailRect.width * 0.86),
        height: Math.round(detailRect.height * 0.16),
      },
    },
    {
      id: "artifact-footer",
      label: "Footer",
      rect: {
        x: Math.round(detailRect.x + detailRect.width * 0.15),
        y: Math.round(detailRect.y + detailRect.height * 0.938),
        width: Math.round(detailRect.width * 0.86),
        height: Math.round(detailRect.height * 0.06),
      },
    },
  ];

  return templates.map((template) => ({ ...template, rect: clampRect(template.rect, imageSize) }));
}

export function inventoryCountCropRect(inventoryRect: LayoutRect, imageSize: { width: number; height: number }): LayoutRect {
  const { width, height } = imageSize;
  return clampRect(
    {
      x: Math.round(width * 0.795),
      y: Math.round(height * 0.02),
      width: Math.round(width * 0.145),
      height: Math.round(height * 0.055),
    },
    imageSize,
  );
}

export function inventoryRect(imageSize: { width: number; height: number }, detailRect: LayoutRect): LayoutRect {
  const { width, height } = imageSize;
  return clampRect(
    {
      x: Math.round(width * 0.055),
      y: Math.round(height * 0.155),
      width: Math.max(140, Math.round(Math.min(detailRect.x - width * 0.07, width * 0.63))),
      height: Math.max(140, Math.round(height * 0.74)),
    },
    imageSize,
  );
}

export function inventoryGrid(imageSize: { width: number; height: number }, detailRect: LayoutRect): InventoryGridLayout {
  const rect = inventoryRect(imageSize, detailRect);
  const cols = 8;
  if (imageSize.width < 800 || imageSize.height < 450 || rect.width < 160 || rect.height < 140) {
    return { centers: [], rows: 0, cols: 0, confidence: 0, source: "missing" };
  }

  const stepX = Math.round(imageSize.width * 0.076);
  const stepY = Math.round(imageSize.height * 0.163);
  // The artifact inventory has 32 safe click targets per full page. The
  // apparent fifth row sits in the bottom control band on 16:9 captures and is
  // not a reliable target during automated scrolling.
  const visibleRows = 4;

  const startX = Math.round(imageSize.width * 0.093);
  const startY = Math.round(imageSize.height * 0.235);
  const centers: InventoryGridLayout["centers"] = [];
  for (let row = 0; row < visibleRows; row++) {
    for (let col = 0; col < cols; col++) {
      const x = startX + col * stepX;
      const y = startY + row * stepY;
      if (x < imageSize.width && y < imageSize.height) {
        centers.push({ x, y, row, col });
      }
    }
  }

  const trimmed = centers.filter((center) => center.x > 0 && center.y > 0);
  return {
    centers: trimmed,
    rows: visibleRows,
    cols,
    confidence: trimmed.length >= cols * 2 ? 76 : trimmed.length >= cols ? 58 : 36,
    source: "detected",
  };
}
