const { useState, useEffect, useMemo, useRef } = React;

const ASSETS = '/neu-design-system/project/assets';
const PHOTOS = '/src/Assets.xcassets';
const APP_DOWNLOAD_URLS = {
  en: 'https://apps.apple.com/us/app/ski-slopes-maps-neu/id6476763152',
  es: 'https://apps.apple.com/es/app/mapas-de-esqu%C3%AD-3d-neu/id6476763152',
  ca: 'https://apps.apple.com/es/app/mapes-desqu%C3%AD-3d-neu/id6476763152?l=ca',
};
function appDownloadUrl(lang) { return APP_DOWNLOAD_URLS[lang] || APP_DOWNLOAD_URLS.en; }

/* ──────────────────────────── DATA LOADER ──────────────────────────── */


function parseCSV(text) {
  const lines = text.replace(/\r\n/g, '\n').split('\n').filter(l => l.length);
  const split = (line) => {
    const out = []; let cur = ''; let q = false;
    for (let i = 0; i < line.length; i++) {
      const c = line[i];
      if (q) {
        if (c === '"' && line[i+1] === '"') { cur += '"'; i++; }
        else if (c === '"') { q = false; }
        else { cur += c; }
      } else {
        if (c === '"') q = true;
        else if (c === ',') { out.push(cur); cur = ''; }
        else { cur += c; }
      }
    }
    out.push(cur);
    return out;
  };
  const header = split(lines[0]);
  return lines.slice(1).map(line => {
    const cells = split(line);
    const row = {};
    header.forEach((h, i) => row[h] = cells[i] ?? '');
    return row;
  });
}

function num(v) { const n = Number(v); return isFinite(n) ? n : 0; }

const KM_DIFFICULTY_COUNTRIES = new Set(['United States', 'Canada']);

function mapResort(row, idx, webcamsMap) {
  const kmTotalNum = num(row.totalSlopesKm);
  const km = row.totalSlopesKm ? kmTotalNum.toFixed(2) : null;
  const price = row.dayPrice
    ? (row.priceCurrency === 'EUR' ? '€' : (row.priceCurrency === 'USD' ? '$' : row.priceCurrency + ' '))
      + num(row.dayPrice).toFixed(2)
    : null;
  const websiteDisplay = row.url_website
    ? row.url_website.replace(/^https?:\/\/(www\.)?/, '').replace(/\/$/, '')
    : null;

  // For US/Canada the difficulty breakdown is in kilometers, not slope counts.
  // iOS NEU app maps: intermediateSlopesKm → Easy, advancedSlopesKm → Intermediate, expertSlopesKm → Difficult.
  // If country is US/Canada AND any of those are > 0, expose `difficultyKm`; otherwise leave null
  // so ResortStatistics falls back to the count-based 4-segment chart.
  const easyKm = num(row.intermediateSlopesKm);
  const interKm = num(row.advancedSlopesKm);
  const hardKm = num(row.expertSlopesKm);
  const useKmBreakdown = KM_DIFFICULTY_COUNTRIES.has(row.country) && (easyKm + interKm + hardKm) > 0;

  return {
    id: row.idName,
    name: row.name,
    region: row.region,
    country: row.country,
    latitude: num(row.latitude),
    longitude: num(row.longitude),
    slopes: num(row.totalSlopesNumber),
    lifts: num(row.totalLifts),
    km,
    kmTotal: kmTotalNum,
    photo: `${PHOTOS}/${row.idName}_photo.imageset/${row.idName}_photo.jpg`,
    logo: `${ASSETS}/resort-logos/${row.idName}_logo.png`,
    isPro: row.freeMap === 'FALSE',
    price,
    website: row.url_website || null,
    websiteDisplay,
    hotelsUrl: row.url_hotels || null,
    difficulty: {
      beg:   num(row.beginnerSlopes),
      inter: num(row.intermediateSlopes),
      adv:   num(row.advancedSlopes),
      exp:   num(row.expertSlopes),
    },
    difficultyKm: useKmBreakdown ? { easy: easyKm, inter: interKm, hard: hardKm } : null,
    webcams: (webcamsMap?.[row.idName] || []).map(c => c.id),
  };
}

