import { Link } from 'react-router-dom'
import DOMPurify from 'dompurify'

const MOON_IMAGE = '/assets/img/hero-moon.png'

// Font family tokens a line may opt into; default is the page serif.
const FONT = { display: 'var(--display)', sans: 'var(--sans)' }

// fontSize may be a number (px, from the editor) or a CSS string (e.g. a clamp()
// used by the pre-populated default so the hero stays responsive until edited).
function sizeToCss(v) {
  return typeof v === 'number' ? `${v}px` : v
}

function lineStyle(line) {
  return {
    display: 'block', // each line stacks (so a span line behaves like the others)
    margin: line.marginTop != null ? `${line.marginTop}px 0 0` : '0',
    fontFamily: FONT[line.font] || undefined,
    fontSize: sizeToCss(line.fontSize),
    color: line.color || 'inherit',
    fontWeight: line.weight || undefined,
    fontStyle: line.italic ? 'italic' : undefined,
    letterSpacing: line.letterSpacing || undefined,
    textTransform: line.transform || undefined,
    lineHeight: line.lineHeight || undefined,
    maxWidth: line.maxWidth ? `${line.maxWidth}px` : undefined,
    marginLeft: line.maxWidth ? 'auto' : undefined,
    marginRight: line.maxWidth ? 'auto' : undefined,
  }
}

function TextBlock({ props }) {
  const align = props.align || 'center'
  return (
    <div style={{ textAlign: align, textShadow: '0 2px 22px rgba(0,0,0,0.82)' }}>
      {(props.lines || []).map((line) => {
        const Tag = /^(h1|h2|h3|p|span|div)$/.test(line.tag) ? line.tag : 'p'
        const key = `${line.tag}:${(line.text || '').slice(0, 40)}`
        // A rich-text line (e.g. the homepage teaser) carries sanitized HTML;
        // sanitize again on render as defense in depth. Others render as text.
        if (line.html) {
          return (
            <Tag
              key={key}
              className="hero-rich"
              style={lineStyle(line)}
              dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(line.text || '') }}
            />
          )
        }
        return (
          <Tag key={key} style={lineStyle(line)}>
            {line.text}
          </Tag>
        )
      })}
    </div>
  )
}

function Buttons({ props }) {
  const justify = { left: 'flex-start', right: 'flex-end' }[props.align] || 'center'
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: props.gap ?? 12, justifyContent: justify }}>
      {(props.items || []).map((b) => (
        <Link key={`${b.to || ''}:${b.label || ''}`} to={b.to || '#'} className={`btn ${b.variant === 'ghost' ? 'btn-ghost' : 'btn-primary'}`}>
          {b.label}
        </Link>
      ))}
    </div>
  )
}

function Badge({ props }) {
  return (
    <span
      className="sans"
      style={{
        display: 'inline-block',
        padding: '6px 14px',
        background: props.bgColor || 'rgba(11,22,48,0.6)',
        color: props.textColor || '#c2d2e6',
        borderRadius: props.borderRadius ?? 999,
        fontSize: '0.74rem',
        fontWeight: 700,
        letterSpacing: '0.18em',
        textTransform: 'uppercase',
      }}
    >
      {props.text}
    </span>
  )
}

function HeroImage({ props }) {
  if (!props.src) {
    // Editor placeholder until an image is chosen (a srcless image never ships live).
    return (
      <div
        className="sans"
        style={{ width: 160, height: 100, display: 'grid', placeItems: 'center', border: '1px dashed var(--accent)', borderRadius: 8, color: 'var(--muted)', fontSize: '0.8rem', background: 'rgba(11,22,48,0.4)' }}
      >
        Upload an image
      </div>
    )
  }
  return (
    <img
      src={props.src}
      alt={props.alt || ''}
      style={{ width: `${props.width || 40}%`, height: 'auto', display: 'block', borderRadius: 8 }}
    />
  )
}

function content(element) {
  switch (element.type) {
    case 'text_block':
      return <TextBlock props={element.props || {}} />
    case 'buttons':
      return <Buttons props={element.props || {}} />
    case 'moon': {
      const props = element.props || {}
      const size = props.size || 96
      const glow = props.glow ?? 0.45
      // Image source is configurable; old layouts with no src fall back to the
      // default hero moon so they render exactly as before. Size/glow unchanged.
      return (
        <img
          src={props.src || MOON_IMAGE}
          alt={props.alt || ''}
          draggable={false}
          style={{
            width: size,
            height: 'auto',
            display: 'block',
            filter: glow ? `drop-shadow(0 0 ${size * 0.45}px rgba(216,226,239,${glow}))` : undefined,
          }}
        />
      )
    }
    case 'badge':
      return <Badge props={element.props || {}} />
    case 'image':
      return <HeroImage props={element.props || {}} />
    default:
      return null
  }
}

// Absolute-positioned wrapper + type-specific content. In `editor` mode the inner
// content is made non-interactive (so clicks select/drag the wrapper) and the
// wrapper takes selection styling + an onPointerDown handler.
export default function HeroElement({
  element,
  wrapperStyle,
  editor = false,
  selected = false,
  onPointerDown,
  children,
}) {
  const anchor = element.anchor || 'center'
  const transform = { center: 'translate(-50%, -50%)', 'top-right': 'translateX(-100%)' }[anchor]
  // text_block/buttons may set a box width (px); kept within the containing block
  // (the hero section live, or the editor canvas) with small side gutters.
  const boxWidth =
    (element.type === 'text_block' || element.type === 'buttons') && element.props?.width
      ? `min(${element.props.width}px, calc(100% - 36px))`
      : undefined
  const cls = [editor ? 'hero-el-editable' : '', selected ? 'is-selected' : ''].filter(Boolean).join(' ')
  return (
    <div
      className={cls || undefined}
      onPointerDown={onPointerDown}
      style={{
        position: 'absolute',
        left: `${element.x}%`,
        top: `${element.y}%`,
        zIndex: element.z || 0,
        transform,
        width: boxWidth,
        cursor: editor ? 'move' : undefined,
        ...wrapperStyle,
      }}
    >
      <div style={editor ? { pointerEvents: 'none' } : undefined}>{content(element)}</div>
      {children}
    </div>
  )
}
