import Link from "next/link";
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { MDXRemote } from "next-mdx-remote/rsc";
import remarkGfm from "remark-gfm";
import { Newsletter } from "../../components/forms/Newsletter";
import { getAdjacentPosts, getAllPosts, getPost } from "@/lib/devblog";
import { formatDate, readingTime } from "@/lib/format";
import { games } from "@/lib/games";
import { SITE_URL, LOGO_URL, STUDIO } from "@/lib/site";

type Props = { params: Promise<{ slug: string }> };

export function generateStaticParams() {
  return getAllPosts().map((p) => ({ slug: p.slug }));
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const post = getPost(slug);
  if (!post) return {};
  const url = `${SITE_URL}/devblog/${post.slug}`;
  return {
    title: post.title,
    description: post.excerpt,
    alternates: { canonical: url },
    openGraph: {
      type: "article",
      title: post.title,
      description: post.excerpt,
      url,
      publishedTime: post.date,
      authors: post.author ? [post.author] : undefined,
      tags: post.tags,
    },
    twitter: {
      card: "summary_large_image",
      title: post.title,
      description: post.excerpt,
    },
  };
}

const mdxComponents = {
  // The page title is already the document's h1. A `#` heading inside a post
  // renders as an h2 so there is never a second one.
  h1: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
    <h2
      {...props}
      className="mt-12 mb-6 font-display text-3xl tracking-wider first:mt-0 sm:text-4xl"
    />
  ),
  h2: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
    <h2 {...props} className="mt-12 mb-4 font-display text-3xl tracking-wider" />
  ),
  h3: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
    <h3 {...props} className="mt-8 mb-3 font-display text-2xl tracking-wider" />
  ),
  h4: (props: React.HTMLAttributes<HTMLHeadingElement>) => (
    <h4
      {...props}
      className="mt-8 mb-3 font-display text-xl tracking-wider text-foreground"
    />
  ),
  p: (props: React.HTMLAttributes<HTMLParagraphElement>) => (
    <p {...props} className="text-foreground-muted leading-relaxed mb-5" />
  ),
  ul: (props: React.HTMLAttributes<HTMLUListElement>) => (
    <ul
      {...props}
      className="text-foreground-muted leading-relaxed mb-5 ml-6 list-disc space-y-2"
    />
  ),
  ol: (props: React.HTMLAttributes<HTMLOListElement>) => (
    <ol
      {...props}
      className="text-foreground-muted leading-relaxed mb-5 ml-6 list-decimal space-y-2"
    />
  ),
  a: (props: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
    <a
      {...props}
      className="text-accent hover:text-foreground underline underline-offset-4 transition-colors"
    />
  ),
  strong: (props: React.HTMLAttributes<HTMLElement>) => (
    <strong {...props} className="text-foreground font-semibold" />
  ),
  blockquote: (props: React.HTMLAttributes<HTMLQuoteElement>) => (
    <blockquote
      {...props}
      className="border-l-2 border-accent pl-6 my-6 italic text-foreground"
    />
  ),
  // Inline code gets a pill; code inside a fence must not, or every block
  // paints a bordered chip on top of its own container. Fenced code is the
  // case that carries a `language-*` class.
  code: (props: React.HTMLAttributes<HTMLElement>) => {
    const fenced =
      typeof props.className === "string" &&
      props.className.includes("language-");

    return fenced ? (
      <code {...props} className="font-mono text-sm text-foreground" />
    ) : (
      <code
        {...props}
        className="rounded border border-border bg-surface-elevated px-1.5 py-0.5 text-sm text-accent"
      />
    );
  },
  pre: (props: React.HTMLAttributes<HTMLPreElement>) => (
    <pre
      {...props}
      className="my-6 overflow-x-auto rounded-2xl border border-border bg-surface-elevated p-5 text-sm"
    />
  ),
  // `remarkGfm` is enabled, so a post can contain a table. Without these it
  // rendered as unstyled browser-default HTML.
  table: (props: React.HTMLAttributes<HTMLTableElement>) => (
    <div className="my-6 overflow-x-auto">
      <table
        {...props}
        className="w-full border-collapse text-sm text-foreground-muted"
      />
    </div>
  ),
  th: (props: React.ThHTMLAttributes<HTMLTableCellElement>) => (
    <th
      {...props}
      className="border border-border bg-surface px-4 py-2 text-left font-display text-xs tracking-[0.2em] text-foreground"
    />
  ),
  td: (props: React.TdHTMLAttributes<HTMLTableCellElement>) => (
    <td {...props} className="border border-border px-4 py-2 align-top" />
  ),
  img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
    // Dimensions are unknown at author time, so this stays a plain <img>
    // rather than next/image. Lazy by default; it is always below the fold.
    // eslint-disable-next-line @next/next/no-img-element
    <img
      {...props}
      alt={props.alt ?? ""}
      loading="lazy"
      className="my-8 w-full rounded-2xl border border-border"
    />
  ),
  hr: () => <hr className="my-12 border-border" />,
};