async function loadResorts() {
  const [csvText, webcamsMap] = await Promise.all([
    fetch('/src/resorts_v2.csv?v=3').then(r => r.text()),
    fetch('/src/data/webcams.json').then(r => r.ok ? r.json() : {}).catch(() => ({})),
  ]);
  return parseCSV(csvText).map((row, i) => mapResort(row, i, webcamsMap));
}

const Icon = ({ name, size = 18, color = "currentColor", stroke = 1.6 }) => {
  const paths = {
    mountain: <path d="M8 3l-6 17h20L15 3l-3.5 9L8 3z"/>,
    chevrons: <g><polyline points="7 15 12 20 17 15"/><polyline points="7 9 12 4 17 9"/></g>,
    cloud: <path d="M17.5 19a4.5 4.5 0 1 0 0-9 6.5 6.5 0 0 0-12.6 2A4 4 0 0 0 6 20h11.5z"/>,
    sun: <g><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></g>,
    sunrise: <g><path d="M18 17a6 6 0 0 0-12 0"/><path d="M12 2v6"/><path d="M4 17h16"/><path d="M9 5l3-3 3 3"/></g>,
    sunset:  <g><path d="M18 7a6 6 0 0 1-12 0"/><path d="M12 22v-6"/><path d="M4 7h16"/><path d="M9 19l3 3 3-3"/></g>,
    droplets: <path d="M7 16.3a5 5 0 0 0 5 5 5 5 0 0 0 5-5c0-3-5-9-5-9s-5 6-5 9z"/>,
    wind: <g><path d="M17.7 7.7a2.5 2.5 0 1 1 1.8 4.3H2"/><path d="M9.6 4.6A2 2 0 1 1 11 8H2"/><path d="M12.6 19.4A2 2 0 1 0 14 16H2"/></g>,
    search: <g><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></g>,
    pin: <g><path d="M12 21s-7-6.5-7-12a7 7 0 1 1 14 0c0 5.5-7 12-7 12z"/><circle cx="12" cy="9" r="3"/></g>,
    "chevron-left": <polyline points="15 18 9 12 15 6"/>,
    plus: <g><path d="M12 5v14M5 12h14"/></g>,
    minus: <path d="M5 12h14"/>,
    settings: <g><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06A2 2 0 0 1 7.04 4.3l.06.06A1.65 1.65 0 0 0 8.92 4a1.65 1.65 0 0 0 1-1.51V2.4a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c.21.64.8 1 1.51 1H21a2 2 0 0 1 0 4h-.09c-.71 0-1.3.36-1.51 1z"/></g>,
    rain: <g><path d="M17.5 12a4.5 4.5 0 1 0 0-9 6.5 6.5 0 0 0-12.6 2A4 4 0 0 0 6 13h11.5z"/><path d="M8 19v1M8 15v1M12 21v1M12 17v1M16 19v1M16 15v1"/></g>,
    snow: <g><path d="M12 2v20"/><path d="M2 12h20"/><path d="M4.93 4.93l14.14 14.14"/><path d="M19.07 4.93L4.93 19.07"/><path d="M12 5l-2 2M12 5l2 2M12 19l-2-2M12 19l2-2M5 12l2-2M5 12l2 2M19 12l-2-2M19 12l-2 2"/></g>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color}
         strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" style={{display:'block'}}>
      {paths[name] || null}
    </svg>
  );
};

function LangSelector({ onSelect }) {
  const { lang, setLang, t } = useI18n();
  return (
    <div className="segmented-control lang-selector" role="group" aria-label={t('header.langAria')}>
      <span className="lang-selector__label">{t('header.langAria')}:</span>
      {LANGS.map(code => (
        <button
          key={code}
          type="button"
          className={`lang-selector__btn ${code === lang ? 'is-active' : ''}`}
          onClick={() => {
            setLang(code);
            onSelect?.();
          }}
          aria-pressed={code === lang}
        >
          {code.toUpperCase()}
        </button>
      ))}
    </div>
  );
}

