/* global React, Icon, IconBtn, db */
const { useState, useEffect, useMemo, useRef } = React;

// ============================================================
// World clock — curated list of common timezones, analog + digital.
// User adds zones from a searchable picker, removes from the card.
// Settings (12h vs 24h, show seconds) persisted alongside the list.
// ============================================================

// Curated list — name + IANA zone. Kept hand-picked rather than
// dumping all 400+ zones — easier to find your city, less overwhelming.
const TZ_CATALOG = [
  { name: 'San Francisco',  region: 'United States',   zone: 'America/Los_Angeles' },
  { name: 'Los Angeles',    region: 'United States',   zone: 'America/Los_Angeles' },
  { name: 'Denver',         region: 'United States',   zone: 'America/Denver' },
  { name: 'Chicago',        region: 'United States',   zone: 'America/Chicago' },
  { name: 'New York',       region: 'United States',   zone: 'America/New_York' },
  { name: 'Toronto',        region: 'Canada',          zone: 'America/Toronto' },
  { name: 'Vancouver',      region: 'Canada',          zone: 'America/Vancouver' },
  { name: 'Mexico City',    region: 'Mexico',          zone: 'America/Mexico_City' },
  { name: 'São Paulo',      region: 'Brazil',          zone: 'America/Sao_Paulo' },
  { name: 'Buenos Aires',   region: 'Argentina',       zone: 'America/Argentina/Buenos_Aires' },
  { name: 'Reykjavík',      region: 'Iceland',         zone: 'Atlantic/Reykjavik' },
  { name: 'London',         region: 'United Kingdom',  zone: 'Europe/London' },
  { name: 'Dublin',         region: 'Ireland',         zone: 'Europe/Dublin' },
  { name: 'Lisbon',         region: 'Portugal',        zone: 'Europe/Lisbon' },
  { name: 'Madrid',         region: 'Spain',           zone: 'Europe/Madrid' },
  { name: 'Paris',          region: 'France',          zone: 'Europe/Paris' },
  { name: 'Amsterdam',      region: 'Netherlands',     zone: 'Europe/Amsterdam' },
  { name: 'Berlin',         region: 'Germany',         zone: 'Europe/Berlin' },
  { name: 'Zürich',         region: 'Switzerland',     zone: 'Europe/Zurich' },
  { name: 'Rome',           region: 'Italy',           zone: 'Europe/Rome' },
  { name: 'Athens',         region: 'Greece',          zone: 'Europe/Athens' },
  { name: 'Stockholm',      region: 'Sweden',          zone: 'Europe/Stockholm' },
  { name: 'Helsinki',       region: 'Finland',         zone: 'Europe/Helsinki' },
  { name: 'Warsaw',         region: 'Poland',          zone: 'Europe/Warsaw' },
  { name: 'Istanbul',       region: 'Turkey',          zone: 'Europe/Istanbul' },
  { name: 'Moscow',         region: 'Russia',          zone: 'Europe/Moscow' },
  { name: 'Cairo',          region: 'Egypt',           zone: 'Africa/Cairo' },
  { name: 'Lagos',          region: 'Nigeria',         zone: 'Africa/Lagos' },
  { name: 'Nairobi',        region: 'Kenya',           zone: 'Africa/Nairobi' },
  { name: 'Johannesburg',   region: 'South Africa',    zone: 'Africa/Johannesburg' },
  { name: 'Dubai',          region: 'UAE',             zone: 'Asia/Dubai' },
  { name: 'Tehran',         region: 'Iran',            zone: 'Asia/Tehran' },
  { name: 'Karachi',        region: 'Pakistan',        zone: 'Asia/Karachi' },
  { name: 'Mumbai',         region: 'India',           zone: 'Asia/Kolkata' },
  { name: 'Delhi',          region: 'India',           zone: 'Asia/Kolkata' },
  { name: 'Bangalore',      region: 'India',           zone: 'Asia/Kolkata' },
  { name: 'Bangkok',        region: 'Thailand',        zone: 'Asia/Bangkok' },
  { name: 'Ho Chi Minh',    region: 'Vietnam',         zone: 'Asia/Ho_Chi_Minh' },
  { name: 'Hanoi',          region: 'Vietnam',         zone: 'Asia/Ho_Chi_Minh' },
  { name: 'Jakarta',        region: 'Indonesia',       zone: 'Asia/Jakarta' },
  { name: 'Singapore',      region: 'Singapore',       zone: 'Asia/Singapore' },
  { name: 'Kuala Lumpur',   region: 'Malaysia',        zone: 'Asia/Kuala_Lumpur' },
  { name: 'Hong Kong',      region: 'China',           zone: 'Asia/Hong_Kong' },
  { name: 'Shanghai',       region: 'China',           zone: 'Asia/Shanghai' },
  { name: 'Beijing',        region: 'China',           zone: 'Asia/Shanghai' },
  { name: 'Taipei',         region: 'Taiwan',          zone: 'Asia/Taipei' },
  { name: 'Seoul',          region: 'South Korea',     zone: 'Asia/Seoul' },
  { name: 'Tokyo',          region: 'Japan',           zone: 'Asia/Tokyo' },
  { name: 'Sydney',         region: 'Australia',       zone: 'Australia/Sydney' },
  { name: 'Melbourne',      region: 'Australia',       zone: 'Australia/Melbourne' },
  { name: 'Perth',          region: 'Australia',       zone: 'Australia/Perth' },
  { name: 'Auckland',       region: 'New Zealand',     zone: 'Pacific/Auckland' },
  { name: 'Honolulu',       region: 'Hawaii',          zone: 'Pacific/Honolulu' },
  { name: 'UTC',            region: 'Universal',       zone: 'UTC' },
];

