/**
 * Template picker: sidebar with search and categories, cards that show the real form (scaled down),
 * and a full live preview (desktop / tablet / mobile) before using a template.
 *
 * Templates load only when the picker opens. Card previews are the real form HTML, rendered by the
 * server in small batches as cards scroll into view. No images ship with the plugin.
 */
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { __, sprintf } from '@wordpress/i18n';
import { Modal, Input, Button, Spin, Empty, message } from 'antd';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
  faMagnifyingGlass, faDesktop, faTabletScreenButton, faMobileScreenButton, faArrowLeft,
  faChevronLeft, faChevronRight, faFire, faLayerGroup, faPlus, faXmark, faEye, faCrown, faFileLines,
  faAward, faBookOpen, faBowlFood, faBoxesStacked, faBrain, faBriefcase, faBug, faBurger, faCalendarCheck, faCalendarDays,
  faCartShopping, faChalkboardUser, faChartPie, faChartSimple, faCircleDollarToSlot, faComments,
  faDoorOpen, faEnvelope, faFaceSmile, faFileInvoice, faFileInvoiceDollar, faFileSignature, faGauge, faGlobe, faGraduationCap,
  faHandHoldingHeart, faHandshake, faHotel, faHouse, faHouseChimney, faIdCard, faKey, faLifeRing, faLightbulb, faMedal,
  faMicrophone, faMugSaucer, faNewspaper, faPenNib, faPeopleCarryBox, faPersonRunning, faPhone, faPills, faPlaneDeparture,
  faQuoteLeft, faRepeat, faRightToBracket, faRing, faRotateLeft, faRoute, faSchool, faScrewdriverWrench, faSignature,
  faSquarePollVertical, faStar, faStethoscope, faTicket, faTrophy, faUserPen, faUserPlus, faUserTie, faUsers, faUtensils,
} from '@fortawesome/free-solid-svg-icons';
import { loadTemplates, buildTemplate, flatFields, templateFeatures } from '../pages/templates';
import { request } from '../services/api';

// Icons named in the template files ('icon' => 'faEnvelope'). Unknown names fall back to a form icon.
const ICONS = {
  faAward, faBookOpen, faBowlFood, faBoxesStacked, faBrain, faBriefcase, faBug, faBurger, faCalendarCheck, faCalendarDays,
  faCartShopping, faChalkboardUser, faChartPie, faChartSimple, faCircleDollarToSlot, faComments, faCrown, faDesktop,
  faDoorOpen, faEnvelope, faFaceSmile, faFileInvoice, faFileInvoiceDollar, faFileSignature, faGauge, faGlobe, faGraduationCap,
  faHandHoldingHeart, faHandshake, faHotel, faHouse, faHouseChimney, faIdCard, faKey, faLifeRing, faLightbulb, faMedal,
  faMicrophone, faMugSaucer, faNewspaper, faPenNib, faPeopleCarryBox, faPersonRunning, faPhone, faPills, faPlaneDeparture,
  faQuoteLeft, faRepeat, faRightToBracket, faRing, faRotateLeft, faRoute, faSchool, faScrewdriverWrench, faSignature,
  faSquarePollVertical, faStar, faStethoscope, faTicket, faTrophy, faUserPen, faUserPlus, faUserTie, faUsers, faUtensils,
};
const TONES = 9;
const toneOf = (slug) => [...String(slug)].reduce((a, c) => a + c.charCodeAt(0), 0) % TONES;

/** Coloured rounded square with the template's icon (same look as the Pro Features page). */
function TplIcon({ t, size = 'md' }) {
  return (
    <span className={'fg-tpl-ic fg-tpl-ic-' + size + ' fg-tone-' + toneOf(t.slug)} aria-hidden="true">
      <FontAwesomeIcon icon={ICONS[t.icon] || faFileLines} />
    </span>
  );
}

