/* Eserler app — author × type filter, search, sort, list view, PDF link */

const PAGE_SIZE = 12;

const _STOP_WORDS_TR = new Set(['ve','veya','ile','ya','ki','hem','ne']);

function trTitleCase(text) {
  if (!text) return text;
  // Tokens with no lowercase letters are abbreviations (TTK, İİK, DASK…) — preserve
  const isAbbrev  = tok => !/[a-zçğışöü]/.test(tok);
  const trLower   = s   => s.replace(/İ/g,'i').replace(/I/g,'ı').toLowerCase();
  const trCapFirst = s  => {
    if (!s) return s;
    const h = s[0] === 'i' ? 'İ' : s[0] === 'ı' ? 'I' : s[0].toUpperCase();
    return h + s.slice(1);
  };

  // Use a Turkish-aware word regex; JS \W treats ı/ş/ğ/ü/ö/ç/İ as non-word
  // and would split "Sayılı" into ["Say","ı","l","ı"], producing "SayILI".
  let firstSeen = false;
  let result = text.replace(/[A-Za-z0-9çğıöşüÇĞİÖŞÜ]+/g, tok => {
    if (isAbbrev(tok)) { firstSeen = true; return tok; }
    const low = trLower(tok);
    const isFirst = !firstSeen;
    firstSeen = true;
    if (!isFirst && _STOP_WORDS_TR.has(low)) return low;
    return trCapFirst(low);
  });

  // Lowercase letters directly after apostrophes (Kanunu'Na → Kanunu'na)
  result = result.replace(/([''''])([A-ZÇĞÖŞÜ])/g,
    (_, apos, c) => apos + c.toLowerCase());
  result = result.replace(/([''''])İ/g, (_, apos) => apos + 'i');
  return result;
}

// Pagination range with ellipses: first 3, last 3, and current ±1.
function pageRange(current, total){
  if (total <= 7) return Array.from({length: total}, (_, i) => i + 1);
  const keep = new Set([1, 2, 3, total - 2, total - 1, total,
                        current - 1, current, current + 1]);
  const nums = [...keep].filter(n => n >= 1 && n <= total).sort((a,b) => a - b);
  const out = [];
  for (let i = 0; i < nums.length; i++){
    out.push(nums[i]);
    if (i < nums.length - 1 && nums[i+1] - nums[i] > 1) out.push('…');
  }
  return out;
}

function authorTitle(ids){
  if (ids.length === 1) return window.AUTHORS[ids[0]].name;
  return ids.map(id => window.AUTHORS[id].name).join(' & ');
}

function WorksApp(){
  const [activeAuthors, setActiveAuthors] = React.useState(new Set()); // empty = all
  const [activeTypes, setActiveTypes] = React.useState(new Set());
  const [onlyPdf, setOnlyPdf] = React.useState(false);
  const [search, setSearch] = React.useState('');
  const [sort, setSort] = React.useState('year-desc');
  const [page, setPage] = React.useState(1);
  const [isMobile, setIsMobile] = React.useState(
    typeof window !== 'undefined' && window.matchMedia
      ? window.matchMedia('(max-width: 600px)').matches : false);
  const listRef = React.useRef(null);
  const isInitial = React.useRef(true);

  React.useEffect(() => {
    const mq = window.matchMedia('(max-width: 600px)');
    const update = () => setIsMobile(mq.matches);
    mq.addEventListener('change', update);
    return () => mq.removeEventListener('change', update);
  }, []);

  const typeLabelOf = (t) => {
    if (!t) return '';
    const obj = isMobile && t.short ? t.short : t.label;
    return window.tn(obj) || window.tn(t.label) || t.id;
  };

  // Scroll the results list into view whenever the page changes
  // (skip on first mount so the page doesn't jump on load).
  React.useEffect(() => {
    if (isInitial.current){ isInitial.current = false; return; }
    const el = listRef.current;
    if (!el) return;
    const top = el.getBoundingClientRect().top + window.scrollY - 90;
    window.scrollTo({ top, behavior: 'smooth' });
  }, [page]);

  const toggle = (set, setter, value) => {
    const n = new Set(set);
    n.has(value) ? n.delete(value) : n.add(value);
    setter(n);
    setPage(1);
  };

  const clearAll = () => {
    setActiveAuthors(new Set());
    setActiveTypes(new Set());
    setOnlyPdf(false);
    setSearch('');
    setPage(1);
  };

  // Counts
  const counts = React.useMemo(() => {
    const byType = {};
    const byAuthor = {};
    window.WORKS.forEach(w => {
      byType[w.type] = (byType[w.type] || 0) + 1;
      w.authors.forEach(a => { byAuthor[a] = (byAuthor[a] || 0) + 1; });
    });
    return { byType, byAuthor };
  }, []);

  // Authors that actually have works (used to render filter buttons)
  const presentAuthors = React.useMemo(() =>
    Object.keys(window.AUTHORS).filter(id => (counts.byAuthor[id] || 0) > 0)
  , [counts]);

  // Faceted counts — each facet's numbers reflect the *other* active filters
  // (plus search) while ignoring its own selection, so the totals next to
  // "Yazar" and "Tür" update as the user narrows the list (e.g. selecting
  // M. Özekes shows his per-type breakdown instead of the global 252).
  const facetCounts = React.useMemo(() => {
    const s = search.trim().toLowerCase();
    const matchSearch = (w) => {
      if (!s) return true;
      const title = (typeof w.title === 'string' ? w.title : window.tn(w.title)) || '';
      const subtitle = (typeof w.subtitle === 'string' ? w.subtitle : window.tn(w.subtitle)) || '';
      return title.toLowerCase().includes(s) || subtitle.toLowerCase().includes(s);
    };
    const byType = {}, byAuthor = {};
    let typeTotal = 0, authorTotal = 0, pdfCount = 0;
    window.WORKS.forEach(w => {
      if (!matchSearch(w)) return;
      const okAuthor = activeAuthors.size === 0 || w.authors.some(a => activeAuthors.has(a));
      const okType   = activeTypes.size === 0 || activeTypes.has(w.type);
      const okPdf    = !onlyPdf || !!w.pdf;
      if (okAuthor && okPdf) { byType[w.type] = (byType[w.type] || 0) + 1; typeTotal++; }
      if (okType && okPdf)   { w.authors.forEach(a => { byAuthor[a] = (byAuthor[a] || 0) + 1; }); authorTotal++; }
      if (okAuthor && okType && w.pdf) pdfCount++;
    });
    return { byType, byAuthor, typeTotal, authorTotal, pdfCount };
  }, [activeAuthors, activeTypes, onlyPdf, search]);

  // Filter
  const filtered = React.useMemo(() => {
    let r = window.WORKS.slice();
    if (activeAuthors.size > 0){
      r = r.filter(w => w.authors.some(a => activeAuthors.has(a)));
    }
    if (activeTypes.size > 0){
      r = r.filter(w => activeTypes.has(w.type));
    }
    if (onlyPdf){
      r = r.filter(w => w.pdf);
    }
    if (search.trim()){
      const s = search.toLowerCase();
      r = r.filter(w => {
        const title = (typeof w.title === 'string' ? w.title : window.tn(w.title)) || '';
        const subtitle = (typeof w.subtitle === 'string' ? w.subtitle : window.tn(w.subtitle)) || '';
        return title.toLowerCase().includes(s) || subtitle.toLowerCase().includes(s);
      });
    }
    r.sort((a,b) => {
      switch(sort){
        case 'year-desc': return (b.year || 0) - (a.year || 0) || window.tn(a.title).localeCompare(window.tn(b.title), window.LANG || 'tr');
        case 'year-asc':  return (a.year || 9999) - (b.year || 9999) || window.tn(a.title).localeCompare(window.tn(b.title), window.LANG || 'tr');
        case 'title-asc': return window.tn(a.title).localeCompare(window.tn(b.title), window.LANG || 'tr');
        case 'type':      return a.type.localeCompare(b.type, 'tr') || window.tn(a.title).localeCompare(window.tn(b.title), window.LANG || 'tr');
        default: return 0;
      }
    });
    return r;
  }, [activeAuthors, activeTypes, onlyPdf, search, sort]);

  const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
  const safePage = Math.min(page, totalPages);
  const paged = filtered.slice((safePage-1)*PAGE_SIZE, safePage*PAGE_SIZE);

  return (
    <React.Fragment>
      {/* Filter sidebar */}
      <aside className="filters">
        <div className="filter-group">
          <h4>{window.t('filter.author')} <span className="count">{facetCounts.authorTotal}</span></h4>
          <div className="author-tabs">
            {Object.keys(window.AUTHORS).map(id => {
              const n = facetCounts.byAuthor[id] || 0;
              const disabled = n === 0;
              return (
                <button key={id}
                  disabled={disabled}
                  className={activeAuthors.has(id) ? 'active' : (disabled ? 'is-disabled' : '')}
                  onClick={disabled ? undefined : () => toggle(activeAuthors, setActiveAuthors, id)}
                  title={disabled ? window.t('filters.disabled-tip') : undefined}>
                  {window.AUTHORS[id].short} <span className="yr">{n} {window.t('count.publication')}</span>
                </button>
              );
            })}
          </div>
        </div>

        <div className="filter-group">
          <h4>{window.t('filter.type')} <span className="count">{facetCounts.typeTotal}</span></h4>
          {window.TYPES.map(t => {
            const tn = facetCounts.byType[t.id] || 0;
            return (
            <div key={t.id}
              className={'filter-row ' + (activeTypes.has(t.id) ? 'active' : '') + (tn === 0 && !activeTypes.has(t.id) ? ' is-empty' : '')}
              onClick={() => toggle(activeTypes, setActiveTypes, t.id)}>
              <span className="chk"></span>
              <span className="label">{window.tn(t.label)}</span>
              <span className="num">{tn}</span>
            </div>
            );
          })}
        </div>

        <div className="filter-group">
          <h4>{window.t('filter.file')} <span className="count">{facetCounts.pdfCount}</span></h4>
          <div className={'filter-row ' + (onlyPdf ? 'active' : '') + (facetCounts.pdfCount === 0 && !onlyPdf ? ' is-empty' : '')}
            onClick={() => { setOnlyPdf(v => !v); setPage(1); }}>
            <span className="chk"></span>
            <span className="label">{window.t('filter.has-pdf')}</span>
            <span className="num">{facetCounts.pdfCount}</span>
          </div>
        </div>

        <button className="clearbtn" onClick={clearAll}>
          {window.t('filters.clear')}
        </button>
      </aside>

      {/* Results */}
      <main>
        <div className="results-head">
          <div className="results-count">
            <strong>{filtered.length}</strong> <em>{window.t('count.publications')}</em>
            {activeAuthors.size === 1 && (
              <em style={{fontSize:18, marginLeft:12}}>
                · {window.AUTHORS[Array.from(activeAuthors)[0]].name}
              </em>
            )}
          </div>
          <div className="results-tools">
            <div className="search">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/>
              </svg>
              <input
                placeholder={window.t('search.title')}
                value={search}
                onChange={e=>{setSearch(e.target.value); setPage(1);}}
              />
            </div>
            <div className="sort">
              <span>{window.t('sort.label')}</span>
              <select value={sort} onChange={e=>setSort(e.target.value)}>
                <option value="title-asc">{window.t('sort.alpha')}</option>
                <option value="type">{window.t('sort.type')}</option>
                <option value="year-desc">{window.t('sort.year-desc')}</option>
                <option value="year-asc">{window.t('sort.year-asc')}</option>
              </select>
            </div>
          </div>
        </div>

        {/* Active chips */}
        {(activeAuthors.size > 0 || activeTypes.size > 0 || onlyPdf || search) && (
          <div className="active-chips">
            <span className="label">{window.t('filters.active')}</span>
            {onlyPdf && (
              <span className="chip" onClick={()=>{ setOnlyPdf(false); setPage(1); }}>
                {window.t('filter.has-pdf')} <span className="x">×</span>
              </span>
            )}
            {Array.from(activeAuthors).map(a => (
              <span key={a} className="chip" onClick={()=>toggle(activeAuthors, setActiveAuthors, a)}>
                {window.AUTHORS[a].name} <span className="x">×</span>
              </span>
            ))}
            {Array.from(activeTypes).map(t => (
              <span key={t} className="chip" onClick={()=>toggle(activeTypes, setActiveTypes, t)}>
                {typeLabelOf(window.TYPES.find(x=>x.id===t))} <span className="x">×</span>
              </span>
            ))}
            {search && (
              <span className="chip" onClick={()=>setSearch('')}>
                "{search}" <span className="x">×</span>
              </span>
            )}
          </div>
        )}

        {/* List */}
        <div className="works-list" ref={listRef}>
          {paged.map((w, i) => {
            const typeLabel = typeLabelOf(window.TYPES.find(t => t.id === w.type)) || w.type;
            return (
              <a
                href={w.pdf ? '/' + encodeURI(w.pdf) : undefined}
                target={w.pdf ? '_blank' : undefined}
                rel={w.pdf ? 'noopener noreferrer' : undefined}
                key={w.id}
                className={'work-row' + (w.pdf ? '' : ' no-file')}>
                <span className="num">{String((safePage-1)*PAGE_SIZE + i + 1).padStart(3, '0')}</span>
                <span className="type">{typeLabel}</span>
                <span className="title">
                  {trTitleCase(window.tn(w.title))}{w.subtitle && <em> — {trTitleCase(window.tn(w.subtitle))}</em>}
                  {w.pdf && (
                    <span className="pdf-tag" aria-label="PDF dosyası açılır" title="Tıklayınca PDF açılır">
                      <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                           strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                        <polyline points="14 2 14 8 20 8"/>
                      </svg>
                      PDF
                    </span>
                  )}
                </span>
                <span className="author">{authorTitle(w.authors)}</span>
                <span className="year">{w.year || '—'}</span>
                <span className="arr">{w.pdf ? '↗' : ''}</span>
              </a>
            );
          })}
        </div>

        {filtered.length === 0 && (
          <div style={{padding:'80px 0', textAlign:'center'}}>
            <p style={{fontFamily:'var(--serif)', fontSize:28, color:'var(--ink-mute)', fontStyle:'italic', margin:0}}>
              {window.t('empty.works')}
            </p>
            <button className="clearbtn" style={{maxWidth:240, margin:'24px auto 0'}} onClick={clearAll}>
              {window.t('filters.clear-short')}
            </button>
          </div>
        )}

        {/* Pagination */}
        {filtered.length > PAGE_SIZE && (
          <div className="pagination">
            <button className="clearbtn" style={{width:'auto', padding:'10px 18px'}}
              disabled={safePage===1}
              onClick={()=>setPage(p=>Math.max(1, p-1))}>
              {window.t('page.prev')}
            </button>
            <div className="page-numbers">
              {pageRange(safePage, totalPages).map((n, i) => (
                n === '…'
                  ? <span key={'e'+i} className="ellipsis">…</span>
                  : <button key={n} className={n===safePage ? 'active' : ''} onClick={()=>setPage(n)}>{n}</button>
              ))}
            </div>
            <button className="clearbtn" style={{width:'auto', padding:'10px 18px'}}
              disabled={safePage===totalPages}
              onClick={()=>setPage(p=>Math.min(totalPages, p+1))}>
              {window.t('page.next')}
            </button>
          </div>
        )}
      </main>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById('works-app')).render(<WorksApp />);