function UnitsSelector() {
  const { t } = useI18n();
  const { distanceUnit, setDistanceUnit } = window.usePrefs();
  const options = [
    { value: 'metric', label: t('header.unitsMetric') },
    { value: 'imperial', label: t('header.unitsImperial') },
  ];
  return (
    <div className="segmented-control units-selector" role="group" aria-label={t('header.unitsAria')}>
      <span className="lang-selector__label">{t('header.unitsLabel')}:</span>
      {options.map(opt => (
        <button
          key={opt.value}
          type="button"
          className={`lang-selector__btn ${opt.value === distanceUnit ? 'is-active' : ''}`}
          onClick={() => setDistanceUnit(opt.value)}
          aria-pressed={opt.value === distanceUnit}
        >
          {opt.label}
        </button>
      ))}
    </div>
  );
}

function TemperatureSelector() {
  const { t } = useI18n();
  const { temperatureUnit, setTemperatureUnit } = window.usePrefs();
  const options = [
    { value: 'c', label: t('header.tempC') },
    { value: 'f', label: t('header.tempF') },
  ];
  return (
    <div className="segmented-control temperature-selector" role="group" aria-label={t('header.tempAria')}>
      <span className="lang-selector__label">{t('header.tempLabel')}:</span>
      {options.map(opt => (
        <button
          key={opt.value}
          type="button"
          className={`lang-selector__btn ${opt.value === temperatureUnit ? 'is-active' : ''}`}
          onClick={() => setTemperatureUnit(opt.value)}
          aria-pressed={opt.value === temperatureUnit}
        >
          {opt.label}
        </button>
      ))}
    </div>
  );
}

function SettingsMenu() {
  const { lang, t } = useI18n();
  const [open, setOpen] = useState(false);
  const rootRef = useRef(null);

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => {
      if (!rootRef.current?.contains(e.target)) setOpen(false);
    };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  return (
    <div className="settings-menu" ref={rootRef}>
      <button
        type="button"
        className={`settings-menu__button ${open ? 'is-open' : ''}`}
        onClick={() => setOpen(v => !v)}
        aria-label={t('header.settingsAria')}
        aria-expanded={open}
      >
        <span className="settings-menu__gear"><Icon name="settings" size={22} color="#0A0A0A" stroke={2}/></span>
        <span className="settings-menu__burger" />
        <span className="settings-menu__burger" />
        <span className="settings-menu__burger" />
      </button>
      {open && (
        <div className="settings-menu__panel">
          <LangSelector onSelect={() => setOpen(false)} />
          <UnitsSelector/>
          <TemperatureSelector/>
          <a className="neu-btn-primary neu-btn-primary--dark settings-menu__download" href={appDownloadUrl(lang)} target="_blank" rel="noopener noreferrer">
            {t('header.download')}
          </a>
        </div>
      )}
    </div>
  );
}

function Header({ onBack, onHome }) {
  const { lang, t } = useI18n();
  return (
    <header className="neu-header">
      <div className="neu-header__brand">
        <button className="neu-header__back" onClick={onBack} aria-label={t('header.backAria')}>
          <Icon name="chevron-left" size={22} color="#0A0A0A" stroke={2}/>
          <span>{t('header.back')}</span>
        </button>
        <button type="button" className="neu-header__home" onClick={onHome} aria-label={t('header.homeAria')}>
          <NeuLogo size={32} />
          <span className="neu-h2">{t('header.brand')}</span>
        </button>
      </div>
      <div className="neu-header__actions">
        <SettingsMenu/>
        <a className="neu-btn-primary neu-btn-primary--dark neu-header__download" href={appDownloadUrl(lang)} target="_blank" rel="noopener noreferrer">{t('header.download')}</a>
      </div>
    </header>
  );
}

