import { defineTrait } from '../define.js';

const EDGE = 8;    // edge hit-zone thickness
const CORNER = 14; // corner hit-zone (square, sits on top of the edges it overlaps)

// Edges resize one axis; corners resize both (x/y at once). `dw`/`dh` are the sign
// applied to the pointer delta (dx/dy): +1 grows from this side, -1 grows from the
// opposite (anchored) side, 0 leaves that axis untouched. Corners are listed LAST so
// they're appended after the edges and win the hit-test where they overlap.
const HANDLES = [
  { name: 'top',          dw: 0,  dh: -1, cursor: 'ns-resize',   geo: { top: '0', left: '0', right: '0', height: `${EDGE}px` } },
  { name: 'right',        dw: 1,  dh: 0,  cursor: 'ew-resize',   geo: { top: '0', right: '0', bottom: '0', width: `${EDGE}px` } },
  { name: 'bottom',       dw: 0,  dh: 1,  cursor: 'ns-resize',   geo: { bottom: '0', left: '0', right: '0', height: `${EDGE}px` } },
  { name: 'left',         dw: -1, dh: 0,  cursor: 'ew-resize',   geo: { top: '0', left: '0', bottom: '0', width: `${EDGE}px` } },
  { name: 'top-left',     dw: -1, dh: -1, cursor: 'nwse-resize', geo: { top: '0', left: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
  { name: 'top-right',    dw: 1,  dh: -1, cursor: 'nesw-resize', geo: { top: '0', right: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
  { name: 'bottom-right', dw: 1,  dh: 1,  cursor: 'nwse-resize', geo: { bottom: '0', right: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
  { name: 'bottom-left',  dw: -1, dh: 1,  cursor: 'nesw-resize', geo: { bottom: '0', left: '0', width: `${CORNER}px`, height: `${CORNER}px` } },
];

export const resizable = defineTrait({
  name: 'resizable',
  category: 'motion-positioning',
  description: 'Drag edges/corners to resize',
  attributes: ['data-resizable-resizing', 'data-resizable-edge'],
  events: ['resize-end'],
  config: [],
  setup({ host }) {
    let resizing = false;
    let active = null;
    let startX = 0;
    let startY = 0;
    let startWidth = 0;
    let startHeight = 0;
    let centerX = 0;
    let centerY = 0;
    let symmetric = false;
    const handles = [];

    // Ensure host is positioned so the absolute hit-zones anchor to it.
    if (getComputedStyle(host).position === 'static') {
      host.style.position = 'relative';
    }

    for (const h of HANDLES) {
      const handle = document.createElement('div');
      handle.dataset.resizableHandle = h.name;
      Object.assign(handle.style, { position: 'absolute', zIndex: '9999', cursor: h.cursor, ...h.geo });

      handle.addEventListener('pointerdown', (e) => {
        e.stopPropagation();
        resizing = true;
        active = h.name;
        startX = e.clientX;
        startY = e.clientY;
        const rect = host.getBoundingClientRect();
        startWidth = rect.width;
        startHeight = rect.height;
        centerX = rect.left + rect.width / 2;
        centerY = rect.top + rect.height / 2;
        // A transform-positioned host re-centers itself as it resizes (e.g.
        // translate(-50%,-50%) centering), so resize SYMMETRICALLY from the center
        // and the dragged edge/corner stays under the cursor. A static/anchored host
        // instead grows from the opposite (fixed) edge.
        symmetric = getComputedStyle(host).transform !== 'none';

        handle.setPointerCapture(e.pointerId);
        host.setAttribute('data-resizable-resizing', '');
        host.setAttribute('data-resizable-edge', h.name);
      });

      handle.addEventListener('pointermove', (e) => {
        if (!resizing || active !== h.name) return;
        if (symmetric) {
          // Dragged edge/corner tracks the cursor; the host grows from its center
          // (both sides) so the re-centering transform keeps it in place.
          if (h.dw) host.style.width = `${Math.max(0, 2 * h.dw * (e.clientX - centerX))}px`;
          if (h.dh) host.style.height = `${Math.max(0, 2 * h.dh * (e.clientY - centerY))}px`;
        } else {
          // Anchored: the opposite edge stays fixed; the dragged edge grows from it.
          const dx = e.clientX - startX;
          const dy = e.clientY - startY;
          if (h.dw) host.style.width = `${Math.max(0, startWidth + h.dw * dx)}px`;
          if (h.dh) host.style.height = `${Math.max(0, startHeight + h.dh * dy)}px`;
        }
      });

      handle.addEventListener('pointerup', () => {
        if (!resizing || active !== h.name) return;
        resizing = false;
        active = null;
        host.removeAttribute('data-resizable-resizing');
        host.removeAttribute('data-resizable-edge');

        const rect = host.getBoundingClientRect();
        host.dispatchEvent(new CustomEvent('resize-end', {
          bubbles: true,
          detail: { width: rect.width, height: rect.height },
        }));
      });

      handles.push(handle);
      host.appendChild(handle);
    }

    return () => {
      for (const handle of handles) {
        handle.remove();
      }
      handles.length = 0;
      host.removeAttribute('data-resizable-resizing');
      host.removeAttribute('data-resizable-edge');
    };
  },
});