export default async function DevblogPost({ params }: Props) {
  const { slug } = await params;
  const post = getPost(slug);
  if (!post) notFound();

  const { newer, older } = getAdjacentPosts(slug);
  const relatedGame = post.game
    ? games.find((entry) => entry.slug === post.game)
    : undefined;
  const minutes = readingTime(post.content);
  const url = `${SITE_URL}/devblog/${post.slug}`;
  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    headline: post.title,
    description: post.excerpt,
    datePublished: post.date,
    dateModified: post.date,
    author: {
      "@type": "Organization",
      name: post.author ?? STUDIO.name,
    },
    publisher: {
      "@type": "Organization",
      name: STUDIO.name,
      logo: {
        "@type": "ImageObject",
        url: LOGO_URL,
      },
    },
    mainEntityOfPage: { "@type": "WebPage", "@id": url },
    url,
    keywords: post.tags?.join(", "),
  };

  return (
    <article className="px-6 pb-24 pt-32 sm:pt-40 lg:px-10">
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
      />
      <div className="mx-auto max-w-3xl">
        <Link
          href="/devblog"
          className="group mb-12 inline-flex items-center gap-2 font-display text-xs tracking-widest text-foreground-muted transition-colors hover:text-accent"
        >
          <span
            aria-hidden
            className="inline-block transition-transform duration-300 ease-out group-hover:-translate-x-1"
          >
            ←
          </span>
          BACK TO DEVBLOG
        </Link>

        <header className="mb-16 border-b border-border pb-8">
          <div className="flex flex-wrap items-center gap-x-4 gap-y-2 font-display text-xs tracking-[0.3em] text-accent">
            <time dateTime={post.date}>
              {formatDate(post.date).toUpperCase()}
            </time>
            <span aria-hidden className="text-border">
              ·
            </span>
            <span className="text-foreground-muted">{minutes} MIN READ</span>
          </div>

          <h1 className="mt-4 mb-6 font-display text-4xl leading-[0.95] tracking-wider sm:text-5xl lg:text-6xl">
            {post.title.toUpperCase()}
          </h1>

          {post.excerpt && (
            <p className="text-lg leading-relaxed text-foreground-muted">
              {post.excerpt}
            </p>
          )}

          <div className="mt-8 flex flex-wrap items-center gap-x-6 gap-y-3">
            {post.author && (
              <p className="text-xs uppercase tracking-widest text-foreground-muted">
                By {post.author}
              </p>
            )}

            {/* The post declares a game in its frontmatter but the page never
                showed it, so a reader had no way back to what it is about. */}
            {relatedGame && (
              <Link
                href={`/games/${relatedGame.slug}`}
                className="border border-accent/40 px-2 py-1 text-[0.65rem] uppercase tracking-widest text-accent transition duration-200 ease-out hover:-translate-y-0.5 hover:border-accent hover:bg-accent hover:text-background active:scale-95"
              >
                {relatedGame.title}
              </Link>
            )}

            {post.tags && post.tags.length > 0 && (
              <ul className="flex flex-wrap gap-2" aria-label="Tags">
                {post.tags.map((tag) => (
                  <li
                    key={tag}
                    className="text-[0.65rem] uppercase tracking-widest text-foreground-muted"
                  >
                    #{tag}
                  </li>
                ))}
              </ul>
            )}
          </div>
        </header>

        <div>
          <MDXRemote
            source={post.content}
            components={mdxComponents}
            options={{
              mdxOptions: {
                remarkPlugins: [remarkGfm],
              },
            }}
          />
        </div>

        {(newer || older) && (
          <nav
            aria-label="Post navigation"
            className="mt-20 pt-10 border-t border-border grid sm:grid-cols-2 gap-6"
          >
            {newer ? (
              <Link
                href={`/devblog/${newer.slug}`}
                className="group block border border-border p-6 transition duration-300 ease-out hover:-translate-y-1 hover:border-accent"
              >
                <p className="mb-2 flex items-center gap-2 font-display text-xs tracking-[0.3em] text-foreground-muted transition-colors group-hover:text-accent">
                  <span
                    aria-hidden
                    className="inline-block transition-transform duration-300 ease-out group-hover:-translate-x-1"
                  >
                    ←
                  </span>
                  NEWER
                </p>
                <p className="font-display text-lg tracking-wider group-hover:text-accent transition-colors">
                  {newer.title.toUpperCase()}
                </p>
              </Link>
            ) : (
              <span aria-hidden />
            )}
            {older ? (
              <Link
                href={`/devblog/${older.slug}`}
                className="group block border border-border p-6 transition duration-300 ease-out hover:-translate-y-1 hover:border-accent sm:text-right"
              >
                <p className="mb-2 flex items-center gap-2 font-display text-xs tracking-[0.3em] text-foreground-muted transition-colors group-hover:text-accent sm:justify-end">
                  OLDER
                  <span
                    aria-hidden
                    className="inline-block transition-transform duration-300 ease-out group-hover:translate-x-1"
                  >
                    →
                  </span>
                </p>
                <p className="font-display text-lg tracking-wider group-hover:text-accent transition-colors">
                  {older.title.toUpperCase()}
                </p>
              </Link>
            ) : (
              <span aria-hidden />
            )}
          </nav>
        )}

        {/* A post used to end on its own navigation. This is the moment a
            reader is most likely to want the next one. */}
        <aside className="mt-16 rounded-2xl border border-border bg-surface p-8 lg:p-10">
          <h2 className="font-display text-2xl tracking-wider sm:text-3xl">
            GET THE NEXT ONE BY EMAIL
          </h2>
          <p className="mt-4 leading-relaxed text-foreground-muted">
            One mail per major update. No launch countdowns, no noise.
          </p>
          <div className="mt-8">
            <Newsletter variant="compact" />
          </div>
        </aside>
      </div>
    </article>
  );
}
