import { BDM_ACT_RECTS_LS, BDM_AUTO_ZOOM_LS, ZOOM_MAX, ZOOM_MIN } from '../config/constants.js';
import { $ } from '../core/dom.js';
import { api } from '../core/api.js';
import { readLs, writeLs } from '../core/storage.js';
import { scheduleUserPreferencesSave } from '../services/preferences.js';
import { getCurrentProjectKind, isCurrentProjectBdm, resolveFieldConfigRootKind } from '../services/project-context.js';
import { state, userPrefsStore, runtime } from '../state/app-state.js';
import { bumpImageViewerTabRequestToken, getNextImageFor, imageViewerTabRequestToken, prefetchCache, setImageViewerTab, workPrefetchKey } from './events.js';
import { applyImageTransform, fitImageToViewAfterLoad } from './highlight.js';
import { setStatus } from './status-bar.js';

export function getBdmAutoZoomEnabled() {
  if (userPrefsStore.bdm_auto_zoom === true) return true;
  if (userPrefsStore.bdm_auto_zoom === false) return false;
  try {
    const cur = readLs(BDM_AUTO_ZOOM_LS);
    if (cur === "0") return false;
    if (cur === "1") return true;
    const legacyView = readLs("datafixBdmImageView_v1");
    if (legacyView === "raw") {
      writeLs(BDM_AUTO_ZOOM_LS, "0");
      return false;
    }
  } catch (_) {
    /* ignore */
  }
  return false;
}


export function setBdmAutoZoomEnabled(on) {
  writeLs(BDM_AUTO_ZOOM_LS, on ? "1" : "0");
  scheduleUserPreferencesSave({ bdm_auto_zoom: !!on });
  const t = $("bdmAutoZoomToggle");
  if (t) t.checked = !!on;
}


export function getBdmActRectsEnabled() {
  if (userPrefsStore.bdm_act_rects === true) return true;
  if (userPrefsStore.bdm_act_rects === false) return false;
  try {
    const cur = readLs(BDM_ACT_RECTS_LS);
    if (cur === "0") return false;
    if (cur === "1") return true;
  } catch (_) {
    /* ignore */
  }
  return false;
}


export function syncBdmAutoZoomToggleUi() {
  const t = $("bdmAutoZoomToggle");
  if (!t) return;
  const actsOn = !!state.bdmActsEnabled;
  t.disabled = !actsOn;
  t.checked = getBdmAutoZoomEnabled();
  const lab = t.closest(".bdm-auto-zoom");
  if (lab) {
    lab.title = actsOn
      ? "Recadrage manuel prioritaire, puis 1re acte détecté (si disponible), sinon région de page."
      : "Activez « Acts » pour utiliser l'auto-zoom.";
    lab.setAttribute("aria-label", actsOn ? "Auto zoom" : "Auto zoom (Acts requis)");
  }
}


export function syncBdmActsToggleUi() {
  const btn = $("bdmActsToggle");
  if (btn) {
    const wrap = btn.closest(".topbar-toggle-check");
    const inBdmImageView = isWorkBdmImageView();
    const canUseActs = inBdmImageView && isCurrentProjectBdm();
    if (wrap) wrap.hidden = !inBdmImageView;
    btn.disabled = !canUseActs;
    btn.checked = canUseActs && !!state.bdmActsEnabled;
  }
  syncBdmAutoZoomToggleUi();
}


export function setBdmActRectsEnabled(on) {
  state.bdmActsEnabled = isCurrentProjectBdm() && !!on;
  writeLs(BDM_ACT_RECTS_LS, state.bdmActsEnabled ? "1" : "0");
  scheduleUserPreferencesSave({ bdm_act_rects: !!state.bdmActsEnabled });
  syncBdmActsToggleUi();
  renderActRectsOverlay();
  if (isWorkBdmImageView()) requestAnimationFrame(() => applyBdmViewZoom());
}

/** First act rect usable for zoom/overlay ({ x, y, w, h } in image pixels). */

export function getFirstValidBdmActCropRect(work) {
  const wk = work;
  if (!wk || !Array.isArray(wk.bdm_act_rects)) return null;
  for (let i = 0; i < wk.bdm_act_rects.length; i += 1) {
    const act = wk.bdm_act_rects[i];
    if (!act || act.x == null || act.y == null || act.w == null || act.h == null) continue;
    const x = parseInt(String(act.x), 10);
    const y = parseInt(String(act.y), 10);
    const rw = parseInt(String(act.w), 10);
    const rh = parseInt(String(act.h), 10);
    if (![x, y, rw, rh].every(Number.isFinite) || rw <= 0 || rh <= 0) continue;
    return { x, y, w: rw, h: rh };
  }
  return null;
}