function Footer() {
  const { lang, t } = useI18n();
  const instagramUrl = lang === 'en'
    ? 'https://www.instagram.com/neu_ski_app/'
    : 'https://www.instagram.com/neu_esqui_app/';
  const tiktokUrl = lang === 'en'
    ? 'https://www.tiktok.com/@neu.ski'
    : 'https://www.tiktok.com/@neu.esqui';
  const columns = [
    {
      title: t('footer.about.title'),
      links: [
        { label: t('footer.about.developer'), href: 'https://guillembruix.com/' },
        { label: t('footer.about.privacy'), href: 'https://guillembruix.com/store/neu_ski_slopes/neu-app-privacy-policy/' },
        { label: t('footer.about.terms'), href: 'https://guillembruix.com/store/neu_ski_slopes/neu-app-terms-of-use/' },
        { label: t('footer.about.contact'), href: 'https://guillembruix.com/store/contact/' },
      ],
    },
    {
      title: t('footer.community.title'),
      links: [
        { label: 'Instagram', href: instagramUrl },
        { label: 'TikTok', href: tiktokUrl },
        { label: 'Discord', href: 'https://discord.gg/mVZz7jBgEX' },
        { label: 'Product Hunt', href: 'https://www.producthunt.com/products/neu-2' },
      ],
    },
    {
      title: t('footer.app.title'),
      links: [
        { label: t('footer.app.download'), href: appDownloadUrl(lang) },
      ],
    },
  ];

  return (
    <footer className="site-footer">
      <a className="site-footer__brand" href={appDownloadUrl(lang)} target="_blank" rel="noopener noreferrer">
        <NeuLogo size={28} />
        <span>{t('footer.brand')}</span>
      </a>
      <div className="site-footer__columns">
        {columns.map(column => (
          <nav className="site-footer__column" key={column.title} aria-label={column.title}>
            <div className="site-footer__heading">{column.title}</div>
            {column.links.map(link => (
              <a key={link.href} className="site-footer__link" href={link.href} target="_blank" rel="noopener noreferrer">
                {link.label}
              </a>
            ))}
          </nav>
        ))}
      </div>
    </footer>
  );
}

function ResortCard({ resort, active, onClick }) {
  const { lang, t } = useI18n();
  const { distanceUnit } = window.usePrefs();
  const stats = resort.km
    ? t('resortCard.stats',     { distance: window.formatDistanceKm(resort.kmTotal, distanceUnit), slopes: resort.slopes, lifts: resort.lifts })
    : t('resortCard.statsNoKm', {                slopes: resort.slopes, lifts: resort.lifts });
  return (
    <button className={`resort-card ${active ? 'is-active' : ''}`} onClick={onClick}>
      <div className="resort-card__bg" style={{backgroundImage:`url(${resort.photo})`}} />
      <div className="resort-card__grad" />
      {resort.logo && (
        <div className="resort-card__logo">
          <img src={resort.logo} alt="" onError={(e) => { e.currentTarget.parentElement.style.display = 'none'; }} />
        </div>
      )}
      <div className="resort-card__meta">
        <div className="neu-h3">{resort.name}</div>
        <div className="resort-card__region">{translatePlace(resort.region, lang)}</div>
        <div className="resort-card__stats">{stats}</div>
      </div>
    </button>
  );
}

function groupByRegion(resorts) {
  const map = new Map();
  for (const r of resorts) {
    const key = `${r.country}|${r.region}`;
    if (!map.has(key)) map.set(key, { country: r.country, region: r.region, items: [] });
    map.get(key).items.push(r);
  }
  return Array.from(map.values());
}

function buildFilterOptions(resorts) {
  const byCountry = new Map();
  for (const r of resorts) {
    if (!byCountry.has(r.country)) byCountry.set(r.country, new Map());
    const regions = byCountry.get(r.country);
    regions.set(r.region, (regions.get(r.region) || 0) + 1);
  }
  const countries = Array.from(byCountry.entries()).map(([country, regions]) => ({
    country,
    total: Array.from(regions.values()).reduce((a, b) => a + b, 0),
    regions: Array.from(regions.entries()).map(([region, count]) => ({ region, count })),
  }));
  countries.sort((a, b) => a.country.localeCompare(b.country));
  countries.forEach(c => c.regions.sort((a, b) => a.region.localeCompare(b.region)));
  return countries;
}

