import { useEffect, useMemo, useState } from "react";

import type { FileMeta, Session, TemplateFields } from "../types/session";
import { formatDocNumber } from "../lib/report";

type JobSheetTemplateProps = {
  session: Session | null;
  pageIndex: number;
  pageCount: number;
  template?: TemplateFields;
  photos?: FileMeta[];
  orderLocked?: boolean;
  variant?: "full" | "photos";
  sectionLabel?: string;
  photoLayout?: "auto" | "two-column" | "stacked";
};

type PhotoSlotProps = {
  url?: string;
  label: string;
  className?: string;
  imageClassName?: string;
};

type LayoutEntry = {
  photo: FileMeta;
  span: boolean;
};

type RatingTone = {
  label: string;
  bg: string;
  text: string;
  border: string;
};

const CATEGORY_SCALE: Record<string, RatingTone> = {
  "0": {
    label: "(100% Original Strength)",
    bg: "bg-green-100",
    text: "text-green-800",
    border: "border-green-200",
  },
  "1": {
    label: "(100% Original Strength)",
    bg: "bg-green-200",
    text: "text-green-800",
    border: "border-green-200",
  },
  "2": {
    label: "(95-100% Original Strength)",
    bg: "bg-yellow-100",
    text: "text-yellow-800",
    border: "border-yellow-200",
  },
  "3": {
    label: "(75-95% Original Strength)",
    bg: "bg-yellow-200",
    text: "text-yellow-800",
    border: "border-yellow-200",
  },
  "4": {
    label: "(50-75% Original Strength)",
    bg: "bg-orange-200",
    text: "text-orange-800",
    border: "border-orange-200",
  },
  "5": {
    label: "(<50% Original Strength)",
    bg: "bg-red-200",
    text: "text-red-800",
    border: "border-red-200",
  },
};

const PRIORITY_SCALE: Record<string, RatingTone> = {
  "1": {
    label: "(Immediate)",
    bg: "bg-red-200",
    text: "text-red-800",
    border: "border-red-200",
  },
  "2": {
    label: "(1 Year)",
    bg: "bg-orange-200",
    text: "text-orange-800",
    border: "border-orange-200",
  },
  "3": {
    label: "(3 Years)",
    bg: "bg-green-200",
    text: "text-green-800",
    border: "border-green-200",
  },
  X: {
    label: "(At Use)",
    bg: "bg-purple-200",
    text: "text-purple-800",
    border: "border-purple-200",
  },
  M: {
    label: "(Monitor)",
    bg: "bg-blue-200",
    text: "text-blue-800",
    border: "border-blue-200",
  },
};

function ratingKey(value: string) {
  const raw = (value || "").trim();
  if (!raw) return "";
  const match = raw.match(/^([0-9]|[xXmM])/);
  if (match) return match[1].toUpperCase();
  return raw.split("")[0].trim().toUpperCase();
}

function formatRating(value: string, scale: Record<string, RatingTone>) {
  const raw = (value || "").trim();
  const key = ratingKey(raw);
  const tone = key ? scale[key] : undefined;
  if (!tone) {
    return {
      text: raw || "",
      className: "bg-gray-50 text-gray-700 border-gray-200",
    };
  }
  return {
    text: `${key} ${tone.label}`,
    className: `${tone.bg} ${tone.text} ${tone.border}`,
  };
}

function normalizeKey(value: string) {
  return value.toLowerCase().replace(/[^a-z0-9]/g, "");
}

function photoKey(photo: FileMeta) {
  return photo.id || photo.url || photo.name || "";
}

function photoUrl(photo: FileMeta) {
  return photo.url || "";
}

