import { cn } from "@/lib/utils";
import { applyMergeTags } from "@/lib/blocks/merge";
import { flattenBlocks, visibleContent, type Article, type PageContent, type Section } from "@/lib/blocks/layout";
import { BlockRenderer } from "./block-renderer";
import { InlineMarkup } from "./markup";
import { Reveal } from "./interactive";
import { SectionBackgroundLayer, borderStyle, isDarkBackground, needsClip } from "./section-style";
import type { RenderContext } from "./types";

const PAD = { none: "", sm: "py-4", md: "py-8", lg: "py-14" } as const;
const INNER = { narrow: "mx-auto w-full max-w-3xl", wide: "mx-auto w-full max-w-6xl", full: "" } as const;
const COLS = ["", "", "md:grid-cols-2", "md:grid-cols-3", "md:grid-cols-4"] as const;
const ARTICLE: Record<Article["style"], string> = {
  plain: "",
  boxed: "my-4 overflow-hidden rounded-xl bg-[var(--muted)]",
  bordered: "my-4 overflow-hidden rounded-xl border border-border",
  boxedBordered: "my-4 overflow-hidden rounded-xl border border-border bg-[var(--muted)]",
};

const TITLE_ALIGN = { left: "text-left", center: "text-center", right: "text-right", justify: "text-justify" } as const;

function Title({ level, children }: { level: 2 | 3; children: string }) {
  const am = /^::(left|center|right|justify)\s+/.exec(children);
  const text = am ? children.slice(am[0].length) : children;
  const cls = cn("site-heading mx-auto w-full max-w-6xl px-4 pt-6 text-2xl font-bold tracking-tight sm:px-6", am && TITLE_ALIGN[am[1] as keyof typeof TITLE_ALIGN]);
  return level === 2 ? <h2 className={cls}><InlineMarkup text={text} /></h2> : <h3 className={cn(cls, "text-xl")}><InlineMarkup text={text} /></h3>;
}

function SectionView({ section, ctx, firstBlockId }: { section: Section; ctx: RenderContext; firstBlockId: string | null }) {
  const title = applyMergeTags(section.title, ctx.vars);
  const bg = section.background;
  const dark = bg ? isDarkBackground(bg, ctx.palette) : false;
  const className = cn(
    section.marginTop && "mt-8", section.marginBottom && "mb-8", PAD[section.padding],
    section.width === "contained" && "mx-auto w-full max-w-6xl px-4 sm:px-6",
    needsClip(section) && "relative overflow-hidden isolate",
    dark && "site-on-dark",
  );
  const style = { ...(section.border ? borderStyle(section.border) : {}), ...(dark ? { color: "#fff" } : {}) };
  const content = (
    <>
      {bg ? <SectionBackgroundLayer bg={bg} ctx={ctx} /> : null}
      <div className={bg ? "relative" : undefined}>
        {section.showTitle && title ? <Title level={2}>{title}</Title> : null}
        <div className={cn(INNER[section.innerWidth], section.articles.length > 1 && cn("grid gap-6 px-4 sm:px-6", COLS[Math.min(section.articles.length, 4)]))}>
          {section.articles.map((a) => {
            const at = applyMergeTags(a.title, ctx.vars);
            return (
              <div key={a.id} className={ARTICLE[a.style]} data-article={a.id}>
                {a.showTitle && at ? <Title level={3}>{at}</Title> : null}
                <BlockRenderer blocks={a.blocks} ctx={ctx} firstOnPage={a.blocks[0]?.id === firstBlockId} />
              </div>
            );
          })}
        </div>
      </div>
    </>
  );
  return section.animation ? (
    <Reveal anim={section.animation} className={className} style={style} sectionId={section.id}>{content}</Reveal>
  ) : (
    <div className={className} style={style} data-section={section.id}>{content}</div>
  );
}

/** Renders sections → articles → blocks for visitors. `now` decides which publish windows are open. */
export function PageContentRenderer({ content, ctx, now = new Date(), ignoreWindows = false }: { content: PageContent; ctx: RenderContext; now?: Date; ignoreWindows?: boolean }) {
  const shown = visibleContent(content, now, { ignoreWindows });
  const firstBlockId = flattenBlocks(shown)[0]?.id ?? null;
  return (
    <>
      {shown.sections.map((s) => (
        <SectionView key={s.id} section={s} ctx={ctx} firstBlockId={firstBlockId} />
      ))}
    </>
  );
}

export function hasVisibleContent(content: PageContent, now = new Date()): boolean {
  return visibleContent(content, now).sections.length > 0;
}