const DEFAULT_ZONES = ['America/Los_Angeles', 'America/New_York', 'Europe/London', 'Asia/Tokyo'];

function WorldClockTool() {
  const [zones, setZones] = useState(DEFAULT_ZONES);
  const [hour24, setHour24] = useState(true);
  const [showSeconds, setShowSeconds] = useState(true);
  const [loaded, setLoaded] = useState(false);
  const [picker, setPicker] = useState(false);
  const [pickerQ, setPickerQ] = useState('');
  const [now, setNow] = useState(Date.now());

  // Tick every second so the analog second hand sweeps smoothly. (The digital
  // readout only recomputes when its own deps change, so this is cheap.)
  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);

  // Load persisted state.
  useEffect(() => {
    let mounted = true;
    Promise.all([db.kv.get('worldClockZones'), db.kv.get('worldClockPrefs')]).then(([z, p]) => {
      if (!mounted) return;
      if (Array.isArray(z?.v)) setZones(z.v);
      if (p?.v) {
        if (typeof p.v.hour24 === 'boolean') setHour24(p.v.hour24);
        if (typeof p.v.showSeconds === 'boolean') setShowSeconds(p.v.showSeconds);
      }
      setLoaded(true);
    });
    return () => { mounted = false; };
  }, []);

  const saveZones = (next) => { setZones(next); db.kv.put({ k: 'worldClockZones', v: next }); };
  const savePrefs = (patch) => {
    const next = { hour24, showSeconds, ...patch };
    setHour24(next.hour24); setShowSeconds(next.showSeconds);
    db.kv.put({ k: 'worldClockPrefs', v: next });
  };

  const addZone = (zone) => {
    if (zones.includes(zone)) return;
    saveZones([...zones, zone]);
  };
  const removeZone = (zone) => saveZones(zones.filter(z => z !== zone));
  const moveZone = (zone, dir) => {
    const i = zones.indexOf(zone);
    if (i < 0) return;
    const j = i + dir;
    if (j < 0 || j >= zones.length) return;
    const next = [...zones];
    [next[i], next[j]] = [next[j], next[i]];
    saveZones(next);
  };

  // Find a "city" label for a zone — fall back to the IANA name.
  const labelFor = (zone) => {
    const m = TZ_CATALOG.find(t => t.zone === zone);
    if (m) return { name: m.name, region: m.region };
    const parts = zone.split('/');
    return { name: parts[parts.length - 1].replace(/_/g, ' '), region: parts[0] };
  };

  // Filter picker — exclude already-added zones, match on name/region.
  const pickerResults = useMemo(() => {
    const q = pickerQ.trim().toLowerCase();
    return TZ_CATALOG
      .filter(t => !zones.includes(t.zone))
      .filter(t => !q || t.name.toLowerCase().includes(q) || t.region.toLowerCase().includes(q) || t.zone.toLowerCase().includes(q));
  }, [pickerQ, zones]);

  if (!loaded) return <div className="wc-tool wc-loading" />;

  // The "home" zone — first in list — drives the offset display on the others.
  const homeZone = zones[0] || 'UTC';

  return (
    <div className="wc-tool">
      <header className="wc-head">
        <div>
          <h1>World clock</h1>
          <p>The first card is your home zone — others show offset from it.</p>
        </div>
        <div className="wc-head-actions">
          <button
            className={`lh-btn ghost ${hour24 ? 'is-active' : ''}`}
            onClick={() => savePrefs({ hour24: !hour24 })}
            title="Toggle 12 / 24 hour"
          >
            <Icon name="schedule" />{hour24 ? '24h' : '12h'}
          </button>
          <button
            className={`lh-btn ghost ${showSeconds ? 'is-active' : ''}`}
            onClick={() => savePrefs({ showSeconds: !showSeconds })}
            title="Toggle seconds"
          >
            <Icon name="timer" />Seconds
          </button>
          <button className="lh-btn primary" onClick={() => setPicker(true)}>
            <Icon name="add" />Add city
          </button>
        </div>
      </header>

      {zones.length === 0 ? (
        <div className="wc-empty">
          <Icon name="public" />
          <div className="title">No cities yet</div>
          <div className="sub">Add one to get started.</div>
          <button className="lh-btn primary" onClick={() => setPicker(true)}>
            <Icon name="add" />Add city
          </button>
        </div>
      ) : (
        <div className="wc-grid">
          {zones.map((z, i) => (
            <ClockCard
              key={z + '_' + i}
              zone={z}
              label={labelFor(z)}
              now={now}
              hour24={hour24}
              showSeconds={showSeconds}
              isHome={i === 0}
              homeZone={homeZone}
              onRemove={() => removeZone(z)}
              onMoveUp={i > 0 ? () => moveZone(z, -1) : null}
              onMoveDown={i < zones.length - 1 ? () => moveZone(z, 1) : null}
            />
          ))}
        </div>
      )}

      {picker && (
        <ZonePicker
          query={pickerQ}
          setQuery={setPickerQ}
          results={pickerResults}
          onPick={(z) => { addZone(z); setPicker(false); setPickerQ(''); }}
          onClose={() => { setPicker(false); setPickerQ(''); }}
        />
      )}
    </div>
  );
}