function resolveLogoUrl(session: Session | null, rawValue?: string) {
  const value = (rawValue || "").trim();
  if (!value) return "";
  if (/^(https?:|data:|\/)/i.test(value)) return value;

  const uploads = session?.uploads?.photos ?? [];
  const key = normalizeKey(value);
  for (const photo of uploads) {
    if (photo.id && value === photo.id) {
      return photo.url || "";
    }
    const name = photo.name || "";
    if (!name) continue;
    const nameKey = normalizeKey(name);
    const stemKey = normalizeKey(name.replace(/\.[^/.]+$/, ""));
    if (key == nameKey || key == stemKey) {
      return photo.url || "";
    }
  }
  return "";
}

function computeLayout(photos: FileMeta[], ratios: Record<string, number>): LayoutEntry[] {
  const entries = photos.map((photo) => {
    const key = photoKey(photo);
    return {
      photo,
      ratio: key ? ratios[key] ?? 1 : 1,
    };
  });

  const memo = new Map<string, { cost: number; rows: number[][] }>();

  function solve(remaining: number[]): { cost: number; rows: number[][] } {
    if (remaining.length == 0) {
      return { cost: 0, rows: [] };
    }
    const cacheKey = remaining.join(",");
    const cached = memo.get(cacheKey);
    if (cached) return cached;

    const [first, ...rest] = remaining;
    let bestCost = Number.POSITIVE_INFINITY;
    let bestRows: number[][] = [];

    const single = solve(rest);
    const singleCost = 2 * entries[first].ratio + single.cost;
    if (singleCost < bestCost) {
      bestCost = singleCost;
      bestRows = [[first], ...single.rows];
    }

    for (let i = 0; i < rest.length; i += 1) {
      const pair = rest[i];
      const next = rest.filter((_, idx) => idx != i);
      const result = solve(next);
      const pairCost = Math.max(entries[first].ratio, entries[pair].ratio) + result.cost;
      if (pairCost < bestCost) {
        bestCost = pairCost;
        bestRows = [[first, pair], ...result.rows];
      }
    }

    const value = { cost: bestCost, rows: bestRows };
    memo.set(cacheKey, value);
    return value;
  }

  const indices = entries.map((_, index) => index);
  const solution = solve(indices);
  const layout: LayoutEntry[] = [];
  solution.rows.forEach((row) => {
    if (row.length == 1) {
      layout.push({ photo: entries[row[0]].photo, span: true });
    } else {
      layout.push({ photo: entries[row[0]].photo, span: false });
      layout.push({ photo: entries[row[1]].photo, span: false });
    }
  });
  return layout;
}

function PhotoSlot({ url, label, className = "", imageClassName = "" }: PhotoSlotProps) {
  if (!url) {
    return (
      <div
        className={[
          "min-h-[120px] w-full rounded-lg border border-dashed border-gray-300 bg-gray-50 flex items-center justify-center text-xs text-gray-500 break-inside-avoid mb-3",
          className,
        ].join(" ")}
        style={{ breakInside: "avoid", pageBreakInside: "avoid" }}
      >
        No photo selected
      </div>
    );
  }
  return (
    <figure
      className={[
        "rounded-lg border border-gray-200 bg-gray-50 p-2 pb-3 break-inside-avoid flex flex-col gap-1 overflow-hidden",
        className,
      ].join(" ")}
      style={{ breakInside: "avoid", pageBreakInside: "avoid" }}
    >
      <div className="w-full flex-1 flex items-center justify-center">
        <img
          src={url}
          alt={label}
          className={["w-full object-contain max-h-[240px]", imageClassName].join(
            " ",
          )}
          loading="eager"
        />
      </div>
      <figcaption className="text-[10px] text-gray-600 text-center break-all leading-tight">
        {label}
      </figcaption>
    </figure>
  );
}

