import React, { CSSProperties } from 'react';
import { useNode, UserComponent } from '@craftjs/core';
import { cssPropsToString } from '../../utils/style-helpers';
import { escapeHtml, escapeAttr, safeImageUrl, scopeId, cssValue } from '../../utils/escape';

interface GalleryImage {
  src: string;
  alt: string;
  caption?: string;
}

interface GalleryProps {
  images?: GalleryImage[];
  columns?: number;
  gap?: string;
  style?: CSSProperties;
  lightbox?: boolean;
  animation?: string;
  animationDelay?: string;
  hideOnDesktop?: boolean;
  hideOnTablet?: boolean;
  hideOnMobile?: boolean;
}

const placeholderSvg = (index: number) => {
  const colors = ['#3b82f6', '#8b5cf6', '#10b981', '#f59e0b', '#ef4444', '#ec4899'];
  const color = colors[index % colors.length];
  return `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300"><rect fill="${color}" width="400" height="300" opacity="0.15"/><rect fill="${color}" x="150" y="100" width="100" height="100" rx="12" opacity="0.3"/><text x="200" y="160" text-anchor="middle" font-family="sans-serif" font-size="24" fill="${color}" opacity="0.6">${index + 1}</text></svg>`)}`;
};

const defaultImages: GalleryImage[] = [
  { src: placeholderSvg(0), alt: 'Gallery image 1', caption: 'First image' },
  { src: placeholderSvg(1), alt: 'Gallery image 2', caption: 'Second image' },
  { src: placeholderSvg(2), alt: 'Gallery image 3', caption: 'Third image' },
  { src: placeholderSvg(3), alt: 'Gallery image 4', caption: 'Fourth image' },
  { src: placeholderSvg(4), alt: 'Gallery image 5', caption: 'Fifth image' },
  { src: placeholderSvg(5), alt: 'Gallery image 6', caption: 'Sixth image' },
];

export const Gallery: UserComponent<GalleryProps> = ({
  images = defaultImages,
  columns = 3,
  gap = '16px',
  style = {},
  lightbox = false,
}) => {
  const {
    connectors: { connect, drag },
    selected,
  } = useNode((node) => ({
    selected: node.events.selected,
  }));

  return (
    <section
      ref={(ref: HTMLElement | null): void => { if (ref) connect(drag(ref)); }}
      style={{
        padding: '60px 20px',
        backgroundColor: '#ffffff',
        outline: selected ? '2px solid #3b82f6' : 'none',
        ...style,
      }}
    >
      <div
        style={{
          maxWidth: '1100px',
          margin: '0 auto',
          display: 'grid',
          gridTemplateColumns: `repeat(${columns}, 1fr)`,
          gap: gap,
        }}
      >
        {images.map((img, i) => (
          <div key={i} style={{ position: 'relative', overflow: 'hidden', borderRadius: '8px' }}>
            <img
              src={img.src}
              alt={img.alt}
              style={{
                width: '100%',
                height: '200px',
                objectFit: 'cover',
                display: 'block',
                borderRadius: '8px',
                backgroundColor: '#f1f5f9',
              }}
            />
            {img.caption && (
              <div
                style={{
                  position: 'absolute',
                  bottom: '0',
                  left: '0',
                  right: '0',
                  padding: '8px 12px',
                  background: 'linear-gradient(transparent, rgba(0,0,0,0.7))',
                  color: '#ffffff',
                  fontSize: '12px',
                  borderBottomLeftRadius: '8px',
                  borderBottomRightRadius: '8px',
                }}
              >
                {img.caption}
              </div>
            )}
          </div>
        ))}
      </div>
    </section>
  );
};

/* ---------- Craft config ---------- */

Gallery.craft = {
  displayName: 'Gallery',
  props: {
    images: defaultImages,
    columns: 3,
    gap: '16px',
    style: {
      backgroundColor: '#ffffff',
      marginTop: '', marginRight: '', marginBottom: '', marginLeft: '',
      paddingTop: '', paddingRight: '', paddingBottom: '', paddingLeft: '',
      border: 'none',
      boxShadow: 'none',
      opacity: '1',
    },
    lightbox: false,
    animation: '',
    animationDelay: '0',
    hideOnDesktop: false,
    hideOnTablet: false,
    hideOnMobile: false,
  },
  rules: {
    canDrag: () => true,
    canMoveIn: () => false,
    canMoveOut: () => true,
  },
};

/* ---------- HTML export ---------- */

(Gallery as any).toHtml = (props: GalleryProps, _childrenHtml: string, nodeId?: string) => {
  const sectionStyle = cssPropsToString({
    padding: '60px 20px',
    ...props.style,
  });
  const images = props.images || defaultImages;
  // Number() coercion: `columns` is a raw string-interpolation sink into the
  // grid style attribute below (repeat(${columns},1fr)) -- a non-numeric
  // (e.g. hand-crafted/AI-generated tree) value would otherwise be able to
  // break out; Number() of anything non-numeric collapses safely to NaN.
  const columns = Number(props.columns) || 3;
  // Sanitized -- gap is a raw string-interpolation sink into the grid style
  // attribute below.
  const gap = cssValue(props.gap) || '16px';
  const lightbox = props.lightbox || false;

  // Deterministic AND unique id, scoped on the Craft node id, for this
  // gallery's overlay/grid element ids and inline-script function names --
  // so two Gallery instances (e.g. both left at default images) don't
  // collide and end up sharing/clobbering one lightbox overlay.
  const galleryId = scopeId(nodeId, JSON.stringify(images) + columns + gap, 'gallery');

  const items = images.map((img) => {
    const caption = img.caption
      ? `<div style="position:absolute;bottom:0;left:0;right:0;padding:8px 12px;background:linear-gradient(transparent,rgba(0,0,0,0.7));color:#ffffff;font-size:12px;border-bottom-left-radius:8px;border-bottom-right-radius:8px">${escapeHtml(img.caption)}</div>`
      : '';
    // Lightbox items carry the image URL as a data attribute rather than an
    // inline onclick with an interpolated src -- a single delegated click
    // listener below reads it, so a src containing a quote can't break out
    // of a per-item event-handler string.
    const lbAttr = lightbox ? ` data-lb-src="${escapeAttr(safeImageUrl(img.src || ''))}" role="button" tabindex="0"` : '';
    const itemStyle = lightbox ? 'cursor:pointer;position:relative;overflow:hidden;border-radius:8px' : 'position:relative;overflow:hidden;border-radius:8px';
    return `<div${lbAttr} style="${itemStyle}">
      <img src="${escapeAttr(safeImageUrl(img.src || ''))}" alt="${escapeAttr(img.alt)}" style="width:100%;height:200px;object-fit:cover;display:block;border-radius:8px;background-color:#f1f5f9" />
      ${caption}
    </div>`;
  }).join('\n    ');

  let lightboxHtml = '';
  let gridIdAttr = '';
  if (lightbox) {
    gridIdAttr = ` id="${galleryId}_grid"`;
    // M-2: focus management for the lightbox dialog.
    //  - OPEN: stash `document.activeElement` (the thumbnail that triggered
    //    the open) in a module-scoped var, then move focus onto the close
    //    button -- so a screen-reader/keyboard user lands inside the dialog
    //    instead of focus staying on (or silently falling back to <body>)
    //    behind the now-visible overlay.
    //  - Tab trap: while the overlay is open, every Tab keypress is
    //    intercepted and refocuses the close button (the dialog's only
    //    focusable control besides Escape/click-to-close), so focus can
    //    never wander out into the page content hidden behind the overlay.
    //  - CLOSE (Escape, backdrop click, or the close button): restore focus
    //    to the element stashed on open.
    lightboxHtml = `
  <div id="${galleryId}_overlay" role="dialog" aria-modal="true" aria-label="Image preview" onclick="${galleryId}_close()" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);z-index:9999;justify-content:center;align-items:center;cursor:pointer">
    <button type="button" id="${galleryId}_closebtn" aria-label="Close preview" tabindex="-1" onclick="event.stopPropagation();${galleryId}_close()" style="position:absolute;top:16px;right:16px;width:36px;height:36px;border-radius:50%;border:none;background:rgba(255,255,255,0.15);color:#ffffff;font-size:20px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center">&times;</button>
    <img id="${galleryId}_img" src="" alt="" style="max-width:90%;max-height:90%;object-fit:contain;border-radius:8px" />
  </div>
  <script>