const FEATURE_LABELS = {
  steps: __( 'Multi-step', 'formglut' ),
  payment: __( 'Payment', 'formglut' ),
  upload: __( 'File upload', 'formglut' ),
  signature: __( 'Signature', 'formglut' ),
  quiz: __( 'Quiz', 'formglut' ),
};
const NOTE_KEY = 'formglut_tpl_pro_note_hidden';
const storage = {
  get(k) { try { return window.localStorage.getItem(k); } catch (e) { return null; } },
  set(k, v) { try { window.localStorage.setItem(k, v); } catch (e) { /* private mode */ } },
};

const labelOf = (f) => f.label || f.text || f.title || '';

/* ------------------------------------------------------------------ card thumbnail: the real form */

const THUMB_W = 760;  // Width the form is drawn at, then scaled to the card.
const THUMB_BOX = 200; // Card thumbnail height (px), matches .fg-tpl-thumb.
const thumbHtml = {};
let thumbHead = '';
const waiting = new Map();
let queue = [];
let timer = 0;

async function flushThumbs() {
  while (queue.length) {
    const batch = queue.splice(0, 8);
    const payload = batch.map((t) => {
      const b = buildTemplate(t);
      return { slug: t.slug, title: t.title, fields: b.fields, settings: b.settings, submit_btn: b.submit_btn };
    });
    try {
      const data = await request('formglut_template_thumbs', { templates: payload }, 'POST');
      if (data.head) thumbHead = data.head;
      batch.forEach((t) => { thumbHtml[t.slug] = data.forms[t.slug] || ''; });
    } catch (e) {
      batch.forEach((t) => { thumbHtml[t.slug] = ''; });
    }
    batch.forEach((t) => { (waiting.get(t.slug) || []).forEach((done) => done()); waiting.delete(t.slug); });
  }
}

function requestThumb(t) {
  if (thumbHtml[t.slug] !== undefined) return Promise.resolve();
  return new Promise((done) => {
    if (waiting.has(t.slug)) { waiting.get(t.slug).push(done); return; }
    waiting.set(t.slug, [done]);
    queue.push(t);
    clearTimeout(timer);
    timer = setTimeout(flushThumbs, 60);
  });
}

function FormThumb({ t }) {
  const ref = useRef(null);
  const [html, setHtml] = useState(thumbHtml[t.slug]);
  const [scale, setScale] = useState(0.33);

  useEffect(() => {
    const el = ref.current;
    if (!el) return undefined;
    const ro = new ResizeObserver(([e]) => setScale(e.contentRect.width / THUMB_W));
    ro.observe(el);
    let io = null;
    if (thumbHtml[t.slug] === undefined) {
      io = new IntersectionObserver((entries) => {
        if (entries.some((x) => x.isIntersecting)) {
          io.disconnect();
          requestThumb(t).then(() => setHtml(thumbHtml[t.slug]));
        }
      }, { rootMargin: '300px' });
      io.observe(el);
    }
    return () => { ro.disconnect(); if (io) io.disconnect(); };
  }, [t]);

  const doc = html ? '<!DOCTYPE html><html><head><meta charset="utf-8">' + thumbHead
    + '<style>html,body{margin:0;background:#fff;overflow:hidden}body{padding:26px 30px}</style></head><body>' + html + '</body></html>' : '';

  return (
    <div className="fg-tpl-real" ref={ref}>
      {html ? (
        <iframe srcDoc={doc} sandbox="" tabIndex={-1} aria-hidden="true" title=""
          style={{ width: THUMB_W, height: Math.ceil(THUMB_BOX / scale), transform: 'scale(' + scale + ')' }} />
      ) : html === '' ? <div className="fg-tpl-real-empty"><TplIcon t={t} size="lg" /></div>
        : <div className="fg-tpl-real-empty"><Spin size="small" /></div>}
    </div>
  );
}

/* ------------------------------------------------------------------ live preview */

