// sidebar.jsx — left rail: add-blocks palette + holiday/cruise search

const BLOCK_TYPES = ["header", "offer", "cruise", "text", "image", "video", "footer"];

const CRUISE_API = 'https://tms-cruises-api.tms-travel-marketing-systems.workers.dev';

const UK_AIRPORTS = [
  'BHX','BRS','EDI','GLA','LBA','LGW','LHR','LPL','MAN','NCL',
  'SEN','STN','EMA','ABZ','BFS','ORK','DUB','INV','DSA','EXT',
  'HUY','LCY','LTN','MME','NWI','PIK','SOU','CWL','BOH','JER','GCI',
];

const CRUISE_TYPES = [
  { value: 'ocean', label: 'Ocean' },
  { value: 'river', label: 'River' },
  { value: 'tour',  label: 'Tour' },
];

// Formats offer price. Falls back to departureAirports[0].price when offer.price is empty.
function formatPrice(offer) {
  const rawPrice = offer.price || offer.departureAirports?.[0]?.price || '';
  if (!rawPrice) return '';
  // If already formatted (contains £ or 'pp'), return as-is to avoid double-formatting.
  if (rawPrice.includes('£') || rawPrice.toLowerCase().includes('pp')) return rawPrice;
  const num = parseFloat(rawPrice);
  if (isNaN(num)) return rawPrice;
  const formatted = '£' + Math.round(num).toLocaleString('en-GB');
  const cat = (offer.priceCategory || '').toLowerCase();
  return (cat.includes('pp') || cat.includes('per person')) ? formatted + 'pp' : formatted;
}

// Derives availability text from offer.bookingPeriodEnd (ISO date string) if present.
function formatBookBy(offer) {
  if (offer.bookingPeriodEnd) {
    // Force midnight local time to avoid UTC-boundary day-shift.
    const d = new Date(offer.bookingPeriodEnd + 'T00:00:00');
    if (!isNaN(d)) {
      return 'Book by ' + d.toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' });
    }
  }
  return 'Limited availability';
}