var ${galleryId}_lastFocus = null;
function ${galleryId}_close(){
  document.getElementById('${galleryId}_overlay').style.display='none';
  if(${galleryId}_lastFocus && ${galleryId}_lastFocus.focus) ${galleryId}_lastFocus.focus();
  ${galleryId}_lastFocus = null;
}
function ${galleryId}_open(src){
  ${galleryId}_lastFocus = document.activeElement;
  var o = document.getElementById('${galleryId}_overlay');
  document.getElementById('${galleryId}_img').src = src;
  o.style.display = 'flex';
  var c = document.getElementById('${galleryId}_closebtn');
  if(c) c.focus();
}
document.getElementById('${galleryId}_grid').addEventListener('click', function(e){
  var t = e.target.closest('[data-lb-src]');
  if(!t) return;
  ${galleryId}_open(t.getAttribute('data-lb-src'));
});
document.getElementById('${galleryId}_grid').addEventListener('keydown', function(e){
  if(e.key!=='Enter' && e.key!==' ') return;
  var t = e.target.closest('[data-lb-src]');
  if(!t) return;
  e.preventDefault();
  ${galleryId}_open(t.getAttribute('data-lb-src'));
});
document.addEventListener('keydown', function(e){
  var o = document.getElementById('${galleryId}_overlay');
  if(!o || o.style.display==='none') return;
  if(e.key==='Escape'){ ${galleryId}_close(); return; }
  if(e.key==='Tab'){
    e.preventDefault();
    var c = document.getElementById('${galleryId}_closebtn');
    if(c) c.focus();
  }
});
  </script>`;
  }

  return {
    html: `<section${sectionStyle ? ` style="${sectionStyle}"` : ''}>
  <div${gridIdAttr} style="max-width:1100px;margin:0 auto;display:grid;grid-template-columns:repeat(${columns},1fr);gap:${gap}">
    ${items}
  </div>${lightboxHtml}
</section>`,
  };
};