const DEVICES = [
  { key: 'desktop', width: '100%', icon: faDesktop, label: __( 'Desktop', 'formglut' ) },
  { key: 'tablet', width: '768px', icon: faTabletScreenButton, label: __( 'Tablet', 'formglut' ) },
  { key: 'mobile', width: '375px', icon: faMobileScreenButton, label: __( 'Mobile', 'formglut' ) },
];
const htmlCache = {};

async function fetchPreview(t) {
  if (htmlCache[t.slug]) return htmlCache[t.slug];
  const { ajax_url, nonce } = window.formglut_admin || {};
  const built = buildTemplate(t);
  const body = new FormData();
  body.append('action', 'formglut_template_preview');
  body.append('nonce', nonce);
  body.append('title', t.title);
  body.append('fields', JSON.stringify(built.fields));
  body.append('settings', JSON.stringify(built.settings));
  body.append('submit_btn', JSON.stringify(built.submit_btn));
  const res = await fetch(ajax_url, { method: 'POST', body, credentials: 'same-origin' });
  if (!res.ok) throw new Error(__( 'Could not load the preview.', 'formglut' ));
  htmlCache[t.slug] = await res.text();
  return htmlCache[t.slug];
}

function LivePreview({ list, index, setIndex, catLabel, onUse, onBack, creating }) {
  const t = list[index];
  const [device, setDevice] = useState('desktop');
  const [html, setHtml] = useState('');
  const [error, setError] = useState('');

  useEffect(() => {
    let live = true;
    setHtml(''); setError('');
    fetchPreview(t).then((h) => live && setHtml(h)).catch((e) => live && setError(e.message));
    return () => { live = false; };
  }, [t]);

  useEffect(() => {
    const onKey = (e) => {
      if (e.target.closest && e.target.closest('input, textarea, select')) return;
      if (e.key === 'ArrowLeft' && index > 0) setIndex(index - 1);
      if (e.key === 'ArrowRight' && index < list.length - 1) setIndex(index + 1);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [index, list.length, setIndex]);

  const fields = flatFields(t.fields).filter((f) => !['form_step', 'hidden', 'html'].includes(f.type));
  const steps = flatFields(t.fields).filter((f) => f.type === 'form_step').length;
  const width = DEVICES.find((d) => d.key === device).width;

  return (
    <div className="fg-tpv">
      <div className="fg-tpv-stage">
        <div className="fg-tpv-bar">
          <button type="button" className="fg-tpv-back" onClick={onBack}><FontAwesomeIcon icon={faArrowLeft} /> {__( 'All templates', 'formglut' )}</button>
          <div className="fg-tpv-devices" role="group" aria-label={__( 'Device width', 'formglut' )}>
            {DEVICES.map((d) => (
              <button key={d.key} type="button" title={d.label} aria-label={d.label} className={device === d.key ? 'active' : ''} onClick={() => setDevice(d.key)}><FontAwesomeIcon icon={d.icon} /></button>
            ))}
          </div>
          <div className="fg-tpv-nav">
            <button type="button" disabled={index === 0} onClick={() => setIndex(index - 1)} aria-label={__( 'Previous template', 'formglut' )}><FontAwesomeIcon icon={faChevronLeft} /></button>
            <span>{index + 1} / {list.length}</span>
            <button type="button" disabled={index === list.length - 1} onClick={() => setIndex(index + 1)} aria-label={__( 'Next template', 'formglut' )}><FontAwesomeIcon icon={faChevronRight} /></button>
          </div>
        </div>
        <div className="fg-tpv-canvas">
          {error ? <Empty description={error} />
            : !html ? <div className="fg-tpv-loading"><Spin /></div>
              : <iframe title={sprintf( /* translators: %s: template name */ __( 'Preview of %s', 'formglut' ), t.title )} srcDoc={html} style={{ width }} className="fg-tpv-frame" />}
        </div>
      </div>
      <aside className="fg-tpv-side">
        <TplIcon t={t} size="lg" />
        <h2>{t.title} {t.source === 'pro' && <span className="fg-pro-pill">PRO</span>}</h2>
        <p className="fg-tpv-desc">{t.description}</p>
        <div className="fg-tpv-meta">
          <span>{catLabel(t.category)}</span>
          <span>{sprintf( /* translators: %d: number of fields */ __( '%d fields', 'formglut' ), fields.length )}</span>
          {steps > 0 && <span>{sprintf( /* translators: %d: number of steps */ __( '%d steps', 'formglut' ), steps + 1 )}</span>}
        </div>
        <Button type="primary" size="large" block loading={creating} onClick={() => onUse(t)}>{__( 'Use this template', 'formglut' )}</Button>
        <p className="fg-tpv-hint">{__( 'Everything can be changed in the editor afterwards.', 'formglut' )}</p>
        <h3>{__( 'Fields in this form', 'formglut' )}</h3>
        <ul className="fg-tpv-fields">
          {fields.map((f, i) => <li key={i}><span>{labelOf(f) || f.type}</span>{f.required && <em>{__( 'required', 'formglut' )}</em>}</li>)}
        </ul>
      </aside>
    </div>
  );
}

/* ------------------------------------------------------------------ picker */

export default function TemplatePicker({ open, onClose, onUse, onBlank, creating }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState('');
  const [search, setSearch] = useState('');
  const [cat, setCat] = useState('all');
  const [preview, setPreview] = useState(-1);
  const [noteHidden, setNoteHidden] = useState(() => !!storage.get(NOTE_KEY));
  const searchRef = useRef(null);

  useEffect(() => {
    if (!open || data) return;
    loadTemplates().then(setData).catch((e) => { setError(e.message); message.error(e.message); });
  }, [open, data]);

  useEffect(() => { if (open) setTimeout(() => searchRef.current && searchRef.current.focus(), 150); }, [open]);

  const templates = data ? data.templates : [];
  const catLabel = (slug) => ((data && data.categories.find((c) => c.slug === slug)) || {}).label || '';
  const counts = useMemo(() => templates.reduce((a, t) => ({ ...a, [t.category]: (a[t.category] || 0) + 1 }), {}), [templates]);

  const list = useMemo(() => {
    const q = search.trim().toLowerCase();
    return templates
      .filter((t) => cat === 'all' || (cat === 'popular' ? t.popular : t.category === cat))
      .filter((t) => !q || [t.title, t.description, t.keywords, catLabel(t.category)].join(' ').toLowerCase().includes(q))
      .sort((a, b) => (b.popular ? 1 : 0) - (a.popular ? 1 : 0));
  }, [templates, cat, search]); // eslint-disable-line react-hooks/exhaustive-deps

  const heading = cat === 'all' ? __( 'All templates', 'formglut' ) : cat === 'popular' ? __( 'Popular', 'formglut' ) : catLabel(cat);
  const hideNote = () => { storage.set(NOTE_KEY, '1'); setNoteHidden(true); };
  const close = () => { setPreview(-1); onClose(); };

  return (
    <Modal open={open} onCancel={close} footer={null} width="min(1320px, 96vw)" centered closable={preview < 0}
      className="fg-tpl-modal" title={null} destroyOnClose={false}>
      {preview >= 0 && list[preview] ? (
        <LivePreview list={list} index={preview} setIndex={setPreview} catLabel={catLabel} onUse={onUse} onBack={() => setPreview(-1)} creating={creating} />
      ) : (
        <div className="fg-tpl">
          <aside className="fg-tpl-side">
            <div className="fg-tpl-side-title">{__( 'Choose a template', 'formglut' )}</div>
            <Input ref={searchRef} allowClear prefix={<FontAwesomeIcon icon={faMagnifyingGlass} style={{ color: '#94a3b8' }} />} placeholder={__( 'Search templates…', 'formglut' )} value={search} onChange={(e) => setSearch(e.target.value)} />
            <nav className="fg-tpl-cats">
              <button type="button" className={cat === 'all' ? 'active' : ''} onClick={() => setCat('all')}><FontAwesomeIcon icon={faLayerGroup} /> {__( 'All templates', 'formglut' )}<span>{templates.length}</span></button>
              <button type="button" className={cat === 'popular' ? 'active' : ''} onClick={() => setCat('popular')}><FontAwesomeIcon icon={faFire} /> {__( 'Popular', 'formglut' )}<span>{templates.filter((t) => t.popular).length}</span></button>
              <div className="fg-tpl-cats-label">{__( 'Categories', 'formglut' )}</div>
              {data && data.categories.map((c) => (
                <button type="button" key={c.slug} className={cat === c.slug ? 'active' : ''} onClick={() => setCat(c.slug)}>{c.label}<span>{counts[c.slug] || 0}</span></button>
              ))}
            </nav>
          </aside>
          <section className="fg-tpl-main">
            {data && data.pro_note && !noteHidden && (
              <div className="fg-tpl-banner">
                <span className="fg-tpl-banner-ic"><FontAwesomeIcon icon={faCrown} /></span>
                <span className="fg-tpl-banner-text">{data.pro_note.text}</span>
                <a href={data.pro_note.url} target="_blank" rel="noopener noreferrer">{__( 'See them', 'formglut' )} →</a>
                <button type="button" className="fg-tpl-banner-x" onClick={hideNote} aria-label={__( 'Dismiss', 'formglut' )}><FontAwesomeIcon icon={faXmark} /></button>
              </div>
            )}
            <div className="fg-tpl-head">
              <h2>{heading}</h2>
              <span>{sprintf( /* translators: %d: number of templates */ __( '%d templates', 'formglut' ), list.length )}</span>
            </div>
            {!data && !error && <div className="fg-tpl-loading"><Spin /></div>}
            {error && <Empty description={error} />}
            {data && (
              <div className="fg-tpl-grid">
                {cat === 'all' && !search && (
                  <button type="button" className="fg-tpl-card fg-tpl-blank" onClick={onBlank} disabled={creating}>
                    <div className="fg-tpl-thumb"><FontAwesomeIcon icon={faPlus} /></div>
                    <div className="fg-tpl-body"><div className="fg-tpl-name">{__( 'Blank form', 'formglut' )}</div><div className="fg-tpl-desc">{__( 'Start from scratch and add your own fields.', 'formglut' )}</div></div>
                  </button>
                )}
                {list.map((t, i) => (
                  <div className="fg-tpl-card" key={t.slug}>
                    <div className="fg-tpl-thumb">
                      <FormThumb t={t} />
                      <div className="fg-tpl-overlay">
                        <Button onClick={() => setPreview(i)} icon={<FontAwesomeIcon icon={faEye} />}>{__( 'Preview', 'formglut' )}</Button>
                        <Button type="primary" disabled={creating} onClick={() => onUse(t)}>{__( 'Use template', 'formglut' )}</Button>
                      </div>
                    </div>
                    <button type="button" className="fg-tpl-body" onClick={() => setPreview(i)}>
                      <div className="fg-tpl-name"><TplIcon t={t} size="sm" /><span>{t.title}</span>{t.source === 'pro' && <span className="fg-pro-pill">PRO</span>}</div>
                      <div className="fg-tpl-desc">{t.description}</div>
                      <div className="fg-tpl-tags">{templateFeatures(t).map((k) => <span key={k}>{FEATURE_LABELS[k]}</span>)}</div>
                    </button>
                  </div>
                ))}
                {!list.length && <Empty className="fg-tpl-empty" description={__( 'No templates match your search.', 'formglut' )} />}
              </div>
            )}
          </section>
        </div>
      )}
    </Modal>
  );
}
