import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import type { CSSProperties } from "react";

import type { FileMeta, Page, Session, TemplateFields } from "../types/session";
import { BASE_H, BASE_W } from "../lib/report";
import { JobSheetTemplate } from "./JobSheetTemplate";

type ReportPageCanvasProps = {
  session: Session | null;
  page: Page | null;
  pageIndex: number;
  pageCount: number;
  scale: number;
  template?: TemplateFields;
  sectionLabel?: string;
  className?: string;
  adaptive?: boolean;
};

export function ReportPageCanvas({
  session,
  page,
  pageIndex,
  pageCount,
  scale,
  template,
  sectionLabel,
  className = "",
  adaptive = false,
}: ReportPageCanvasProps) {
  const items = page?.items ?? [];
  const safeScale = Number.isFinite(scale) && scale > 0 ? scale : 1;
  const pageVariant = page?.variant ?? "full";
  const photos = resolvePagePhotos(session, page, pageIndex);
  const sheets = adaptive ? [photos] : [photos];
  const sheetRefs = useRef<Array<HTMLDivElement | null>>([]);
  const [sheetHeights, setSheetHeights] = useState<number[]>([]);

  const defaultHeight = BASE_H * safeScale;
  const resolvedHeights = useMemo(() => {
    if (sheetHeights.length !== sheets.length) {
      return sheets.map(() => defaultHeight);
    }
    return sheetHeights.map((height) => (height > 0 ? height : defaultHeight));
  }, [defaultHeight, sheetHeights, sheets.length]);

  const offsets = useMemo(() => {
    const values: number[] = [];
    let running = 0;
    resolvedHeights.forEach((height) => {
      values.push(running);
      running += height;
    });
    return values;
  }, [resolvedHeights]);

  const containerHeight = resolvedHeights.reduce((sum, height) => sum + height, 0);

  const measureHeights = () => {
    const next = sheets.map((_, index) => {
      const node = sheetRefs.current[index];
      if (!node) return defaultHeight;
      const rect = node.getBoundingClientRect();
      return rect.height || defaultHeight;
    });
    setSheetHeights((prev) => {
      if (prev.length === next.length && prev.every((val, idx) => Math.abs(val - next[idx]) < 1)) {
        return prev;
      }
      return next;
    });
  };

  useLayoutEffect(() => {
    measureHeights();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sheets.length, safeScale]);

  useEffect(() => {
    const observer = new ResizeObserver(() => measureHeights());
    sheetRefs.current.forEach((node) => {
      if (node) observer.observe(node);
    });
    return () => observer.disconnect();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sheets.length]);

  return (
    <div
      className={["relative w-full", className].join(" ")}
      style={{ height: `${containerHeight}px` }}
    >
      <div className="absolute inset-0 pointer-events-none">
        {sheets.map((sheetPhotos, sheetIndex) => (
          <div
            key={`sheet-${sheetIndex}`}
            style={{
              position: "absolute",
              top: `${offsets[sheetIndex] ?? 0}px`,
              left: 0,
              width: `${BASE_W * safeScale}px`,
              height: `${resolvedHeights[sheetIndex] ?? defaultHeight}px`,
            }}
          >
            <div
              ref={(node) => {
                sheetRefs.current[sheetIndex] = node;
              }}
              style={{
                width: `${BASE_W}px`,
                minHeight: `${BASE_H}px`,
                transform: `scale(${safeScale})`,
                transformOrigin: "top left",
              }}
            >
              {page?.blank ? (
                <div className="w-full h-full bg-white" />
              ) : (
                  <JobSheetTemplate
                    session={session}
                    pageIndex={pageIndex}
                    pageCount={pageCount}
                    template={template}
                    photos={sheetPhotos}
                    orderLocked={page?.photo_order_locked ?? false}
                    variant={pageVariant}
                    sectionLabel={sectionLabel}
                    photoLayout={page?.photo_layout}
                  />
              )}
            </div>
          </div>
        ))}
      </div>

      {items
        .slice()
        .sort((a, b) => (a.z ?? 0) - (b.z ?? 0))
        .map((item) => {
          const itemStyle: CSSProperties = {
            position: "absolute",
            left: `${item.x * safeScale}px`,
            top: `${item.y * safeScale}px`,
            width: `${item.w * safeScale}px`,
            height: `${item.h * safeScale}px`,
            zIndex: item.z ?? 0,
          };

          if (item.type === "text") {
            return (
              <div key={item.id} style={itemStyle}>
                <div
                  className="w-full h-full p-2 overflow-hidden"
                  style={{
                    whiteSpace: "pre-wrap",
                    fontSize: `${(item.style?.fontSize ?? 14) * safeScale}px`,
                    fontWeight: item.style?.bold ? 700 : 400,
                    fontStyle: item.style?.italic ? "italic" : "normal",
                    textDecoration: item.style?.underline ? "underline" : "none",
                    color: item.style?.color ?? "#111827",
                    textAlign: item.style?.align ?? "left",
                  }}
                >
                  {item.content ?? ""}
                </div>
              </div>
            );
          }

          if (item.type === "image") {
            return (
              <div key={item.id} style={itemStyle}>
                <img
                  src={item.src}
                  alt={item.name ?? "Image"}
                  className="w-full h-full object-contain bg-white"
                  loading="eager"
                />
              </div>
            );
          }

          return (
            <div key={item.id} style={itemStyle}>
              <div
                className="w-full h-full"
                style={{
                  background: item.style?.fill ?? "#ffffff",
                  borderStyle: "solid",
                  borderColor: item.style?.stroke ?? "#111827",
                  borderWidth: `${(item.style?.strokeWidth ?? 1) * safeScale}px`,
                }}
              />
            </div>
          );
        })}
    </div>
  );
}

function resolvePagePhotos(
  session: Session | null,
  page: Page | null | undefined,
  pageIndex: number,
): FileMeta[] {
  if (!session) return [];
  const uploads = session.uploads?.photos ?? [];
  const byId = new Map(uploads.map((photo) => [photo.id, photo]));
  const explicit = page?.photo_ids ?? [];
  if (explicit.length) {
    return explicit.map((id) => byId.get(id)).filter(Boolean) as FileMeta[];
  }
  return [];
}
