import { useEffect, useRef } from "react";
import type { Particle } from "@/api/types";
import type { ParticlePath } from "@/lib/particle-path";
import { cn } from "@/lib/utils";
import { useAllLinkMetadata, type LinkPreviewEntry } from "@/hooks/use-link-metadata";
import { extractUrls } from "@/lib/link-metadata";
import {
  LinkPreviewCard,
  LinkPreviewCardSkeleton,
} from "@/components/link-preview-card";
import { useParticleAttachments } from "@/hooks/use-particle-attachments";
import { ParticleAttachments } from "@/features/particles/particle-attachments";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import rehypeHighlight from "rehype-highlight";
import "highlight.js/styles/github-dark.css";

type TextParticle = Extract<Particle, { type: "text" }>;

interface TextParticleViewProps {
  particle: TextParticle;
  streamPath: ParticlePath;
  paused: boolean;
  onEnded: () => void;
  onProgress?: (ratio: number) => void;
}

// Characters per minute (~1000 cpm ≈ 200 wpm at ~5 chars/word)
const CHARS_PER_MINUTE = 1000;
const MIN_DURATION_S = 3;
const MAX_DURATION_S = 15;
const TICK_MS = 100;
const EXTRA_S_PER_LINK = 2;
const EXTRA_S_PER_ATTACHMENT = 2;

// Below this threshold: immersive centered display
const IMMERSIVE_CHAR_LIMIT = 120;

function computeReadDuration(
  text: string,
  linkCount: number,
  attachmentCount: number,
): number {
  const base = (text.length / CHARS_PER_MINUTE) * 60;
  const extra = linkCount * EXTRA_S_PER_LINK + attachmentCount * EXTRA_S_PER_ATTACHMENT;
  return Math.min(Math.max(base + extra, MIN_DURATION_S), MAX_DURATION_S);
}

function getImmersiveTextStyle(length: number) {
  if (length < 30) return { size: "text-5xl", weight: "font-semibold" };
  if (length < 70) return { size: "text-3xl", weight: "font-semibold" };
  return { size: "text-2xl", weight: "font-normal" };
}

function hasMarkdownFormatting(content: string): boolean {
  return /^#{1,6} |^\s*[-*+] |^\s*\d+\. |^```|`[^`]+`|\*\*|__|\*[^*]|_[^_]|^>/m.test(content);
}

const markdownComponents: React.ComponentProps<typeof ReactMarkdown>["components"] = {
  h1: ({ children }) => <h1 className="mb-3 text-3xl font-bold text-white">{children}</h1>,
  h2: ({ children }) => <h2 className="mb-2 text-2xl font-semibold text-white">{children}</h2>,
  h3: ({ children }) => <h3 className="mb-2 text-xl font-semibold text-white">{children}</h3>,
  h4: ({ children }) => <h4 className="mb-1 text-lg font-medium text-white">{children}</h4>,
  h5: ({ children }) => <h5 className="mb-1 text-base font-medium text-white">{children}</h5>,
  h6: ({ children }) => <h6 className="mb-1 text-sm font-medium text-white">{children}</h6>,
  p: ({ children }) => <p className="mb-3 leading-relaxed text-white last:mb-0">{children}</p>,
  strong: ({ children }) => <strong className="font-semibold text-white">{children}</strong>,
  em: ({ children }) => <em className="italic text-white">{children}</em>,
  a: ({ href, children }) => (
    <a href={href} className="text-blue-400 underline" target="_blank" rel="noreferrer">
      {children}
    </a>
  ),
  code: ({ className, children, ...props }) => {
    const isBlock = className?.startsWith("language-");
    if (isBlock) {
      return (
        <code className={cn(className, "text-sm")} {...props}>
          {children}
        </code>
      );
    }
    return (
      <code className="rounded bg-white/10 px-1.5 py-0.5 font-mono text-sm text-white" {...props}>
        {children}
      </code>
    );
  },
  pre: ({ children }) => (
    <pre className="mb-3 overflow-x-auto rounded-lg bg-black/40 p-4 text-sm last:mb-0">
      {children}
    </pre>
  ),
  ul: ({ children }) => <ul className="mb-3 list-disc pl-5 text-white last:mb-0">{children}</ul>,
  ol: ({ children }) => <ol className="mb-3 list-decimal pl-5 text-white last:mb-0">{children}</ol>,
  li: ({ children }) => <li className="mb-1 leading-relaxed">{children}</li>,
  blockquote: ({ children }) => (
    <blockquote className="mb-3 border-l-2 border-white/30 pl-4 italic text-white/70 last:mb-0">
      {children}
    </blockquote>
  ),
  hr: () => <hr className="my-4 border-white/10" />,
};

