/* @jsx React.createElement */
/* Insights — the index and the post shell. Global functions, like the other
   .jsx files: no import, no export. Loaded after SiteShell.jsx.

   The index reads /insights/series.json, then one index.json per series.
   A post page reads ./post.json and ./body.html from its own folder. See
   README "Insights" for the folder contract. */

const INSIGHTS_PATH = '/insights/';

function formatPostDate(iso) {
  const [y, m, d] = String(iso || '').split('-').map(Number);
  if (!y || !m || !d) return iso || '';
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  return `${d} ${months[m - 1]} ${y}`;
}

function fetchJson(url) {
  return fetch(url, { cache: 'no-cache' }).then((r) => {
    if (!r.ok) throw new Error(`${url}: ${r.status}`);
    return r.json();
  });
}

/* Every series with its posts, newest first. status: loading | ready | error */
function useInsights() {
  const [state, setState] = React.useState({ status: 'loading', series: [] });
  React.useEffect(() => {
    let live = true;
    fetchJson(INSIGHTS_PATH + 'series.json')
      .then((series) => Promise.all(series.map((s) =>
        fetchJson(`${INSIGHTS_PATH}${s.key}/index.json`)
          .then((idx) => ({ ...s, posts: sortPosts(idx.posts || []) }))
          .catch(() => ({ ...s, posts: [], failed: true })))))
      .then((series) => live && setState({ status: 'ready', series }))
      .catch(() => live && setState({ status: 'error', series: [] }));
    return () => { live = false; };
  }, []);
  return state;
}

function sortPosts(posts) {
  return posts.slice().sort((a, b) => (a.date < b.date ? 1 : a.date > b.date ? -1 : 0));
}

function PostRow({ post, seriesName }) {
  return (
    <a className="post-row" href={post.path}>
      <div className="post-when">
        <span className="series-tag">{seriesName}</span>
        <time dateTime={post.date}>{formatPostDate(post.date)}</time>
      </div>
      <div>
        <h3 className="post-title">{post.title}</h3>
        {post.dek ? <p className="post-dek">{post.dek}</p> : null}
        {post.pdf ? <span className="post-pdf">PDF available</span> : null}
      </div>
    </a>
  );
}

function SeriesSection({ series, num, status }) {
  return (
    <section className="series" id={series.key}>
      <div className="wrap">
        <div className="eyebrow"><span className="num">{num}</span><span className="am">&middot;</span>{series.key}</div>
        <div className="series-head">
          <h2>{series.name}</h2>
          <p className="blurb">{series.blurb}</p>
        </div>
        <div className="posts">
          {series.posts.map((p) => <PostRow key={p.slug} post={p} seriesName={series.name} />)}
          {series.posts.length === 0 && (
            <p className="posts-empty">
              {status === 'loading' ? 'Loading…'
                : series.failed ? 'This list could not be loaded.'
                : <>First post coming. Follow the <a href="/insights/feed.xml">RSS feed</a> to get it.</>}
            </p>
          )}
        </div>
      </div>
    </section>
  );
}

/* The brief-request block. insights/brief.js builds it; this just gives it a
   place to render inside a React page. */
function BriefRequest() {
  const ref = React.useRef(null);
  React.useEffect(() => { window.renderBriefRequest(ref.current); }, []);
  return <section className="brief" id="brief" ref={ref}></section>;
}

/* A post folder's page: hero from ./post.json, body from ./body.html. */
function PostPage() {
  const base = location.pathname.endsWith('/') ? location.pathname : location.pathname + '/';
  const [post, setPost] = React.useState(null);
  const [body, setBody] = React.useState({ status: 'loading', html: '' });

  React.useEffect(() => {
    fetchJson(base + 'post.json').then(setPost).catch(() => setPost({ failed: true }));
    fetch(base + 'body.html', { cache: 'no-cache' })
      .then((r) => { if (!r.ok) throw new Error(r.status); return r.text(); })
      .then((html) => setBody({ status: 'ready', html }))
      .catch(() => setBody({ status: 'error', html: '' }));
  }, []);

  const seriesName = post && post.series ? post.series.charAt(0).toUpperCase() + post.series.slice(1) : '';

  return (
    <SiteShell active="insights">
      <header className="article-hero">
        <div className="grid" aria-hidden="true"></div>
        <div className="wrap inner">
          {post && !post.failed ? (
            <>
              <p className="crumbs">
                <span className="idx">{seriesName}</span><span className="sep">/</span>
                <time dateTime={post.date}>{formatPostDate(post.date)}</time>
              </p>
              <h1>{post.title}</h1>
              {post.dek ? <p className="dek">{post.dek}</p> : null}
              <div className="article-meta">
                <a href="/insights">All posts</a>
                {post.pdf ? <><span>&middot;</span><a href={post.pdf}>Download the PDF</a></> : null}
              </div>
            </>
          ) : (
            <p className="post-status">{post && post.failed ? 'This post could not be loaded.' : 'Loading…'}</p>
          )}
        </div>
      </header>
      <main className="article post">
        {body.status === 'ready'
          ? <div className="prose-wrap" dangerouslySetInnerHTML={{ __html: body.html }} />
          : <div className="prose-wrap"><p className="post-status">
              {body.status === 'error' ? <>This post could not be loaded. <a href="/insights">All posts</a></> : 'Loading…'}
            </p></div>}
      </main>
      <BriefRequest />
    </SiteShell>
  );
}

window.useInsights = useInsights;
window.SeriesSection = SeriesSection;
window.BriefRequest = BriefRequest;
window.PostPage = PostPage;