/**
 * Zoom/pan so that rect {x,y,w,h} (original image pixels) fills the viewport.
 * Returns true if applied, false if conditions not met.
 */

export function zoomToCropRect(rect) {
  if (!rect || !rect.w || !rect.h) return false;
  const wrap = $("imgWrap");
  const img = $("pageImg");
  if (!wrap || !img || !img.naturalWidth) return false;
  const cs = window.getComputedStyle(wrap);
  const pw = parseFloat(cs.paddingLeft || "0") + parseFloat(cs.paddingRight || "0");
  const ph = parseFloat(cs.paddingTop || "0") + parseFloat(cs.paddingBottom || "0");
  const vw = Math.max(8, wrap.clientWidth - pw);
  const vh = Math.max(8, wrap.clientHeight - ph);
  const MARGIN = 0.04;
  const zFitW = vw / (rect.w * (1 + MARGIN));
  const zFitH = vh / (rect.h * (1 + MARGIN));
  let z = Math.round(Math.min(zFitW, zFitH) * 100);
  z = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, z));
  state.zoom = z;
  const scale = z / 100;
  const cx = rect.x + rect.w / 2;
  const cy = rect.y + rect.h / 2;
  state.panX = vw / 2 - cx * scale;
  state.panY = vh / 2 - cy * scale;
  applyImageTransform();
  return true;
}

/**
 * BDM: auto zoom only when Acts is on and the toggle is saved — manual crop, first act
 * (eligible doc types), then page region. Never reloads the image.
 */

export function applyBdmViewZoom() {
  const w = state.work;
  if (!isWorkBdmImageView() || !w) {
    fitImageToViewAfterLoad();
    return;
  }
  if (state.bdmActsEnabled && getBdmAutoZoomEnabled()) {
    if (w.bdm_manual_crop && zoomToCropRect(w.bdm_manual_crop)) return;
    if (isCurrentWorkActDetectionEligible() && zoomToCropRect(getFirstValidBdmActCropRect(w))) return;
    if (w.bdm_auto_rect && zoomToCropRect(w.bdm_auto_rect)) return;
  }
  fitImageToViewAfterLoad();
}


export function imageViewUrl(baseUrl) {
  return baseUrl || "";
}


export function syncBdmToolbarFromStorage() {
  state.bdmActsEnabled = isCurrentProjectBdm() && getBdmActRectsEnabled();
  syncBdmActsToggleUi();
  syncBdmImageTabs();
}


export function syncBdmPanInputsFromState() {
  const ix = $("bdmPanXInput");
  const iy = $("bdmPanYInput");
  if (ix) ix.value = String(Math.round(state.panX));
  if (iy) iy.value = String(Math.round(state.panY));
}


export function commitBdmPanFromInputs() {
  const elx = $("bdmPanXInput");
  const ely = $("bdmPanYInput");
  if (!elx && !ely) return;
  const nx = elx ? parseInt(String(elx.value || "").trim(), 10) : NaN;
  const ny = ely ? parseInt(String(ely.value || "").trim(), 10) : NaN;
  if (Number.isFinite(nx)) state.panX = nx;
  if (Number.isFinite(ny)) state.panY = ny;
  applyImageTransform();
}

/**
 * True when this batch uses BDM image routes (crop / manual). Must match server _is_batch_bdm.
 * Older work payloads without bdm_batch fall back to getCurrentProjectKind().
 */

export function isWorkBdmImageView() {
  if (!state.work || !state.work.image_file_url) return false;
  if (typeof state.work.bdm_batch === "boolean") return state.work.bdm_batch;
  return resolveFieldConfigRootKind(getCurrentProjectKind()) === "BDM";
}


export function isActDetectionDocType(docType) {
  const normalized = String(docType || "")
    .trim()
    .toUpperCase()
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[-_]+/g, " ")
    .replace(/\s+/g, " ");
  return normalized === "BIRTH"
    || normalized === "DEATH"
    || normalized === "MARRIAGE"
    || normalized === "MIXED"
    || normalized === "NAISSANCE"
    || normalized === "NAISSANCES"
    || normalized === "DECES"
    || normalized === "MARIAGE"
    || normalized === "MARIAGES";
}


