import { useEffect, useRef, useState } from 'react';
import { Pencil } from 'lucide-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 { TextEditOverlay } from '@/features/particles/text-edit-overlay';
import { RelativeTimestamp } from '@/components/relative-timestamp';
import { useAuthStore } from '@/stores/auth-store';
import { MarkdownEditor } from '@/features/compose/markdown-editor';

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,
  );
}

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 userId = useAuthStore((s) => s.user?.id);
  const isCreator = !!userId && userId === particle.created_by_human_id;
  const [isEditing, setIsEditing] = useState(false);

  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() === '';

  const editButton = isCreator && !isEditing && (
    <button
      type="button"
      onMouseDown={(e) => e.stopPropagation()}
      onClick={(e) => {
        e.stopPropagation();
        setIsEditing(true);
      }}
      title="Edit"
      className="absolute bottom-[calc(var(--stream-safe-bottom,2rem)+0.5rem)] left-1/2 -translate-x-1/2 z-30 flex items-center gap-1.5 rounded-full bg-black/40 px-3 py-1.5 text-xs text-white/70 backdrop-blur-sm transition-colors hover:bg-black/60 hover:text-white"
    >
      <Pencil className="size-3.5" />
      Edit
    </button>
  );

  const editedLabel = particle.properties.edited_at && (
    <span className="text-xs text-white/40">
      edited <RelativeTimestamp date={particle.properties.edited_at} />
    </span>
  );

  const editOverlay = isEditing && (
    <TextEditOverlay
      particle={particle}
      streamPath={streamPath}
      onClose={() => setIsEditing(false)}
    />
  );

  // Mode 1: bare URLs only — show link cards centered
  if (linksOnly && !hasAttachments) {
    return (
      <div className="group relative flex h-full w-full items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 px-8 pt-[var(--stream-safe-top,2rem)] pb-[var(--stream-safe-bottom,2rem)]">
        <LinkPreviews entries={linkPreviews} />
        {editedLabel && (
          <div className="absolute bottom-6 left-1/2 -translate-x-1/2">
            {editedLabel}
          </div>
        )}
        {editButton}
        {editOverlay}
      </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="group relative flex h-full w-full flex-col items-center justify-center gap-4 bg-gradient-to-b from-black/40 via-black/20 to-black/40 px-8 pt-[var(--stream-safe-top,2rem)] pb-[var(--stream-safe-bottom,2rem)]">
        <p
          className={cn(
            'max-w-2xl break-words text-center leading-relaxed text-white select-text cursor-text',
            style.size,
            style.weight,
          )}
        >
          {content}
        </p>
        {editedLabel}
        {editButton}
        {editOverlay}
      </div>
    );
  }

  // Mode 3: card layout
  return (
    <div className="group relative flex h-full w-full items-center justify-center bg-gradient-to-b from-black/40 via-black/20 to-black/40 px-8 pt-[var(--stream-safe-top,2rem)] pb-[var(--stream-safe-bottom,2rem)]">
      <div
        className={cn(
          'flex max-h-full w-full max-w-2xl flex-col gap-4 overflow-y-auto overscroll-contain rounded bg-white/10 p-6 backdrop-blur-md',
          '[&::-webkit-scrollbar]:w-2',
          '[&::-webkit-scrollbar]:p-2',
          '[&::-webkit-scrollbar-track]:bg-transparent',
          '[&::-webkit-scrollbar-thumb]:rounded-full',
          '[&::-webkit-scrollbar-thumb]:bg-white/30',
          '[&::-webkit-scrollbar-thumb]:hover:bg-white/50',
        )}
      >
        <MarkdownEditor
          key={content}
          value={content}
          readOnly
          className="select-text pb-3"
        />

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

        {hasAttachments && <ParticleAttachments attachments={attachments} />}

        {editedLabel}
      </div>
      {editButton}
      {editOverlay}
    </div>
  );
}
