/* global React, ReactDOM */
const { useState, useEffect, useRef, useLayoutEffect, useCallback } = React;

// =========================================================
// WidgetConfigPop — per-widget settings: size (width in sensible steps,
// height presets), what the widget shows, order and hide.
//
// Placement is decided ONCE when it opens (under the settings button, or
// above it when there's no room; a bottom sheet on phones) and it stays
// put while you click — changing the width/height re-flows the dashboard
// underneath, but the panel itself never jumps. It follows the page only
// when the page scrolls or the window resizes.
// =========================================================

const WIDTH_LABELS = { 3: '¼', 4: '⅓', 6: '½', 8: '⅔', 9: '¾', 12: 'Celá' };
const HEIGHTS = [
  { v: null, label: 'Auto' },
  { v: 200, label: 'Nízká' },
  { v: 280, label: 'Střední' },
  { v: 360, label: 'Vysoká' },
  { v: 460, label: 'Max' },
];

window.WidgetConfigPop = function WidgetConfigPop({ widgetId, title, icon, span, minSpan = 3, onSetSpan, rows = 1, onSetRows, rowsStack, userHeight, onSetHeight,
  onMove, canMoveBack, canMoveFwd, onHide, config = {}, onConfigChange, onClose, gearRef, station,
  hourlyRange, onHourlyRangeChange, chartCfg, onChartCfgChange }) {
  const popRef = useRef(null);
  // Esc + a press outside (not on the settings button) close it.
  useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    const onDoc = (e) => {
      if (popRef.current && popRef.current.contains(e.target)) return;
      if (gearRef?.current && gearRef.current.contains(e.target)) return;
      onClose();
    };
    document.addEventListener('keydown', onKey);
    document.addEventListener('pointerdown', onDoc);
    return () => {
      document.removeEventListener('keydown', onKey);
      document.removeEventListener('pointerdown', onDoc);
    };
  }, [onClose, gearRef]);

  // Placement: below/above the settings button (side fixed at open), right
  // edge aligned with the button; phones get a bottom sheet.
  const [pos, setPos] = useState(null);
  const sideRef = useRef(null);
  const place = useCallback(() => {
    const g = gearRef?.current;
    if (!g) return;
    const vw = window.innerWidth, vh = window.innerHeight;
    if (vw < 640) { setPos(p => (p && p.sheet) ? p : { sheet: true }); return; }
    const r = g.getBoundingClientRect();
    const width = Math.min(344, vw - 16);
    const left = Math.round(Math.max(8, Math.min(r.right - width, vw - width - 8)));
    if (!sideRef.current) sideRef.current = (vh - r.bottom >= 360 || vh - r.bottom >= r.top) ? 'below' : 'above';
    const next = sideRef.current === 'below'
      ? { left, width, top: Math.round(r.bottom + 6), maxH: Math.round(vh - r.bottom - 14) }
      : { left, width, bottom: Math.round(vh - r.top + 6), maxH: Math.round(r.top - 14) };
    setPos(p => (p && p.left === next.left && p.top === next.top && p.bottom === next.bottom && p.maxH === next.maxH) ? p : next);
  }, [gearRef]);
  useLayoutEffect(() => {
    place();
    window.addEventListener('resize', place);
    window.addEventListener('scroll', place, true);
    return () => {
      window.removeEventListener('resize', place);
      window.removeEventListener('scroll', place, true);
    };
  }, [place]);

  const setCfg = (k, v) => onConfigChange({ [k]: v });
  // On/off pill. Most settings default to on; `defaultOff` for the rest.
  const toggle = (k, label, defaultOff) => {
    const isOn = defaultOff ? config[k] === true : config[k] !== false;
    return (
      <button key={k} type="button" className="wcp-tog" aria-pressed={isOn}
              onClick={() => setCfg(k, !isOn)}>
        <i className={`bi bi-${isOn ? 'check-lg' : 'plus-lg'}`} aria-hidden="true"/>{label}
      </button>
    );
  };
  const seg = (items, value, onPick) => (
    <div className="wcp-seg">
      {items.map(o => (
        <button key={String(o.v)} type="button" aria-pressed={o.v === value} onClick={() => onPick(o.v)}
                className={o.dim ? 'is-dim' : undefined} title={o.title || o.label}>{o.label}</button>
      ))}
    </div>
  );
  const rangeSeg = (value, onPick) => seg(
    [12, 24, 48, 72].map(v => ({ v, label: v + ' h' })), value, onPick);
  const curve = (cfg, onChange, k, label, swatch) => (
    <button key={k} type="button" className="wcp-tog" aria-pressed={!!cfg[k]}
            onClick={() => onChange({ ...cfg, [k]: !cfg[k] })}>
      {swatch ? <span className="wcp-swatch" style={{ background: swatch }}/> : <i className="bi bi-images" aria-hidden="true"/>}
      {label}
    </button>
  );

  // Per-widget content options.
  let period = null, show = null;
  switch (widgetId) {
    case 'hourly':
      if (onHourlyRangeChange) period = rangeSeg(hourlyRange, onHourlyRangeChange);
      show = [toggle('showDateHeader', 'Den'), toggle('showIcon', 'Ikony'), toggle('showWind', 'Vítr'), toggle('showPrecip', 'Srážky')];
      break;
    case 'daily':
      show = [toggle('showIcon', 'Ikony počasí'), toggle('showRangeBar', 'Pruh min/max'), toggle('showPrecipCol', 'Srážky'),
              toggle('showProb', 'Pravděpodobnost srážek'), toggle('showMore', 'Další dny z MASTER')];
      break;
    case 'chart':
      if (chartCfg && onChartCfgChange) {
        period = rangeSeg(chartCfg.hours, (v) => onChartCfgChange({ ...chartCfg, hours: v }));
        show = [
          curve(chartCfg, onChartCfgChange, 'temp', 'Teplota', 'var(--temp-warm)'),
          curve(chartCfg, onChartCfgChange, 'precip', 'Srážky', 'var(--rain)'),
          curve(chartCfg, onChartCfgChange, 'wind', 'Vítr', '#14b8a6'),
          curve(chartCfg, onChartCfgChange, 'humidity', 'Vlhkost', '#22c55e'),
          curve(chartCfg, onChartCfgChange, 'pressure', 'Tlak', '#8b5cf6'),
          curve(chartCfg, onChartCfgChange, 'icons', 'Ikony', null),
        ];
      }
      show = [...(show || []), toggle('showNightShade', 'Noc'), toggle('showGrid', 'Mřížka'),
              toggle('showDayLabels', 'Dny')];
      break;
    case 'station':
      show = [toggle('showMeta', 'Vlhkost a vítr'), toggle('showFeels', 'Pocitově a proti včerejšku'),
              toggle('showRange', 'Rozsah 24 h'), toggle('showMoon', 'Měsíc v noci'),
              toggle('showCompare', 'Rozdíl od předpovědi', true),
              toggle('hideDecimals', 'Bez desetin', true)];
      break;
    case 'tempChart':
      show = [toggle('showStats', 'Čísla pod grafem'), toggle('showMinMax', 'Min a max'),
              toggle('showPrecip', 'Srážky'), toggle('showIcons', 'Ikony počasí', true)];
      break;
    case 'webcam':
      show = [toggle('showCaption', 'Popisek'), toggle('showLink', 'Odkaz na kamerypocasi.cz')];
      break;
    case 'sensors':
    case 'indoor': {
      const allKeys = widgetId === 'sensors'
        ? (window.__sensorOutdoorKeys || []).filter(k => station?.latest?.[k] != null)
        : (window.__sensorDiscoverIndoor?.(station) || []);
      const hiddenKeys = config.hiddenKeys || [];
      const flip = (k) => onConfigChange({ hiddenKeys: hiddenKeys.includes(k) ? hiddenKeys.filter(x => x !== k) : [...hiddenKeys, k] });
      show = [toggle('showSpark', 'Mini grafy'), toggle('showRange', 'Min a max'), toggle('showTrend', 'Trend'),
        ...allKeys.map(k => {
          const on = !hiddenKeys.includes(k);
          const label = window.__sensorGetField ? window.__sensorGetField(station, k).label : k;
          return (
            <button key={k} type="button" className="wcp-tog" aria-pressed={on} onClick={() => flip(k)}>
              <i className={`bi bi-${on ? 'check-lg' : 'plus-lg'}`} aria-hidden="true"/>{label}
            </button>
          );
        })];
      break;
    }
    case 'models':
      show = [toggle('showBar', 'Pruh přesnosti'), toggle('showScore', 'Skóre')];
      break;
    case 'wind':
      show = [toggle('showCompass', 'Kompas'), toggle('showCompare', 'Porovnání s předpovědí')];
      break;
    case 'radar':
      period = seg([1, 2, 3].map(v => ({ v, label: v + ' h' })), config.hours || 1, (v) => setCfg('hours', v));
      show = [toggle('showLegend', 'Legenda'), toggle('autoplay', 'Přehrávat samo')];
      break;
    case 'sun':
      show = [toggle('showMoon', 'Měsíc'), toggle('showCountdown', 'Odpočet')];
      break;
    default:
      break;
  }

  const widths = window.SPAN_STEPS.filter(v => v >= minSpan)
    .map(v => ({ v, label: WIDTH_LABELS[v] || String(v), title: `${v} z 12 sloupců` }));
  if (!widths.some(o => o.v === span)) widths.push({ v: span, label: `${span}/12` });
  widths.sort((a, b) => a.v - b.v);
  const heightPreset = HEIGHTS.some(o => o.v === (userHeight || null));

  if (!pos) return null;
  const style = pos.sheet ? undefined
    : { left: pos.left, width: pos.width, top: pos.top, bottom: pos.bottom, maxHeight: pos.maxH };
  const node = (
    <>
      {pos.sheet && <div className="wcp-backdrop" onPointerDown={onClose}/>}
      <div className={`wcp ${pos.sheet ? 'is-sheet' : ''}`} ref={popRef} style={style}
           role="dialog" aria-label={`Nastavení: ${title}`} onClick={e => e.stopPropagation()}>
        <div className="wcp-head">
          <i className={`bi bi-${icon}`} aria-hidden="true"/>
          <span>{title}</span>
          <button type="button" className="wcp-x" onClick={onClose} aria-label="Zavřít"><i className="bi bi-x-lg"/></button>
        </div>
        <div className="wcp-scroll">
          {onSetSpan && <>
            <div className="wcp-label">Šířka</div>
            {seg(widths, span, (v) => onSetSpan(v))}
          </>}
          {onSetRows && <>
            <div className="wcp-label">Řádky<small> · vedle vysokého widgetu se menší srovnají pod sebe</small></div>
            {seg([1, 2, 3, 4].map(v => {
              // spanning rows that nothing stacks beside changes nothing — say so
              const idle = !!rowsStack && v > 1 && v !== rows && !rowsStack(v);
              return { v, label: String(v), dim: idle,
                       title: v === 1 ? 'Jeden řádek' : idle ? `Přes ${v} řádky — vedle se teď nic nesrovná, nic se nezmění` : `Přes ${v} řádky` };
            }), rows, (v) => onSetRows(v))}
          </>}
          <div className="wcp-label">Nejmenší výška{!heightPreset && <small> · vlastní {userHeight} px</small>}</div>
          {seg(HEIGHTS, heightPreset ? (userHeight || null) : undefined, (v) => onSetHeight?.(v))}
          {period && <><div className="wcp-label">Období</div>{period}</>}
          {show && show.length > 0 && <><div className="wcp-label">Zobrazit</div><div className="wcp-togs">{show}</div></>}
        </div>
        <div className="wcp-foot">
          <button type="button" disabled={!canMoveBack} onClick={() => onMove?.(-1)} title="Posunout o místo dřív">
            <i className="bi bi-arrow-left" aria-hidden="true"/>Dřív
          </button>
          <button type="button" disabled={!canMoveFwd} onClick={() => onMove?.(1)} title="Posunout o místo dál">
            Dál<i className="bi bi-arrow-right" aria-hidden="true"/>
          </button>
          <button type="button" className="danger" onClick={onHide}>
            <i className="bi bi-eye-slash" aria-hidden="true"/>Skrýt
          </button>
        </div>
      </div>
    </>
  );
  return ReactDOM.createPortal(node, document.body);
};