function normalizeSearchText(value) {
  return String(value || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .trim();
}

function Sidebar({ resorts, activeId, onPick }) {
  const { lang, t } = useI18n();
  const [filter, setFilter] = useState({ kind: 'all' });
  const [search, setSearch] = useState('');
  const [open, setOpen] = useState(false);
  const rootRef = useRef(null);

  const options = useMemo(() => buildFilterOptions(resorts), [resorts]);

  const facetFiltered = useMemo(() => {
    if (filter.kind === 'country') return resorts.filter(r => r.country === filter.country);
    if (filter.kind === 'region')  return resorts.filter(r => r.country === filter.country && r.region === filter.region);
    return resorts;
  }, [resorts, filter]);

  const filtered = useMemo(() => {
    const query = normalizeSearchText(search);
    if (!query) return facetFiltered;
    return facetFiltered.filter(r => normalizeSearchText([
      r.name,
      r.country,
      r.region,
      translatePlace(r.country, lang),
      translatePlace(r.region, lang),
    ].join(' ')).includes(query));
  }, [facetFiltered, search, lang]);

  const groups = useMemo(() => groupByRegion(filtered), [filtered]);

  const label =
    filter.kind === 'all'     ? t('sidebar.allCountries') :
    filter.kind === 'country' ? translatePlace(filter.country, lang) :
    /* region */                translatePlace(filter.region, lang);

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (!rootRef.current?.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const pick = (next) => { setFilter(next); setOpen(false); };

  return (
    <aside className="neu-sidebar">
      <div className="neu-sidebar__head" ref={rootRef}>
        <div className="neu-sidebar__title">
          <Icon name="mountain" size={14} color="#007AFF" stroke={1.6}/>
          <span className="neu-h4">{t('sidebar.title')}</span>
        </div>
        <label className="neu-sidebar__search">
          <Icon name="search" size={14} color="#717182" stroke={1.6}/>
          <input
            type="search"
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder={t('sidebar.searchPlaceholder')}
            aria-label={t('sidebar.searchAria')}
          />
        </label>
        <button className="neu-combobox" onClick={() => setOpen(o => !o)} aria-expanded={open}>
          <span className="neu-combobox__lbl">{label}</span>
          <span className="neu-combobox__ct">({filtered.length})</span>
          <span className="neu-combobox__ch"><Icon name="chevrons" size={14} color="#717182" stroke={1.6}/></span>
        </button>
        {open && (
          <div className="neu-combobox__menu" role="listbox">
            <button className={`neu-combobox__opt ${filter.kind === 'all' ? 'is-sel' : ''}`}
                    onClick={() => pick({ kind: 'all' })}>
              <span>{t('sidebar.allCountries')}</span>
              <span className="neu-combobox__opt-ct">{resorts.length}</span>
            </button>
            {options.map(c => (
              <React.Fragment key={c.country}>
                <button className={`neu-combobox__opt neu-combobox__opt--country ${filter.kind === 'country' && filter.country === c.country ? 'is-sel' : ''}`}
                        onClick={() => pick({ kind: 'country', country: c.country })}>
                  <span>{translatePlace(c.country, lang)}</span>
                  <span className="neu-combobox__opt-ct">{c.total}</span>
                </button>
                {c.regions.map(rg => (
                  <button key={rg.region}
                          className={`neu-combobox__opt neu-combobox__opt--nested ${filter.kind === 'region' && filter.country === c.country && filter.region === rg.region ? 'is-sel' : ''}`}
                          onClick={() => pick({ kind: 'region', country: c.country, region: rg.region })}>
                    <span>{translatePlace(rg.region, lang)}</span>
                    <span className="neu-combobox__opt-ct">{rg.count}</span>
                  </button>
                ))}
              </React.Fragment>
            ))}
          </div>
        )}
      </div>
      <div className="neu-sidebar__list">
        {groups.length ? groups.map(g => (
          <React.Fragment key={`${g.country}|${g.region}`}>
            <div className="neu-sidebar__group">
              <span className="neu-sidebar__group-country">{translatePlace(g.country, lang)}:</span> {translatePlace(g.region, lang)}
            </div>
            {g.items.map(r => (
              <ResortCard key={r.id} resort={r} active={r.id === activeId} onClick={() => onPick(r.id)} />
            ))}
          </React.Fragment>
        )) : (
          <div className="neu-sidebar__empty">{t('sidebar.noResults')}</div>
        )}
      </div>
    </aside>
  );
}

Object.assign(window, { Icon, Header, Footer, LangSelector, UnitsSelector, TemperatureSelector, Sidebar, ResortCard, ASSETS, loadResorts });