// ============================================================
// ClockCard — analog + digital + day-context
// ============================================================
function ClockCard({ zone, label, now, hour24, showSeconds, isHome, homeZone, onRemove, onMoveUp, onMoveDown }) {
  const d = new Date(now);

  // Get time parts in the target zone via Intl
  const parts = useMemo(() => {
    const fmt = new Intl.DateTimeFormat('en-US', {
      timeZone: zone,
      hour: 'numeric', minute: '2-digit', second: '2-digit',
      hour12: !hour24,
      weekday: 'short', month: 'short', day: 'numeric',
    });
    const tokens = fmt.formatToParts(d);
    const get = (t) => tokens.find(p => p.type === t)?.value || '';
    return {
      hour: get('hour'),
      minute: get('minute'),
      second: get('second'),
      dayPeriod: get('dayPeriod'),
      weekday: get('weekday'),
      month: get('month'),
      day: get('day'),
    };
  }, [zone, hour24, Math.floor(d.getTime() / (showSeconds ? 1000 : 30000))]);

  // Analog hand angles, derived from CONTINUOUS time so they only ever
  // increase — the CSS transition then always rotates clockwise and never
  // springs backward when a hand wraps past 12 (60s → 0s, 60m → 0m).
  // Timezones only ever shift by whole minutes, so the per-zone offset is a
  // constant added to each hand; adding a constant preserves monotonicity.
  const angles = useMemo(() => {
    const offMin = zoneOffsetMin(zone, d);          // minutes east of UTC (constant per zone)
    const zonedMs = d.getTime() + offMin * 60000;   // wall-clock ms in this zone
    const totalSec = zonedMs / 1000;
    const totalMin = totalSec / 60;
    const totalHrs = totalMin / 60;
    const h24 = Math.floor(((totalHrs % 24) + 24) % 24);
    return {
      second: totalSec * 6,   // 6°/s,  monotonic
      minute: totalMin * 6,   // 6°/min, monotonic
      hour:   totalHrs * 30,  // 30°/hr, monotonic
      isDay:  h24 >= 6 && h24 < 19,
    };
  }, [zone, Math.floor(d.getTime() / 1000)]);

  // Offset from home zone in hours
  const offsetLabel = useMemo(() => {
    if (isHome) return 'Local';
    const here = zoneOffsetMin(zone, d);
    const home = zoneOffsetMin(homeZone, d);
    const diffMin = here - home;
    const sign = diffMin >= 0 ? '+' : '−';
    const abs = Math.abs(diffMin);
    const h = Math.floor(abs / 60);
    const m = abs % 60;
    return `${sign}${h}${m ? ':' + String(m).padStart(2,'0') : ''}h`;
  }, [zone, homeZone, isHome, Math.floor(d.getTime() / 60000)]);

  return (
    <article className={`wc-card ${angles.isDay ? 'is-day' : 'is-night'} ${isHome ? 'is-home' : ''}`}>
      <header className="wc-card-head">
        <div className="wc-card-title">
          <div className="wc-card-city">{label.name}</div>
          <div className="wc-card-region">
            {label.region}
            {isHome && <span className="wc-card-home-tag">Home</span>}
          </div>
        </div>
        <div className="wc-card-actions">
          {onMoveUp && <button className="wc-icon-btn" onClick={onMoveUp} title="Move up"><Icon name="arrow_upward" /></button>}
          {onMoveDown && <button className="wc-icon-btn" onClick={onMoveDown} title="Move down"><Icon name="arrow_downward" /></button>}
          <button className="wc-icon-btn" onClick={onRemove} title="Remove"><Icon name="close" /></button>
        </div>
      </header>

      <div className="wc-card-body">
        <AnalogFace angles={angles} />
        <div className="wc-card-digital">
          <div className="wc-card-time">
            <span>{parts.hour}</span>
            <span className="wc-card-colon">:</span>
            <span>{parts.minute}</span>
            {showSeconds && (
              <>
                <span className="wc-card-colon wc-card-colon-sec">:</span>
                <span className="wc-card-sec">{parts.second}</span>
              </>
            )}
            {!hour24 && parts.dayPeriod && <span className="wc-card-ampm">{parts.dayPeriod}</span>}
          </div>
          <div className="wc-card-meta">
            <span>{parts.weekday}, {parts.month} {parts.day}</span>
            <span className="wc-card-offset">{offsetLabel}</span>
          </div>
        </div>
      </div>
    </article>
  );
}