function CruisesTab({ onAddCruise }) {
  const [q, setQ] = React.useState('');
  const [ship, setShip] = React.useState('');
  const [cruiseType, setCruiseType] = React.useState('ocean');
  const [operatorId, setOperatorId] = React.useState('');
  const [region, setRegion] = React.useState('');
  const [monthKey, setMonthKey] = React.useState('');
  const [operators, setOperators] = React.useState([]);
  const [regions, setRegions] = React.useState([]);
  const [results, setResults] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const debounceRef = React.useRef(null);

  const monthOptions = React.useMemo(() => {
    const months = [];
    const now = new Date();
    for (let i = 0; i < 18; i++) {
      const d = new Date(now.getFullYear(), now.getMonth() + i, 1);
      months.push({
        label: d.toLocaleString('en-GB', { month: 'long', year: 'numeric' }),
        month: String(d.getMonth() + 1).padStart(2, '0'),
        year:  String(d.getFullYear()),
      });
    }
    return months;
  }, []);

  // Reload operators + regions when cruiseType changes
  React.useEffect(() => {
    setOperatorId('');
    setRegion('');
    Promise.all([
      fetch(`${CRUISE_API}/operators?type=${cruiseType}`).then(r => r.json()),
      fetch(`${CRUISE_API}/regions?type=${cruiseType}`).then(r => r.json()),
    ]).then(([opData, regData]) => {
      setOperators(opData.operators || []);
      setRegions(regData.regions || []);
    }).catch(() => {});
  }, [cruiseType]);

  const doSearch = React.useCallback(async (cQ, cShip, cT, cO, cR, cMonthKey) => {
    setLoading(true);
    setError(null);
    try {
      const params = new URLSearchParams({ limit: '20', sort: 'date' });
      const combinedQ = [cQ, cShip].filter(Boolean).join(' ');
      if (combinedQ) params.set('q', combinedQ);
      if (cT) params.set('type', cT);
      if (cO) params.set('operator_id', cO);
      if (cR) params.set('region', cR);
      if (cMonthKey) {
        const [mm, yyyy] = cMonthKey.split('/');
        params.set('month', mm);
        params.set('year', yyyy);
      }
      const url = `${CRUISE_API}/search?${params}`;
      console.log('[TMS cruise search]', url);
      const res = await fetch(url);
      if (!res.ok) throw new Error(res.status);
      const data = await res.json();
      setResults(data.cruises || data.results || []);
    } catch (e) {
      setError('Could not load cruises — check your connection');
      setResults(null);
    } finally {
      setLoading(false);
    }
  }, []);

  // Debounce search on any filter change
  React.useEffect(() => {
    clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => doSearch(q, ship, cruiseType, operatorId, region, monthKey), 300);
    return () => clearTimeout(debounceRef.current);
  }, [q, ship, cruiseType, operatorId, region, monthKey, doSearch]);

  const hasFilters = cruiseType !== 'ocean' || operatorId !== '' || region !== '' || ship !== '' || monthKey !== '';
  const clearFilters = () => { setCruiseType('ocean'); setOperatorId(''); setRegion(''); setShip(''); setMonthKey(''); };

  const fmtDate = (iso) => {
    if (!iso) return '';
    const d = new Date(iso + 'T00:00:00');
    return isNaN(d) ? iso : d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' });
  };

  const fmtPrice = (c) => c.display_price
    ? 'From £' + Math.round(c.display_price).toLocaleString('en-GB') + 'pp' : '';

  const normalizeUrl = (url) => {
    if (!url) return '';
    // Widgety returns protocol-relative URLs (//widgety.co.uk/...) — add https: for Cloudinary
    return url.startsWith('//') ? 'https:' + url : url;
  };

  const handleAdd = (c) => {
    console.log('cover_image_url raw:', c.cover_image_url);
    const rawImg = normalizeUrl(c.cover_image_url);
    onAddCruise({
      cruiseName:    c.name,
      operatorLine:  [c.operator_name, c.ship_name].filter(Boolean).join(' · '),
      departureDate: fmtDate(c.departure_date),
      duration:      c.duration_nights ? String(c.duration_nights) : '',
      departurePort: c.departure_port || '',
      regions:       Array.isArray(c.regions) ? c.regions.join(', ') : (c.regions || ''),
      price:         fmtPrice(c),
      imageUrl:      rawImg,
      ctaUrl:        `https://cruise-search.pages.dev/detail?id=${c.id}`,
      teaser:        '',
      promoBadge:    c.has_promo ? (c.promo_headline || 'Special offer') : '',
      cruiseType:    c.cruise_type || 'ocean',
      _id:           c.id,
    });
  };

  return (
    <div className="bld-search">
      <div className="bld-filters" style={{ gridTemplateColumns: '1fr' }}>
        <input className="bld-input" placeholder="Destination or cruise line…"
               value={q} onChange={(e) => setQ(e.target.value)} />
      </div>
      <div className="bld-filters">
        <select className="bld-select" value={cruiseType} onChange={(e) => setCruiseType(e.target.value)}>
          {CRUISE_TYPES.map(t => <option key={t.value} value={t.value}>{t.label}</option>)}
        </select>
        <select className="bld-select" value={operatorId} onChange={(e) => setOperatorId(e.target.value)}>
          <option value="">Any operator</option>
          {operators.map(o => <option key={o.id} value={String(o.id)}>{o.name}</option>)}
        </select>
        <select className="bld-select" value={region} onChange={(e) => setRegion(e.target.value)}>
          <option value="">Any region</option>
          {regions.map(r => <option key={r}>{r}</option>)}
        </select>
        <select className="bld-select" value={monthKey} onChange={(e) => setMonthKey(e.target.value)}>
          <option value="">Any month</option>
          {monthOptions.map(m => (
            <option key={`${m.month}/${m.year}`} value={`${m.month}/${m.year}`}>{m.label}</option>
          ))}
        </select>
        <input className="bld-input" placeholder="Ship name…" value={ship}
               onChange={(e) => setShip(e.target.value)}
               style={{ gridColumn: '1 / -1' }} />
      </div>
      {hasFilters && (
        <div style={{ padding: '2px 0 4px', textAlign: 'right' }}>
          <button onClick={clearFilters}
                  style={{ background: 'none', border: 'none', padding: 0, fontSize: 11, color: 'var(--product-fg-muted)', cursor: 'pointer', textDecoration: 'underline' }}>
            Clear filters
          </button>
        </div>
      )}
      {loading ? (
        <p className="bld-search-empty">Loading cruises…</p>
      ) : error ? (
        <p className="bld-search-empty" style={{ color: 'var(--tms-red-500)' }}>{error}</p>
      ) : results === null ? (
        <p className="bld-search-empty">Browse sailings by destination, cruise line or region.</p>
      ) : results.length === 0 ? (
        <p className="bld-search-empty">No cruises match. Try widening your filters.</p>
      ) : (
        <>
          <div className="bld-search-meta"><span>{results.length} cruise{results.length === 1 ? '' : 's'}</span><span>Tap to add</span></div>
          <div className="bld-results">
            {results.map((c, i) => (
              <button key={c.id || i} className="bld-result bld-result--cruise" onClick={() => handleAdd(c)}>
                {c.cover_image_url && (
                  <img className="bld-result-thumb" src={normalizeUrl(c.cover_image_url)} alt={c.name} />
                )}
                <div className="bld-result-body">
                  <span className="bld-result-top">
                    <span className="bld-result-dest">{c.name}</span>
                    {fmtPrice(c) && <span className="bld-result-price">{fmtPrice(c)}</span>}
                  </span>
                  <span className="bld-result-sub">
                    {[c.operator_name, fmtDate(c.departure_date), c.duration_nights && c.duration_nights + ' nts'].filter(Boolean).join(' · ')}
                  </span>
                  {c.has_promo && (
                    <span className="bld-result-badge bld-result-badge--promo">{c.promo_headline || 'Special offer'}</span>
                  )}
                </div>
              </button>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

function Sidebar({ onAddBlock, onAddOffer, onAddCruise, section }) {
  const { Search, Lock } = window.Icons;
  const [tab, setTab] = React.useState('holidays');
  const [q, setQ] = React.useState("");
  const [airport, setAirport] = React.useState("Any airport");
  const [operator, setOperator] = React.useState("Any operator");
  const [date, setDate] = React.useState("Any date");
  const [allOffers, setAllOffers] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  const cruisesEnabled = (window.TMS_CONFIG?.features?.cruises) !== false;

  React.useEffect(() => {
    if (tab === 'holidays' && allOffers === null) runSearch();
  }, [tab]); // eslint-disable-line

  const airportOptions = React.useMemo(() => {
    if (!allOffers) return [];
    const seen = new Map();
    allOffers.forEach(o => {
      (o.departureAirports || []).forEach(a => {
        if (UK_AIRPORTS.includes(a.type) && !seen.has(a.type)) {
          seen.set(a.type, a.airport);
        }
      });
    });
    return [...seen.entries()]
      .sort((a, b) => a[1].localeCompare(b[1]))
      .map(([type, airport]) => ({ type, airport }));
  }, [allOffers]);

  const operators = React.useMemo(() => {
    if (!allOffers) return ["Any operator"];
    const vals = [...new Set(allOffers.map(o => o.operator).filter(Boolean))].sort();
    return ["Any operator", ...vals];
  }, [allOffers]);

  const dates = React.useMemo(() => {
    if (!allOffers) return ["Any date"];
    const vals = [...new Set(allOffers.map(o => {
      if (!o.holidayStartDate) return null;
      const d = new Date(o.holidayStartDate + 'T00:00:00');
      if (isNaN(d)) return null;
      return d.toLocaleDateString('en-GB', { month: 'short', year: 'numeric' });
    }).filter(Boolean))].sort();
    return ["Any date", ...vals];
  }, [allOffers]);

  const results = React.useMemo(() => {
    if (!allOffers) return null;
    const ql = q.trim().toLowerCase();
    return allOffers.filter(o => {
      if (ql && ![(o.destination || ''), (o.name || ''), (o.operator || ''), (o.title || '')].some(s => s.toLowerCase().includes(ql))) return false;
      if (operator !== "Any operator" && (o.operator || '') !== operator) return false;
      // Airport filter: match against any departure airport, not just [0].
      if (airport !== "Any airport" && !(o.departureAirports || []).some(d => d.airport === airport)) return false;
      if (date !== "Any date") {
        if (!o.holidayStartDate) return false;
        const d = new Date(o.holidayStartDate + 'T00:00:00');
        if (isNaN(d)) return false;
        if (d.toLocaleDateString('en-GB', { month: 'short', year: 'numeric' }) !== date) return false;
      }
      return true;
    });
  }, [allOffers, q, airport, operator, date]);

  const runSearch = async () => {
    const cfg = window.TMS_CONFIG || {};
    const siteId = cfg.siteId || '';
    const offersUrl = (cfg.offersUrl || 'https://tms-offers.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
    if (!siteId) {
      setError("No siteId configured — set TMS_CONFIG.siteId");
      setAllOffers(null);
      return;
    }
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(`${offersUrl}/offers?siteId=${encodeURIComponent(siteId)}`);
      if (!res.ok) {
        const text = await res.text();
        console.warn('[TMS offer search] Worker error', res.status, text);
        throw new Error(`${res.status}`);
      }
      const data = await res.json();
      const offers = Array.isArray(data.offers) ? data.offers : Array.isArray(data) ? data : [];
      console.log('[TMS offer search] raw response', {
        source: data.source,
        fetchedAt: data.fetchedAt,
        count: offers.length,
        firstOffer: offers[0] || null,
      });
      if (offers.length === 0) {
        console.warn('[TMS offer search] Worker returned 0 offers for siteId:', siteId, '— full response:', data);
      }
      setAllOffers(offers);
    } catch (e) {
      setError("Could not load offers — check your connection");
      setAllOffers(null);
    } finally {
      setLoading(false);
    }
  };

  // Maps a raw Offer (from Worker) to the shape addOffer() in app.jsx expects.
  const mapOffer = (o) => {
    const cfg = window.TMS_CONFIG || {};
    const ctaUrl = o.extra?.url
      || o.ctaUrl
      || (cfg.defaultOfferUrl
          ? `${cfg.defaultOfferUrl}/${o.id}`
          : `https://www.screen.latecards.co.uk/offer-detail-page?id=${encodeURIComponent(o.id)}`);
    return {
      dest:         o.destination || o.name,
      title:        o.title || '',
      price:        formatPrice(o),
      badge:        o.flightIncluded !== false ? 'ATOL Protected' : 'ABTA',
      op:           o.operator || '',
      airport:      o.departureAirports?.[0]?.airport || '',
      nights:       o.nights || '',
      board:        o.board || '',
      imageUrl:     o.imageUrl || '',
      ctaUrl,
      availability: formatBookBy(o),
    };
  };

  return (
    <aside className="bld-sidebar">
      {section !== 'search' && (<>
        <div className="bld-side-head">Add blocks</div>
        <div className="bld-palette">
          {BLOCK_TYPES.map((t) => {
            const Ic = window.Icons[window.TYPE_META[t].label];
            return (
              <button key={t} className="bld-palette-btn" onClick={() => onAddBlock(t)}>
                <span className="bld-palette-ic"><Ic /></span>
                {window.TYPE_META[t].label}
              </button>
            );
          })}
        </div>
        <div className="bld-divider" />
      </>)}

      {section !== 'blocks' && (<>
        <div className="bld-tabs">
          <button className={"bld-tab" + (tab === 'holidays' ? " is-active" : "")}
                  onClick={() => setTab('holidays')}>Holidays</button>
          <button className={"bld-tab" + (tab === 'cruises' ? " is-active" : "")}
                  onClick={() => cruisesEnabled && setTab('cruises')}
                  disabled={!cruisesEnabled}
                  title={!cruisesEnabled ? 'Cruise search — contact your account manager to enable' : ''}>
            {!cruisesEnabled && <Lock />}Cruises
          </button>
        </div>
      </>)}

      {section !== 'blocks' && tab === 'holidays' && (
        <div className="bld-search">
          <div className="bld-search-head">Offer search</div>
          <div className="bld-search-row">
            <input className="bld-input" placeholder="Destination or operator…" value={q}
                   onChange={(e) => setQ(e.target.value)} />
            <button className="bld-search-go" title="Search offers" onClick={runSearch} disabled={loading}>
              {loading ? <span style={{ fontSize: 11, lineHeight: 1, letterSpacing: 1 }}>...</span> : <Search />}
            </button>
          </div>
          <div className="bld-filters">
            <select className="bld-select" value={airport} onChange={(e) => setAirport(e.target.value)}>
              <option value="Any airport">Any airport</option>
              {airportOptions.map(({ type, airport: name }) => (
                <option key={type} value={name}>{name}</option>
              ))}
            </select>
            <select className="bld-select" value={operator} onChange={(e) => setOperator(e.target.value)}>
              {operators.map((o) => <option key={o}>{o}</option>)}
            </select>
            <select className="bld-select" value={date} onChange={(e) => setDate(e.target.value)} style={{ gridColumn: "1 / -1" }}>
              {dates.map((d) => <option key={d}>{d}</option>)}
            </select>
          </div>

          {error ? (
            <p className="bld-search-empty" style={{ color: 'var(--tms-red-500)' }}>{error}</p>
          ) : results === null ? (
            <p className="bld-search-empty">Search live availability from your agent account — by destination, airport, operator or date.</p>
          ) : results.length === 0 ? (
            <p className="bld-search-empty">No offers match. Try widening your filters.</p>
          ) : (
            <>
              <div className="bld-search-meta"><span>{results.length} offer{results.length === 1 ? "" : "s"}</span><span>Tap to add</span></div>
              <div className="bld-results">
                {results.map((o, i) => {
                  const thumbUrl = (o.imageUrl || '').replace('http://', 'https://');
                  return (
                    <button key={i} className="bld-result bld-result--cruise" onClick={() => onAddOffer(mapOffer(o))}>
                      <span className="bld-result-thumb" style={{ flexShrink: 0, background: '#0A6E7E', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
                        {thumbUrl
                          ? <img src={thumbUrl} alt="" width="48" height="48"
                                 style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
                                 onError={(e) => { e.currentTarget.style.display = 'none'; }} />
                          : <span style={{ color: '#C5EAEE', fontSize: 16 }}>&#9992;</span>
                        }
                      </span>
                      <div className="bld-result-body">
                        <span className="bld-result-top">
                          <span className="bld-result-dest">{o.destination || o.name}</span>
                          <span className="bld-result-price">{formatPrice(o)}</span>
                        </span>
                        <span className="bld-result-sub">
                          {[o.title, o.nights && `${o.nights} nts`, o.board, o.operator, o.departureAirports?.[0]?.airport].filter(Boolean).join(' · ')}
                        </span>
                        <span className="bld-result-badge">{o.flightIncluded !== false ? 'ATOL Protected' : 'ABTA'}</span>
                      </div>
                    </button>
                  );
                })}
              </div>
            </>
          )}
        </div>
      )}

      {section !== 'blocks' && tab === 'cruises' && cruisesEnabled && (
        <CruisesTab onAddCruise={onAddCruise} />
      )}
    </aside>
  );
}

window.Sidebar = Sidebar;