function MarkdownContent({ content, className }: { content: string; className?: string }) {
  return (
    <div className={cn("break-words overflow-hidden", className)}>
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        rehypePlugins={[rehypeHighlight]}
        components={markdownComponents}
      >
        {content}
      </ReactMarkdown>
    </div>
  );
}

function LinkPreviews({ entries }: { entries: LinkPreviewEntry[] }) {
  return (
    <div className="flex flex-wrap gap-3">
      {entries.map((entry) => (
        <div key={entry.url} className="shrink-0">
          {entry.isLoading ? (
            <LinkPreviewCardSkeleton />
          ) : entry.metadata ? (
            <LinkPreviewCard metadata={entry.metadata} />
          ) : null}
        </div>
      ))}
    </div>
  );
}

export function TextParticleView({
  particle,
  streamPath,
  paused,
  onEnded,
  onProgress,
}: TextParticleViewProps) {
  const content = particle.properties.content;
  const linkPreviews = useAllLinkMetadata(content);
  const { attachments } = useParticleAttachments(streamPath, particle.id);
  const urls = extractUrls(content);

  const hasLinks = urls.length > 0;
  const hasAttachments = attachments.length > 0;
  const hasEnrichments = hasLinks || hasAttachments;

  const durationS = computeReadDuration(content, urls.length, attachments.length);
  const elapsedRef = useRef(0);

  // Reset elapsed when particle changes
  useEffect(() => {
    elapsedRef.current = 0;
  }, [particle.id]);

  useEffect(() => {
    if (paused) return;

    const interval = setInterval(() => {
      elapsedRef.current += TICK_MS / 1000;
      const ratio = Math.min(elapsedRef.current / durationS, 1);
      onProgress?.(ratio);

      if (ratio >= 1) {
        clearInterval(interval);
        onEnded();
      }
    }, TICK_MS);

    return () => clearInterval(interval);
  }, [paused, durationS, onEnded, onProgress, particle.id]);

  // Content is just bare URLs with no surrounding text
  const contentTrimmed = content.trim();
  const linksOnly = hasLinks && urls.every((url) => contentTrimmed.includes(url)) &&
    contentTrimmed.replace(/https?:\/\/[^\s<>"')\]]+/g, "").trim() === "";

  // Mode 1: bare URLs only — show link cards centered
  if (linksOnly && !hasAttachments) {
    return (
      <div className="flex h-full w-full items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 p-8">
        <LinkPreviews entries={linkPreviews} />
      </div>
    );
  }

  // Mode 2: short plain text, no enrichments — immersive centered display
  if (content.length < IMMERSIVE_CHAR_LIMIT && !hasEnrichments && !hasMarkdownFormatting(content)) {
    const style = getImmersiveTextStyle(content.length);
    return (
      <div className="flex h-full w-full flex-col items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 p-8">
        <p
          className={cn(
            "max-w-2xl break-words text-center leading-relaxed text-white select-text cursor-text",
            style.size,
            style.weight,
          )}
        >
          {content}
        </p>
      </div>
    );
  }

  // Mode 3: card layout
  return (
    <div className="flex h-full w-full items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 p-8">
      <div className="flex max-h-full w-full max-w-2xl flex-col gap-4 overflow-y-auto rounded-2xl bg-white/10 p-5 backdrop-blur-md">
        <MarkdownContent content={content} className="break-words select-text cursor-text" />

        {hasLinks && <LinkPreviews entries={linkPreviews} />}

        {hasAttachments && <ParticleAttachments attachments={attachments} />}
      </div>
    </div>
  );
}