export function isCurrentWorkActDetectionEligible() {
  if (!isWorkBdmImageView() || !state.work) return false;
  return isActDetectionDocType(state.work.form_type);
}


export function updateBdmToolbarVisibility() {
  const tb = $("bdmViewToolbar");
  const panStatus = $("statusPan");
  const isBdm = isWorkBdmImageView();
  if (!tb) return;
  tb.hidden = !isBdm;
  if (panStatus) panStatus.hidden = !isBdm;
  syncBdmActsToggleUi();
  syncBdmImageTabs();
  renderActRectsOverlay();
  void applyImageViewerTab();
}


export function renderActRectsOverlay() {
  const layer = $("actRectsLayer");
  if (!layer) return;
  layer.innerHTML = "";

  if (state.imageViewerTab === "next") {
    layer.hidden = true;
    return;
  }

  if (!state.bdmActsEnabled || !isCurrentWorkActDetectionEligible() || !state.work) {
    layer.hidden = true;
    return;
  }

  const acts = Array.isArray(state.work.bdm_act_rects) ? state.work.bdm_act_rects : [];
  if (!acts.length) {
    layer.hidden = true;
    return;
  }

  acts.forEach((act) => {
    if (!act || act.x == null || act.y == null || act.w == null || act.h == null) return;
    const x = parseInt(String(act.x), 10);
    const y = parseInt(String(act.y), 10);
    const w = parseInt(String(act.w), 10);
    const h = parseInt(String(act.h), 10);
    if (![x, y, w, h].every(Number.isFinite) || w <= 0 || h <= 0) return;

    const box = document.createElement("div");
    box.className = "act-rect";
    box.style.left = `${x}px`;
    box.style.top = `${y}px`;
    box.style.width = `${w}px`;
    box.style.height = `${h}px`;

    const label = document.createElement("span");
    label.className = "act-rect__label";
    const actId = parseInt(String(act.id == null ? "" : act.id), 10);
    const confRaw = parseFloat(String(act.confidence == null ? "" : act.confidence));
    const conf = Number.isFinite(confRaw) ? confRaw : null;
    label.textContent = conf != null
      ? `A${Number.isFinite(actId) ? actId : "?"} ${conf.toFixed(2)}`
      : `A${Number.isFinite(actId) ? actId : "?"}`;
    box.appendChild(label);
    layer.appendChild(box);
  });

  layer.hidden = layer.childElementCount === 0;
}


export function applyDeferredWorkDetection(det, forImageId) {
  if (!state.work || state.work.image_id !== forImageId) return;
  if (det && Object.prototype.hasOwnProperty.call(det, "bdm_auto_rect")) {
    state.work.bdm_auto_rect = det.bdm_auto_rect;
  }
  state.work.bdm_act_rects = det && Array.isArray(det.bdm_act_rects) ? det.bdm_act_rects : [];
  state.work.bdm_detection_pending = false;
  requestAnimationFrame(() => {
    if (isWorkBdmImageView()) {
      applyBdmViewZoom();
    }
    renderActRectsOverlay();
  });
}


export function reloadCurrentImageWithView() {
  applyBdmViewZoom();
}


export function initBdmImageControls() {
  syncBdmToolbarFromStorage();
  const t = $("bdmAutoZoomToggle");
  if (t) {
    t.addEventListener("change", function () {
      setBdmAutoZoomEnabled(!!t.checked);
      requestAnimationFrame(() => applyBdmViewZoom());
    });
  }
  const acts = $("bdmActsToggle");
  if (acts) {
    acts.addEventListener("change", function () {
      setBdmActRectsEnabled(!!acts.checked);
    });
  }
  const btnToggle = $("btnToggleNextImage");
  if (btnToggle) {
    btnToggle.addEventListener("click", function () {
      toggleImageViewerTab();
    });
  }
  const elx = $("bdmPanXInput");
  const ely = $("bdmPanYInput");
  function onPanFocus() {
    runtime.bdmPanInputEditing = true;
  }
  function onPanBlur() {
    runtime.bdmPanInputEditing = false;
    commitBdmPanFromInputs();
  }
  function onPanKeydown(e, el) {
    if (e.key === "Enter") {
      e.preventDefault();
      el.blur();
    }
    if (e.key === "Escape") {
      e.preventDefault();
      runtime.bdmPanInputEditing = false;
      syncBdmPanInputsFromState();
      el.blur();
    }
  }
  if (elx) {
    elx.addEventListener("focus", onPanFocus);
    elx.addEventListener("blur", onPanBlur);
    elx.addEventListener("keydown", (e) => onPanKeydown(e, elx));
  }
  if (ely) {
    ely.addEventListener("focus", onPanFocus);
    ely.addEventListener("blur", onPanBlur);
    ely.addEventListener("keydown", (e) => onPanKeydown(e, ely));
  }
}


