---
/**
 * Chapter.astro — layout for a single chapter page.
 *
 * Wraps Base.astro with a chapter-specific structure:
 *   <article.prose>
 *     <ChapterHeader />     ← frontmatter metadata
 *     <ChapterTOC />        ← collapsed "On this page"
 *     <slot />              ← the rendered MDX body
 *     <ChapterNav />        ← prev / next
 *   </article.prose>
 *
 * Driven by a CollectionEntry<'chapters'> passed in Astro.props.entry
 * plus the `headings` array Astro's MDX renderer provides.
 *
 * v4.6.0: passes ogType="article" to Base + emits article:* meta tags via
 * Base's `<slot name="head" />`. Article tags read from chapter frontmatter
 * (`author`, `published`, `updated`, `tags`) with `author` falling back to
 * book-level `bookConfig.author`. `entry.data.image` (chapter-specific OG
 * image) is passed as `ogImage` for richer per-chapter social cards.
 */
import type { CollectionEntry } from 'astro:content';
import type { MarkdownHeading } from 'astro';
import Base from './Base.astro';
import bookConfig from 'virtual:book-scaffold/book-config';
import ChapterHeader from '../components/ChapterHeader.astro';
import ChapterTOC from '../components/ChapterTOC.astro';
import SectionMap from '../components/SectionMap.astro';
import ChapterNav from '../components/ChapterNav.astro';

interface Props {
  entry: CollectionEntry<'chapters'>;
  headings: MarkdownHeading[];
  /** v5.0.0 (#80): manifest identity derived from the entry id. */
  bookId?: string;
}
const { entry, headings, bookId } = Astro.props;

// v4.6.0: article:* meta-tag data. All fields are Zod-optional in the
// chapter schemas (academic / tools / course-notes / research-portfolio),
// so any of these may be undefined. `author` falls back to bookConfig.author
// (the top-level defineBookConfig field) so single-author books don't
// repeat themselves per chapter.
const articleAuthor =
  (entry.data as { author?: string }).author ??
  (bookId && bookConfig.corpus
    ? bookConfig.corpus.books.find((book) => book.id === bookId)?.author
    : undefined) ??
  bookConfig.author ??
  null;
const articlePublished = (entry.data as { published?: Date }).published;
const articleUpdated = (entry.data as { updated?: Date }).updated;
const articleTags = ((entry.data as { tags?: string[] }).tags ?? []) as string[];
const chapterImage = (entry.data as { image?: string }).image;

// (#section-map): best-effort context label for the gutter section map, e.g.
// "Part 2 · Ch 4" or "Week 1". All hierarchy fields are profile-dependent and
// Zod-optional (academic carries part+week; tools/research-portfolio carry
// part+chapter; minimal carries none), so each piece is included only when
// present — the label is omitted entirely (undefined) when nothing is derivable.
const dataAny = entry.data as {
  part?: string | number;
  chapter?: number;
  week?: number;
  layout?: 'default' | 'wide';
};

// 1d: per-page width knob. `layout` is Zod-optional on every profile schema
// (closed enum 'default'|'wide'). Emit `data-layout` ONLY for a non-default
// value so existing chapters (no `layout`, or `layout: default`) render the
// attribute-free <article> byte-identically — `undefined` makes Astro drop the
// attribute, and only `.prose[data-layout="wide"]` carries a rule in layout.css.
const layoutMode =
  dataAny.layout && dataAny.layout !== 'default' ? dataAny.layout : undefined;
const labelParts: string[] = [];
if (dataAny.part !== undefined && dataAny.part !== '') {
  // Numeric part → "Part N"; string-enum part (academic, e.g. "foundations")
  // → title-case it as-is.
  labelParts.push(
    typeof dataAny.part === 'number'
      ? `Part ${dataAny.part}`
      : dataAny.part.charAt(0).toUpperCase() + dataAny.part.slice(1),
  );
}
if (dataAny.chapter !== undefined) labelParts.push(`Ch ${dataAny.chapter}`);
else if (dataAny.week !== undefined) labelParts.push(`Week ${dataAny.week}`);
const sectionMapLabel = labelParts.length > 0 ? labelParts.join(' · ') : undefined;
---

<Base
  title={entry.data.title}
  description={entry.data.description}
  ogType="article"
  ogImage={chapterImage}
  bookId={bookId}
>
  <Fragment slot="head">
    {articleAuthor && <meta property="article:author" content={articleAuthor} />}
    {articlePublished && (
      <meta property="article:published_time" content={articlePublished.toISOString()} />
    )}
    {articleUpdated && (
      <meta property="article:modified_time" content={articleUpdated.toISOString()} />
    )}
    {articleTags.map((t) => <meta property="article:tag" content={t} />)}
  </Fragment>
  <article class="prose" data-layout={layoutMode}>
    <ChapterHeader data={entry.data} />
    <ChapterTOC headings={headings} />
    <SectionMap headings={headings} label={sectionMapLabel} />
    <slot />
    <ChapterNav currentId={entry.id} />
  </article>
</Base>