// ============================================================
// AnalogFace — SVG analog clock
// ============================================================
function AnalogFace({ angles }) {
  return (
    <svg className="wc-face" viewBox="0 0 100 100" width="92" height="92">
      <circle cx="50" cy="50" r="46" className="wc-face-ring" />
      {Array.from({ length: 12 }, (_, i) => {
        const a = (i * 30) * Math.PI / 180;
        const x1 = 50 + Math.sin(a) * 40;
        const y1 = 50 - Math.cos(a) * 40;
        const x2 = 50 + Math.sin(a) * 44;
        const y2 = 50 - Math.cos(a) * 44;
        return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} className={`wc-face-tick ${i % 3 === 0 ? 'is-major' : ''}`} />;
      })}
      <line x1="50" y1="50" x2="50" y2="22" className="wc-face-hand wc-face-hour"
        transform={`rotate(${angles.hour} 50 50)`} />
      <line x1="50" y1="50" x2="50" y2="14" className="wc-face-hand wc-face-minute"
        transform={`rotate(${angles.minute} 50 50)`} />
      <line x1="50" y1="56" x2="50" y2="12" className="wc-face-hand wc-face-second"
        transform={`rotate(${angles.second} 50 50)`} />
      <circle cx="50" cy="50" r="2.5" className="wc-face-cap" />
    </svg>
  );
}

// ============================================================
// ZonePicker — modal with search
// ============================================================
function ZonePicker({ query, setQuery, results, onPick, onClose }) {
  const inputRef = useRef(null);
  useEffect(() => { inputRef.current?.focus(); }, []);

  return (
    <div className="wc-picker-overlay" onClick={onClose}>
      <div className="wc-picker" onClick={e => e.stopPropagation()}>
        <div className="wc-picker-head">
          <Icon name="search" />
          <input
            ref={inputRef}
            placeholder="Search by city, country, or zone…"
            value={query}
            onChange={e => setQuery(e.target.value)}
            onKeyDown={e => {
              if (e.key === 'Escape') onClose();
              else if (e.key === 'Enter' && results[0]) onPick(results[0].zone);
            }}
          />
          <button className="wc-picker-close" onClick={onClose}><Icon name="close" /></button>
        </div>
        <div className="wc-picker-results">
          {results.length === 0 ? (
            <div className="wc-picker-empty">No matches.</div>
          ) : results.map((t, i) => (
            <button key={t.zone + '_' + i} className="wc-picker-row" onClick={() => onPick(t.zone)}>
              <div className="wc-picker-row-name">{t.name}</div>
              <div className="wc-picker-row-region">{t.region}</div>
              <div className="wc-picker-row-zone">{t.zone}</div>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ============================================================
// Helper: get offset (in minutes east of UTC) for a zone at a date.
// Uses Intl.DateTimeFormat to parse the formatted local time and
// compare against UTC. Not perfect but plenty accurate for display.
// ============================================================
function zoneOffsetMin(zone, date) {
  const fmt = new Intl.DateTimeFormat('en-US', {
    timeZone: zone,
    year: 'numeric', month: '2-digit', day: '2-digit',
    hour: '2-digit', minute: '2-digit', second: '2-digit',
    hour12: false,
  });
  const parts = fmt.formatToParts(date);
  const get = (t) => parts.find(p => p.type === t)?.value || '00';
  // Build a UTC date from those parts, then diff against the input ms
  const asUTC = Date.UTC(
    +get('year'),
    +get('month') - 1,
    +get('day'),
    +get('hour') % 24,
    +get('minute'),
    +get('second'),
  );
  return Math.round((asUTC - date.getTime()) / 60000);
}

window.WorldClockTool = WorldClockTool;