export function JobSheetTemplate({
  session,
  pageIndex,
  pageCount,
  template,
  photos,
  orderLocked = false,
  variant = "full",
  sectionLabel,
  photoLayout = "auto",
}: JobSheetTemplateProps) {
  const inspectionDate =
    template?.inspection_date ?? session?.inspection_date ?? "";
  const inspector = template?.inspector ?? "";
  const docNumber =
    template?.document_no ??
    session?.document_no ??
    (session?.id ? formatDocNumber(session) : "");
  const companyLogo = template?.company_logo ?? "";
  const figureCaption = template?.figure_caption ?? "";

  const reference = template?.reference ?? "";
  const area = template?.area ?? "";
  const itemDescription = template?.item_description ?? "";
  const functionalLocation = template?.functional_location ?? "";
  const category = template?.category ?? "";
  const priority = template?.priority ?? "";
  const requiredAction = template?.required_action ?? "";

  const conditionText = itemDescription;
  const actionText = requiredAction;
  const categoryBadge = formatRating(category, CATEGORY_SCALE);
  const priorityBadge = formatRating(priority, PRIORITY_SCALE);

  const resolvedPhotos = photos && photos.length ? photos : [];
  const limitedPhotos = resolvedPhotos.slice(0, 6);
  const logoUrl = resolveLogoUrl(session, companyLogo);
  const [ratios, setRatios] = useState<Record<string, number>>({});

  useEffect(() => {
    let active = true;
    const pending = limitedPhotos.filter((photo) => {
      const key = photoKey(photo);
      return key && !ratios[key] && photoUrl(photo);
    });
    if (!pending.length) return undefined;

    pending.forEach((photo) => {
      const key = photoKey(photo);
      const url = photoUrl(photo);
      if (!key || !url) return;
      const img = new Image();
      img.onload = () => {
        if (!active) return;
        const ratio = img.naturalWidth ? img.naturalHeight / img.naturalWidth : 1;
        setRatios((prev) => ({ ...prev, [key]: ratio || 1 }));
      };
      img.src = url;
    });

    return () => {
      active = false;
    };
  }, [limitedPhotos, ratios]);

  const orderedPhotos = useMemo(() => {
    if (!limitedPhotos.length) return [];
    if (orderLocked) return limitedPhotos;
    const layout = computeLayout(limitedPhotos, ratios);
    return layout.map((entry) => entry.photo);
  }, [limitedPhotos, ratios, orderLocked]);

  const displayedPhotos =
    variant === "full" ? orderedPhotos.slice(0, 2) : orderedPhotos;

  const normalizedLayout = (photoLayout || "auto").toLowerCase();
  const layoutMode =
    normalizedLayout === "stacked" || normalizedLayout === "two-column"
      ? normalizedLayout
      : "auto";
  const photoGridClass =
    layoutMode === "stacked"
      ? "grid grid-cols-1 gap-3"
      : layoutMode === "two-column"
        ? "grid grid-cols-2 gap-3"
        : displayedPhotos.length <= 1
          ? "grid grid-cols-1 gap-3"
          : "grid grid-cols-2 gap-3";

  return (
    <div className="w-full h-full p-5 text-[11px] text-gray-700 flex flex-col">
      <header className="mb-3 border-b border-gray-200 pb-2">
        <div className="grid grid-cols-[auto,1fr,auto] items-center gap-3">
          <img
            src="/assets/prosento-logo.png"
            alt="Prosento logo"
            className="h-14 w-auto object-contain"
          />
          <div className="text-center leading-tight">
            <div className="text-base font-semibold text-gray-900">
              {docNumber || "-"}
            </div>
          </div>
          {logoUrl ? (
            <img
              src={logoUrl}
              alt="Company logo"
              className="h-14 w-auto object-contain"
            />
          ) : (
            <div className="h-14 min-w-[140px] rounded-md border border-dashed border-gray-300 px-2 text-[9px] font-semibold text-gray-400 flex items-center justify-center text-center">
              Company Logo not found
            </div>
          )}
        </div>
      </header>

      {variant === "full" ? (
        <section className="mb-2" aria-labelledby="observations-title">
          <h2
            id="observations-title"
            className="text-[10px] font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-1"
          >
            Observations and Findings
          </h2>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
            <div className="md:col-span-2">
              <div className="grid grid-cols-3 gap-2">
                <div className="space-y-0.5">
                  <div className="text-[9px] font-medium text-gray-500">Ref</div>
                  <div className="template-field text-[10px] font-semibold text-gray-900">
                    {reference}
                  </div>
                </div>
                <div className="space-y-0.5">
                  <div className="text-[9px] font-medium text-gray-500">Area</div>
                  <div className="template-field text-[10px] font-semibold text-gray-900">
                    {area}
                  </div>
                </div>
                <div className="space-y-0.5">
                  <div className="text-[9px] font-medium text-gray-500">Location</div>
                  <div className="template-field text-[10px] font-semibold text-gray-900">
                    {functionalLocation}
                  </div>
                </div>
              </div>
            </div>

            <div className="md:col-span-2 flex justify-center">
              <div className="inline-flex items-center gap-4">
                <div className="text-center space-y-1">
                  <div className="text-[9px] font-medium text-gray-500">
                    Category
                  </div>
                  <span
                    className={[
                      "template-field inline-flex items-center justify-center rounded-md border px-4 py-1 text-[10px] font-semibold min-w-[120px]",
                      categoryBadge.className,
                    ].join(" ")}
                  >
                    {categoryBadge.text}
                  </span>
                </div>

                <div className="text-center space-y-1">
                  <div className="text-[9px] font-medium text-gray-500">
                    Priority
                  </div>
                  <span
                    className={[
                      "template-field inline-flex items-center justify-center rounded-md border px-4 py-1 text-[10px] font-semibold min-w-[120px]",
                      priorityBadge.className,
                    ].join(" ")}
                  >
                    {priorityBadge.text}
                  </span>
                </div>

              </div>
            </div>

            <div className="md:col-span-2 space-y-1">
              <div className="text-[9px] font-medium text-gray-500">
                Condition Description
              </div>
              <div className="bg-gray-50 border-l-4 border-gray-300 p-1.5 rounded-sm">
                <p className="template-field template-field-multiline text-gray-700 text-[9px] font-medium leading-snug">
                  {conditionText}
                </p>
              </div>
            </div>

            <div className="md:col-span-2 space-y-1">
              <div className="text-[9px] font-medium text-gray-500">
                Action Required
              </div>
              <div className="bg-gray-50 border-l-4 border-gray-300 p-1.5 rounded-sm">
                <p className="template-field template-field-multiline text-gray-700 text-[9px] font-medium leading-snug">
                  {actionText}
                </p>
              </div>
            </div>
          </div>
        </section>
      ) : null}

      <section className="mb-3 avoid-break flex-1 min-h-0 flex flex-col">
        <div className="text-[10px] font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-2">
          {variant === "photos" ? "Photo Documentation (continued)" : "Photo Documentation"}
        </div>
        <div className={`${photoGridClass} flex-1 items-stretch`}>
          {displayedPhotos.length === 0 ? (
            <PhotoSlot url={undefined} label="No photo selected" className="h-full" />
          ) : (
            displayedPhotos.map((photo, index) => (
              <PhotoSlot
                key={photo?.id || `${index}`}
                url={photo?.url}
                label={figureCaption || photo?.name || `Figure ${index + 1}`}
                className="h-full"
              />
            ))
          )}
        </div>
      </section>

      <footer className="mt-2 text-[10px] text-gray-500 flex flex-col items-center gap-1">
        <div className="flex flex-wrap items-center justify-center gap-3">
          <span>Date: {inspectionDate || "-"}</span>
          <span>Inspector: {inspector || "-"}</span>
          <span>Doc: {docNumber || "-"}</span>
        </div>
        <div className="text-[10px] font-semibold text-gray-600">
          RepEx Inspection Job Sheet
        </div>
        <div className="text-[10px] text-gray-500">
          {sectionLabel ? `${sectionLabel} - ` : ""}
          Page {pageIndex + 1} of {pageCount}
        </div>
      </footer>
    </div>
  );
}
