import Link from "next/link";
import {
  Children,
  isValidElement,
  type ComponentPropsWithoutRef,
  type ReactNode,
} from "react";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { cn } from "~/lib/utils";

type CalloutVariant = "note" | "tip" | "warning";

const calloutStyles: Record<CalloutVariant, string> = {
  note: "border-sky-500/40 bg-sky-500/10 text-sky-950 dark:text-sky-100",
  tip: "border-emerald-500/40 bg-emerald-500/10 text-emerald-950 dark:text-emerald-100",
  warning: "border-amber-500/40 bg-amber-500/10 text-amber-950 dark:text-amber-100",
};

function Callout({
  title,
  variant = "note",
  children,
}: {
  title?: string;
  variant?: CalloutVariant;
  children: ReactNode;
}) {
  return (
    <aside className={cn("my-6 rounded-md border px-4 py-3", calloutStyles[variant])}>
      {title && <p className="mb-2 font-semibold">{title}</p>}
      <div className="[&>*:first-child]:mt-0 [&>*:last-child]:mb-0">{children}</div>
    </aside>
  );
}

function Lead({ children }: { children: ReactNode }) {
  return <span className="text-muted-foreground my-6 block text-lg leading-8">{children}</span>;
}

function TagList({ tags }: { tags: string[] }) {
  return (
    <div className="my-4 flex flex-wrap gap-1.5">
      {tags.map((tag) => (
        <Badge key={tag} variant="outline">
          {tag}
        </Badge>
      ))}
    </div>
  );
}

function ButtonLink({
  href,
  children,
  variant = "default",
}: {
  href: string;
  children: ReactNode;
  variant?: ComponentPropsWithoutRef<typeof Button>["variant"];
}) {
  const isExternal = /^https?:\/\//.test(href);

  return (
    <Button asChild variant={variant}>
      {isExternal ? (
        <a href={href} target="_blank" rel="noreferrer">
          {children}
        </a>
      ) : (
        <Link href={href}>{children}</Link>
      )}
    </Button>
  );
}

function Figure({
  src,
  alt,
  caption,
}: {
  src: string;
  alt: string;
  caption?: string;
}) {
  return (
    <figure className="my-8">
      <img src={src} alt={alt} className="w-full rounded-md border object-cover" />
      {caption && <figcaption className="text-muted-foreground mt-2 text-center text-sm">{caption}</figcaption>}
    </figure>
  );
}

// A bare markdown image (![alt](src)) fills the prose width. Pass a numeric
// markdown title — ![alt](src "160") — to render it as a fixed-size, circular
// avatar instead (used by the CV header). Untitled images keep the old look.
function Img({ src, alt, title }: { src: string; alt?: string; title?: string }) {
  const size = title && /^\d+$/.test(title) ? Number(title) : undefined;
  if (size) {
    return (
      <img
        src={src}
        alt={alt ?? ""}
        width={size}
        height={size}
        style={{ width: size, height: size }}
        className="mx-auto !my-0 shrink-0 rounded-full object-cover ring-2 ring-foreground/10"
      />
    );
  }
  return <img src={src} alt={alt ?? ""} className="w-full rounded-md border object-cover" />;
}

function PullQuote({ children }: { children: ReactNode }) {
  return (
    <blockquote className="border-primary my-8 border-l-4 pl-5 text-xl leading-8 font-medium">
      {children}
    </blockquote>
  );
}

function ExternalLink(props: ComponentPropsWithoutRef<"a">) {
  const href = props.href ?? "";
  const isExternal = /^https?:\/\//.test(href);

  if (!isExternal) return <a {...props} />;

  return <a {...props} target="_blank" rel="noreferrer" />;
}

const blockComponents = new Set<unknown>([Callout, Figure, PullQuote, TagList]);

function Paragraph({ children }: { children: ReactNode }) {
  const containsBlockComponent = Children.toArray(children).some(
    (child) => isValidElement(child) && blockComponents.has(child.type),
  );

  if (containsBlockComponent) return <>{children}</>;

  return <p>{children}</p>;
}

export const mdxComponents = {
  a: ExternalLink,
  p: Paragraph,
  Badge,
  ButtonLink,
  Callout,
  Figure,
  img: Img,
  Lead,
  PullQuote,
  TagList,
};
