// News feed — source-limited football headlines grouped by day.
const { useEffect: useEffectNews, useMemo: useMemoNews, useState: useStateNews } = React;

const NEWS_RSS_JSON = 'https://api.rss2json.com/v1/api.json?rss_url=';
const NEWS_SOURCES = [
  {
    id: 'bbc',
    name: 'BBC Sport Football',
    type: 'rss',
    url: 'https://feeds.bbci.co.uk/sport/football/rss.xml',
    allowedHosts: ['www.bbc.co.uk', 'www.bbc.com', 'feeds.bbci.co.uk'],
  },
  {
    id: 'guardian',
    name: 'Guardian Football',
    type: 'rss',
    url: 'https://www.theguardian.com/football/rss',
    allowedHosts: ['www.theguardian.com', 'theguardian.com'],
  },
  {
    id: 'espn',
    name: 'ESPN Soccer',
    type: 'rss',
    url: 'https://www.espn.com/espn/rss/soccer/news',
    allowedHosts: ['www.espn.com', 'espn.com'],
  },
];

function newsText(node) {
  return (node?.textContent || '').replace(/\s+/g, ' ').trim();
}

function decodeNewsText(value) {
  const text = (value || '').replace(/\s+/g, ' ').trim();
  if (!text) return '';
  const textarea = document.createElement('textarea');
  textarea.innerHTML = text;
  return textarea.value;
}

function newsAbsUrl(href, base) {
  try {
    return new URL(href, base).href;
  } catch (e) {
    return null;
  }
}

function newsAllowed(url, source) {
  try {
    const host = new URL(url).hostname.replace(/^m\./, 'www.');
    return source.allowedHosts.includes(host);
  } catch (e) {
    return false;
  }
}

function newsDate(value) {
  const d = new Date(value);
  return Number.isFinite(d.getTime()) ? d : null;
}

function fetchWithTimeout(url, timeoutMs = 6500) {
  const controller = new AbortController();
  const timer = window.setTimeout(() => controller.abort(), timeoutMs);
  return fetch(url, { signal: controller.signal }).finally(() => window.clearTimeout(timer));
}

function fetchRssJson(source) {
  return fetchWithTimeout(`${NEWS_RSS_JSON}${encodeURIComponent(source.url)}`).then(res => {
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  }).then(data => {
    if (data.status !== 'ok' || !Array.isArray(data.items)) throw new Error(data.message || 'RSS unavailable');
    return data.items.map(item => {
      const title = decodeNewsText(item.title);
      const link = newsAbsUrl(item.link || item.guid, source.url);
      const date = newsDate(item.pubDate || item.isoDate);
      if (!title || !link || !date || !newsAllowed(link, source)) return null;
      return {
        id: `${source.id}:${link}`,
        sourceId: source.id,
        source: source.name,
        title,
        link,
        date,
      };
    }).filter(Boolean);
  });
}

function formatNewsDay(date) {
  return new Intl.DateTimeFormat('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }).format(date);
}

function formatNewsTime(date) {
  return new Intl.DateTimeFormat('en-GB', { hour: '2-digit', minute: '2-digit' }).format(date);
}

function NewsView() {
  const [state, setState] = useStateNews({ status: 'loading', items: [], errors: [] });
  const [sourceFilter, setSourceFilter] = useStateNews('all');

  useEffectNews(() => {
    let alive = true;
    setState({ status: 'loading', items: [], errors: [] });
    Promise.allSettled(NEWS_SOURCES.map(source =>
      fetchRssJson(source).then(items => ({ source, items }))
    )).then(results => {
      if (!alive) return;
      const items = [];
      const errors = [];
      results.forEach((result, index) => {
        const source = NEWS_SOURCES[index];
        if (result.status === 'rejected') {
          errors.push(`${source.name}: unavailable`);
          return;
        }
        items.push(...result.value.items);
        if (result.value.items.length === 0) errors.push(`${source.name}: no timestamped items found`);
      });
      const deduped = Array.from(new Map(items.map(item => [item.link, item])).values())
        .sort((a, b) => b.date - a.date)
        .slice(0, 80);
      setState({ status: 'ready', items: deduped, errors });
    }).catch(err => {
      if (alive) setState({ status: 'error', items: [], errors: [err.message || 'Unable to load news'] });
    });
    return () => { alive = false; };
  }, []);

  const visibleItems = useMemoNews(() => (
    sourceFilter === 'all' ? state.items : state.items.filter(item => item.sourceId === sourceFilter)
  ), [state.items, sourceFilter]);

  const groups = useMemoNews(() => {
    const out = {};
    visibleItems.forEach(item => {
      const key = item.date.toISOString().slice(0, 10);
      if (!out[key]) out[key] = { date: item.date, items: [] };
      out[key].items.push(item);
    });
    return Object.values(out).sort((a, b) => b.date - a.date);
  }, [visibleItems]);

  return (
    <div className="news-view">
      <div className="news-head">
        <div>
          <div className="news-kicker">News feed</div>
          <h1>Football headlines</h1>
        </div>
        <div className="news-source-list">
          <button className={sourceFilter === 'all' ? 'active' : ''} onClick={() => setSourceFilter('all')}>All</button>
          {NEWS_SOURCES.map(source => (
            <button
              key={source.id}
              className={sourceFilter === source.id ? 'active' : ''}
              onClick={() => setSourceFilter(source.id)}
            >
              {source.name}
            </button>
          ))}
        </div>
      </div>

      {state.status === 'loading' && <div className="news-empty">Loading latest articles...</div>}
      {state.status === 'error' && <div className="news-empty">Unable to load news.</div>}

      {state.status === 'ready' && (
        <>
          {state.errors.length > 0 && (
            <div className="news-status">
              {state.errors.map(error => <span key={error}>{error}</span>)}
            </div>
          )}
          {groups.length === 0 && <div className="news-empty">No articles available from the approved sources.</div>}
          {groups.map(group => (
            <section key={group.date.toISOString()} className="news-day">
              <div className="news-day-title">{formatNewsDay(group.date)}</div>
              <div className="news-list">
                {group.items.map(item => (
                  <article key={item.id} className="news-item">
                    <time>{formatNewsTime(item.date)}</time>
                    <span className="news-source">{item.source}</span>
                    <a href={item.link} target="_blank" rel="noopener noreferrer">{item.title}</a>
                  </article>
                ))}
              </div>
            </section>
          ))}
        </>
      )}
    </div>
  );
}

window.NewsView = NewsView;