export function syncBdmImageTabs() {
  const btnToggle = $("btnToggleNextImage");
  const isBdm = isWorkBdmImageView();
  if (!btnToggle) return;
  btnToggle.hidden = !isBdm;
  const nextMeta = state.work ? getNextImageFor(state.work.image_id) : null;
  if (state.imageViewerTab === "next" && !nextMeta) {
    state.imageViewerTab = "current";
  }
  const onNext = state.imageViewerTab === "next";
  btnToggle.disabled = !nextMeta;
  btnToggle.classList.toggle("is-active", onNext);
  btnToggle.setAttribute("aria-pressed", onNext ? "true" : "false");
  btnToggle.textContent = onNext ? "\u25C0" : "\u25B6";
  const nextLabel = onNext
    ? "Revenir à l'image courante"
    : "Voir l'image suivante";
  btnToggle.setAttribute("aria-label", nextLabel);
  btnToggle.title = nextMeta ? nextLabel : "Pas d'image suivante";
}


export async function ensureNextImageWorkLoaded() {
  if (!state.work) return null;
  const nextMeta = getNextImageFor(state.work.image_id);
  if (!nextMeta) {
    runtime.nextImageWork = null;
    return null;
  }
  if (runtime.nextImageWork && runtime.nextImageWork.image_id === nextMeta.image_id) {
    return runtime.nextImageWork;
  }
  const token = bumpImageViewerTabRequestToken();
  try {
    const cacheKey = workPrefetchKey(state.batch, nextMeta.image_id);
    if (prefetchCache[cacheKey]) {
      runtime.nextImageWork = await prefetchCache[cacheKey];
    } else {
      runtime.nextImageWork = await api(`/api/batch/${encodeURIComponent(state.batch)}/work/${nextMeta.image_id}`);
    }
    if (token !== imageViewerTabRequestToken) return null;
    return runtime.nextImageWork;
  } catch (_) {
    if (token !== imageViewerTabRequestToken) return null;
    runtime.nextImageWork = null;
    return null;
  }
}


export async function applyImageViewerTab() {
  const pageImgEl = $("pageImg");
  const imgPanEl = $("imgPan");
  const noImgEl = $("noImg");
  if (!pageImgEl || !imgPanEl || !noImgEl) return;
  noImgEl.textContent = "Sélectionnez un lot puis une image.";

  if (!state.work) {
    imgPanEl.hidden = true;
    noImgEl.hidden = false;
    syncBdmImageTabs();
    return;
  }

  syncBdmImageTabs();

  if (state.imageViewerTab !== "next") {
    const layer = $("actRectsLayer");
    if (layer) {
      layer.innerHTML = "";
      layer.hidden = true;
    }
    if (!state.work.image_file_url) {
      imgPanEl.hidden = true;
      noImgEl.hidden = false;
      return;
    }
    pageImgEl.src = state.work.image_file_url;
    imgPanEl.hidden = false;
    noImgEl.hidden = true;
    return;
  }

  const nextMeta = getNextImageFor(state.work.image_id);
  if (!nextMeta) {
    state.imageViewerTab = "current";
    syncBdmImageTabs();
    pageImgEl.src = state.work.image_file_url || "";
    imgPanEl.hidden = !state.work.image_file_url;
    noImgEl.hidden = !!state.work.image_file_url;
    return;
  }

  setStatus("Chargement image suivante...");
  const nextWork = await ensureNextImageWorkLoaded();
  if (!nextWork || !nextWork.image_file_url) {
    imgPanEl.hidden = true;
    noImgEl.hidden = false;
    noImgEl.textContent = "Image suivante introuvable.";
    return;
  }
  noImgEl.textContent = "Sélectionnez un lot puis une image.";
  const layer = $("actRectsLayer");
  if (layer) {
    layer.innerHTML = "";
    layer.hidden = true;
  }
  pageImgEl.src = imageViewUrl(nextWork.image_file_url);
  imgPanEl.hidden = false;
  noImgEl.hidden = true;
}


export function toggleImageViewerTab() {
  setImageViewerTab(state.imageViewerTab === "next" ? "current" : "next");
}
