/**
 * Reusable detail drawer — slides in from the right, loads a fragment URL,
 * supports deep-link via URL hash, and can step through rows on the current
 * grid page.
 *
 * The drawer chrome is rendered server-side by templates/partials/app-detail-drawer.phtml
 * (mounted once in the logged-in shell). This module only attaches behavior
 * via the [data-detail-drawer] selector and never injects markup.
 */

import { getHtml, SessionExpiredError } from '../core/app-http.js';
import { initFragmentContent } from '../core/app-fragment-init.js';
import { createFocusTrap, createScrollLock } from '../core/app-focus-trap.js';

const STATE_KEY = Symbol('detail-drawer-state');

/** Default row-uuid discovery: scrapes the visible Grid.js rows on the page. */
function makeGridRowProvider(gridConfig, rowUuidAttr) {
  if (!gridConfig) { return null; }
  return () => {
    const wrapper = gridConfig?.wrapper || document;
    const rows = wrapper.querySelectorAll(`.gridjs-tr[data-${rowUuidAttr}]`);
    const uuids = [];
    rows.forEach((row) => {
      const uuid = row.getAttribute(`data-${rowUuidAttr}`);
      if (uuid) { uuids.push(uuid); }
    });
    return uuids;
  };
}

export function initDetailDrawer(options = {}) {
  const {
    gridConfig = null,
    triggerSelector = '[data-drawer-trigger]',
    rowSelector = '.gridjs-tr',
    rowUuidAttr = 'uuid',
    rowProvider = null,
    fetchUrl,
    fullUrl,
    hashPrefix = 'detail',
    onContentLoaded = null,
  } = options;

  if (typeof fetchUrl !== 'function') {
    console.warn('[detail-drawer] fetchUrl required');
    return null;
  }

  const root = document.querySelector('[data-detail-drawer]');
  if (!(root instanceof HTMLElement)) {
    console.warn('[detail-drawer] [data-detail-drawer] not in DOM — partial not mounted?');
    return null;
  }
  if (root[STATE_KEY]) { return root[STATE_KEY]; }

  const effectiveRowProvider = typeof rowProvider === 'function'
    ? rowProvider
    : makeGridRowProvider(gridConfig, rowUuidAttr);
  const stepperEnabled = typeof effectiveRowProvider === 'function';

  const panel = root.querySelector('[data-detail-drawer-panel]');
  const backdrop = root.querySelector('[data-detail-drawer-backdrop]');
  const closeButton = root.querySelector('[data-detail-drawer-close]');
  const prevButton = root.querySelector('[data-detail-drawer-prev]');
  const nextButton = root.querySelector('[data-detail-drawer-next]');
  const stepperContainer = root.querySelector('.app-detail-drawer-stepper');
  const fullLink = root.querySelector('[data-detail-drawer-full]');
  const contentEl = root.querySelector('[data-detail-drawer-content]');
  const loadingEl = root.querySelector('[data-detail-drawer-loading]');
  const errorEl = root.querySelector('[data-detail-drawer-error]');

  if (stepperContainer instanceof HTMLElement) {
    stepperContainer.hidden = !stepperEnabled;
  }

  const hashPattern = new RegExp(`^#${hashPrefix}/([^/?#]+)`);
  const focusTrap = createFocusTrap(panel);
  const scrollLock = createScrollLock();
  let lastTrigger = null;

  const api = {
    currentUuid: null,
    isOpen: false,
    open(uuid, opts = {}) {
      const pushHash = opts.pushHash !== false;
      if (!uuid) { return; }
      const wasOpen = api.isOpen;
      api.currentUuid = String(uuid);
      root.hidden = false;
      root.setAttribute('aria-hidden', 'false');
      root.classList.add('is-open');
      document.documentElement.classList.add('app-detail-drawer-open');
      api.isOpen = true;
      if (!wasOpen) {
        lastTrigger = document.activeElement instanceof HTMLElement ? document.activeElement : null;
        scrollLock.lock();
        focusTrap.activate(lastTrigger);
      }
      if (typeof fullUrl === 'function') {
        fullLink.href = fullUrl(uuid);
      }
      if (pushHash) {
        const targetHash = `#${hashPrefix}/${uuid}`;
        if (window.location.hash !== targetHash) {
          history.replaceState(null, '', window.location.pathname + window.location.search + targetHash);
        }
      }
      updateStepper();
      loadContent(uuid);
    },
    close(opts = {}) {
      const clearHash = opts.clearHash !== false;
      if (!api.isOpen) { return; }
      api.isOpen = false;
      api.currentUuid = null;
      root.classList.remove('is-open');
      root.setAttribute('aria-hidden', 'true');
      root.hidden = true;
      document.documentElement.classList.remove('app-detail-drawer-open');
      focusTrap.deactivate();
      scrollLock.unlock();
      lastTrigger = null;
      contentEl.innerHTML = '';
      if (clearHash && hashPattern.test(window.location.hash)) {
        history.replaceState(null, '', window.location.pathname + window.location.search);
      }
    },
    openNext() { step(+1); },
    openPrev() { step(-1); },
  };

  function getRowUuids() {
    if (!stepperEnabled) { return []; }
    try {
      const result = effectiveRowProvider();
      return Array.isArray(result) ? result.filter(Boolean).map(String) : [];
    } catch (err) {
      console.warn('[detail-drawer] rowProvider failed', err);
      return [];
    }
  }

  function step(direction) {
    if (!api.currentUuid || !stepperEnabled) { return; }
    const uuids = getRowUuids();
    const idx = uuids.indexOf(api.currentUuid);
    if (idx < 0) { return; }
    const nextIdx = idx + direction;
    if (nextIdx < 0 || nextIdx >= uuids.length) { return; }
    api.open(uuids[nextIdx]);
  }

  function updateStepper() {
    if (!stepperEnabled) {
      prevButton.disabled = true;
      nextButton.disabled = true;
      return;
    }
    const uuids = getRowUuids();
    const idx = uuids.indexOf(api.currentUuid);
    prevButton.disabled = idx <= 0;
    nextButton.disabled = idx < 0 || idx >= uuids.length - 1;
  }

  async function loadContent(uuid) {
    contentEl.innerHTML = '';
    errorEl.hidden = true;
    loadingEl.hidden = false;
    const url = fetchUrl(uuid);
    try {
      const html = await getHtml(url);
      if (!api.isOpen || api.currentUuid !== String(uuid)) { return; }
      contentEl.innerHTML = html;
      contentEl.querySelectorAll('script').forEach((script) => {
        const replacement = document.createElement('script');
        [...script.attributes].forEach((attr) => replacement.setAttribute(attr.name, attr.value));
        replacement.textContent = script.textContent;
        script.parentNode.replaceChild(replacement, script);
      });
      loadingEl.hidden = true;
      initFragmentContent(contentEl);
      if (typeof onContentLoaded === 'function') {
        try {
          onContentLoaded(contentEl, uuid);
        } catch (hookErr) {
          console.warn('[detail-drawer] onContentLoaded failed', hookErr);
        }
      }
    } catch (err) {
      if (err instanceof SessionExpiredError) {
        api.close({ clearHash: true });
        window.location.reload();
        return;
      }
      loadingEl.hidden = true;
      errorEl.hidden = false;
      console.warn('[detail-drawer] load failed', err);
    }
  }

  document.addEventListener('click', (event) => {
    const trigger = event.target.closest(triggerSelector);
    if (!trigger) { return; }
    if (event.metaKey || event.ctrlKey || event.shiftKey || event.button === 1) {
      return;
    }
    const row = trigger.closest(rowSelector);
    const uuid = row?.getAttribute(`data-${rowUuidAttr}`) || trigger.getAttribute(`data-${rowUuidAttr}`);
    if (!uuid) { return; }
    event.preventDefault();
    api.open(uuid);
  });

  closeButton.addEventListener('click', () => api.close());
  backdrop.addEventListener('click', () => api.close());
  prevButton.addEventListener('click', () => api.openPrev());
  nextButton.addEventListener('click', () => api.openNext());

  document.addEventListener('keydown', (event) => {
    if (!api.isOpen) { return; }
    if (event.key === 'Escape') {
      event.preventDefault();
      api.close();
      return;
    }
    if (event.target instanceof HTMLElement) {
      const tag = event.target.tagName;
      if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || event.target.isContentEditable) {
        return;
      }
    }
    if (event.key === 'j' || event.key === 'ArrowDown') {
      event.preventDefault();
      api.openNext();
    } else if (event.key === 'k' || event.key === 'ArrowUp') {
      event.preventDefault();
      api.openPrev();
    }
  });

  window.addEventListener('hashchange', () => {
    const match = hashPattern.exec(window.location.hash);
    if (match) {
      api.open(match[1], { pushHash: false });
    } else if (api.isOpen) {
      api.close({ clearHash: false });
    }
  });

  const initialMatch = hashPattern.exec(window.location.hash);
  if (initialMatch) {
    requestAnimationFrame(() => api.open(initialMatch[1], { pushHash: false }));
  }

  root[STATE_KEY] = api;
  return api;
}
