import {
  AlertCircle,
  CheckCircle2,
  Forward,
  Hash,
  Image as ImageIcon,
  MessageCircle,
  Pencil,
  Reply,
  RotateCw,
  Smile,
  Trash2,
  Video,
} from "lucide-react";
import { Fragment, useEffect, useMemo, useState } from "react";
import type { MessageRecord } from "../../../entities/message/types.js";
import { parseMetadata } from "../../../shared/lib/utils.js";
import { getMessageById } from "../../../shared/api/client.js";
import { Badge, Button, Skeleton, StatusBadge } from "../../../shared/ui";

const CUSTOM_EMOJI_REGEX = /<(a)?:([a-zA-Z0-9_]+):(\d+)>/g;

function renderContentWithCustomEmojis(content: string): React.ReactNode {
  const parts: React.ReactNode[] = [];
  const regex = new RegExp(CUSTOM_EMOJI_REGEX.source, "g");
  let lastIndex = 0;
  let match: RegExpExecArray | null;

  while ((match = regex.exec(content)) !== null) {
    if (match.index > lastIndex) {
      parts.push(content.slice(lastIndex, match.index));
    }
    const [, animated, name, id] = match;
    const ext = animated ? "gif" : "png";
    const url = `https://cdn.discordapp.com/emojis/${id}.${ext}?size=128`;
    parts.push(
      <img
        key={`${id}-${match.index}`}
        src={url}
        alt={name}
        className="inline-block h-[22px] w-[22px] align-middle object-contain"
        loading="lazy"
        draggable={false}
        title={`:${name}:`}
      />,
    );
    lastIndex = regex.lastIndex;
  }
  if (lastIndex < content.length) {
    parts.push(content.slice(lastIndex));
  }
  if (parts.length === 0) return content;
  return <Fragment>{parts}</Fragment>;
}

// ─── Props ───────────────────────────────────────────────────────────────────

interface MessageCardProps {
  messages: MessageRecord[];
  onReanalyze: (id: string) => Promise<void>;
}

// ─── Helpers ─────────────────────────────────────────────────────────────────

function parseStringList(value?: string | null): string[] {
  if (!value) return [];
  try {
    const parsed = JSON.parse(value) as unknown;
    return Array.isArray(parsed)
      ? parsed.filter((item): item is string => typeof item === "string")
      : [];
  } catch {
    return value
      .split(",")
      .map((item) => item.trim())
      .filter(Boolean);
  }
}

function severityColor(severity: string) {
  switch (severity) {
    case "critical":
      return "bg-destructive-soft text-destructive border-destructive/20";
    case "high":
      return "bg-warning-soft text-warning border-warning/20";
    case "medium":
      return "bg-warning-soft text-warning border-warning/20";
    case "low":
      return "bg-info-soft text-info border-info/20";
    default:
      return "bg-muted text-muted-foreground border-border";
  }
}

function formatTimeAgo(ts: number): string {
  const seconds = Math.floor((Date.now() - ts) / 1000);
  if (seconds < 60) return `${seconds}s ago`;
  if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
  if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
  return new Date(ts).toLocaleDateString();
}

function formatTime(ts: number): string {
  return new Date(ts).toLocaleTimeString([], {
    hour: "2-digit",
    minute: "2-digit",
  });
}

// ─── Single message row inside a group ───────────────────────────────────────

function MessageRow({
  message,
  onReanalyze,
}: {
  message: MessageRecord;
  onReanalyze: (id: string) => Promise<void>;
}) {
  const metadata = useMemo(
    () => parseMetadata(message.metadata),
    [message.metadata],
  );
  const displayContent = message.edited_content ?? message.content;
  const aiStatus = message.ai_status ?? "pending";
  const categories = useMemo(() => {
    const list = parseStringList(
      message.ai_categories ?? message.ai_moderation_flags,
    );
    return list.filter((c) => c !== "analysis_incomplete");
  }, [message.ai_categories, message.ai_moderation_flags]);
  const confidence =
    message.ai_confidence ?? message.ai_moderation_score ?? null;
  const [isReanalyzing, setIsReanalyzing] = useState(false);

  // ── Fetch referenced message content for replies if not in metadata ──
  const referenceMeta = metadata.reference;
  const [fetchedRefContent, setFetchedRefContent] = useState<{
    username: string;
    content: string;
  } | null>(null);

  useEffect(() => {
    if (
      message.is_reply &&
      referenceMeta?.messageId &&
      !referenceMeta?.content &&
      !message.deleted_at
    ) {
      getMessageById(referenceMeta.messageId)
        .then((refMsg) => {
          if (refMsg) {
            setFetchedRefContent({
              username: refMsg.username,
              content: refMsg.content,
            });
          }
        })
        .catch(() => {
          // Referenced message might not exist in our DB
        });
    }
  }, [message.is_reply, referenceMeta?.messageId, referenceMeta?.content, message.deleted_at]);

  const analysisSummary = useMemo(() => {
    const parts: string[] = [];
    if (categories.length > 0) {
      parts.push(categories.slice(0, 3).join(", "));
      if (categories.length > 3) parts.push(`+${categories.length - 3} more`);
    }
    if (message.ai_severity && message.ai_severity !== "none") {
      parts.push(message.ai_severity);
    }
    if (confidence != null) {
      parts.push(`${Math.round(confidence * 100)}% confidence`);
    }
    if (parts.length === 0) return "View AI analysis";
    return parts.join(" · ");
  }, [categories, message.ai_severity, confidence]);

  const stickers = metadata.stickers ?? [];
  const attachments = metadata.attachments ?? [];
  const imageAttachments = attachments.filter(
    (a) =>
      a.contentType?.startsWith("image/") ||
      /\.(png|jpe?g|gif|webp)$/i.test(a.name),
  );
  const videoAttachments = attachments.filter(
    (a) =>
      a.contentType?.startsWith("video/") ||
      /\.(mp4|webm|mov|mkv|avi)$/i.test(a.name),
  );
  const hasImages = imageAttachments.length > 0;
  const hasVideos = videoAttachments.length > 0;

  /** Hide the fallback text ("[Attachment: ...]", "[Sticker: ...]", "[Embed]") when the actual media IS already shown visually. */
  const isFallbackText =
    /^\[(Attachment|Sticker):/i.test(displayContent) ||
    /^\[Embed\]/i.test(displayContent);
  const shouldShowContent = displayContent && !isFallbackText;

  const handleReanalyze = async () => {
    setIsReanalyzing(true);
    try {
      await onReanalyze(message.id);
    } finally {
      setIsReanalyzing(false);
    }
  };

  // ── Reference context (reply / forward / crosspost) ─────────────────
  const renderReferenceIndicator = () => {
    // Use fetched content if metadata doesn't have it
    const effectiveRepliedUsername =
      referenceMeta?.repliedUsername ?? fetchedRefContent?.username ?? null;
    const effectiveRepliedContent =
      referenceMeta?.content ?? fetchedRefContent?.content ?? null;

    if (message.is_reply) {
      return (
        <div className="flex items-start gap-1.5 mb-2 text-[12px] text-muted-foreground/70 border-l-2 border-muted-foreground/20 pl-2.5 py-1 hover:border-primary/40 transition-colors">
          <Reply className="h-3 w-3 mt-0.5 shrink-0" />
          <span className="min-w-0">
            <span className="font-medium text-foreground/60">
              Replying to{" "}
              {effectiveRepliedUsername
                ? `@${effectiveRepliedUsername}`
                : "a message"}
            </span>
            {effectiveRepliedContent && (
              <span className="block truncate max-w-[400px] text-ellipsis text-[11px] text-muted-foreground/50 mt-0.5">
                {effectiveRepliedContent}
              </span>
            )}
          </span>
        </div>
      );
    }

    if (message.is_forward) {
      return (
        <div className="flex items-center gap-1.5 mb-2 text-[12px] text-muted-foreground/70 border-l-2 border-warning/40 pl-2.5 py-1">
          <Forward className="h-3 w-3 shrink-0 text-warning" />
          <span className="font-medium text-warning/70">Forwarded</span>
        </div>
      );
    }

    if (message.is_crosspost) {
      return (
        <div className="flex items-center gap-1.5 mb-2 text-[12px] text-muted-foreground/70 border-l-2 border-info/40 pl-2.5 py-1">
          <MessageCircle className="h-3 w-3 shrink-0 text-info" />
          <span className="font-medium text-info/70">Crossposted</span>
        </div>
      );
    }

    return null;
  };

  const referenceIndicator = renderReferenceIndicator();

  return (
    <div className="space-y-2">
      {/* Row header: time + edit/delete indicators + AI badges */}
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span
          className="text-[11px] text-muted-foreground/70"
          title={new Date(message.created_at).toLocaleString()}
        >
          {formatTime(message.created_at)}
        </span>
        {message.edited_at && (
          <span className="flex items-center gap-0.5 text-[11px] text-muted-foreground/70">
            <Pencil className="h-2.5 w-2.5" /> edited
          </span>
        )}
        {message.deleted_at && (
          <span className="flex items-center gap-0.5 text-[11px] text-destructive/70">
            <Trash2 className="h-2.5 w-2.5" /> deleted
          </span>
        )}
        <div className="ml-auto flex items-center gap-1">
          <StatusBadge status={aiStatus} className="text-[10px] px-1.5 py-0">
            {aiStatus === "clean" && <CheckCircle2 className="h-3 w-3" />}
            {aiStatus === "flagged" && <AlertCircle className="h-3 w-3" />}
            {aiStatus === "error" && <AlertCircle className="h-3 w-3" />}
          </StatusBadge>
          {message.ai_severity && message.ai_severity !== "none" && (
            <Badge
              className={`text-[10px] px-1.5 py-0 ${severityColor(message.ai_severity)}`}
            >
              {message.ai_severity}
            </Badge>
          )}
          {confidence != null && (
            <Badge
              variant="outline"
              className="text-[10px] px-1.5 py-0 tabular-nums"
            >
              {Math.round(confidence * 100)}%
            </Badge>
          )}
        </div>
      </div>

      {/* Reference context: reply / forward / crosspost */}
      {referenceIndicator}

      {/* Content — hidden when it's just an "[Attachment: ...]" fallback and the image is shown below */}
      {shouldShowContent ? (
        <p
          className={`whitespace-pre-wrap break-words text-sm leading-6 ${
            message.deleted_at
              ? "text-muted-foreground/60"
              : "text-foreground/90"
          }`}
        >
          {renderContentWithCustomEmojis(displayContent)}
        </p>
      ) : null}

      {/* Stickers */}
      {stickers.length > 0 && (
        <div className="flex flex-wrap gap-2">
          {stickers.map((sticker) => (
            <div
              key={sticker.name || sticker.url}
              className="flex items-center gap-1.5"
            >
              {sticker.url ? (
                <img
                  src={sticker.url}
                  alt={sticker.name || "sticker"}
                  className="h-12 w-12 rounded-lg border border-border object-contain bg-muted/50"
                  loading="lazy"
                />
              ) : (
                <div className="flex h-12 w-12 items-center justify-center rounded-lg border border-border bg-muted/50">
                  <Smile className="h-6 w-6 text-muted-foreground" />
                </div>
              )}
            </div>
          ))}
        </div>
      )}

      {/* Attached images */}
      {hasImages && (
        <div className="flex gap-2 overflow-x-auto">
          {imageAttachments.slice(0, 4).map((img) => (
            <a
              key={img.url}
              href={img.url}
              target="_blank"
              rel="noreferrer"
              className="shrink-0 overflow-hidden rounded-lg border border-border"
            >
              <img
                src={img.url}
                alt={img.name}
                className="h-16 w-16 object-cover transition-transform hover:scale-105"
                loading="lazy"
              />
            </a>
          ))}
          {imageAttachments.length > 4 && (
            <div className="flex h-16 w-16 items-center justify-center rounded-lg border border-border bg-muted text-[11px] text-muted-foreground">
              +{imageAttachments.length - 4}
              <ImageIcon className="ml-0.5 h-3 w-3" />
            </div>
          )}
        </div>
      )}

      {/* Attached videos */}
      {hasVideos && (
        <div className="flex gap-2 overflow-x-auto">
          {videoAttachments.slice(0, 4).map((vid) => (
            <video
              key={vid.url}
              src={vid.url}
              controls
              className="h-28 w-48 shrink-0 rounded-lg border border-border object-cover bg-black"
              preload="metadata"
            />
          ))}
          {videoAttachments.length > 4 && (
            <div className="flex h-28 w-16 items-center justify-center rounded-lg border border-border bg-muted text-[11px] text-muted-foreground">
              +{videoAttachments.length - 4}
              <Video className="ml-0.5 h-3 w-3" />
            </div>
          )}
        </div>
      )}

      {/* Categories */}
      {categories.length > 0 && (
        <div className="flex flex-wrap gap-1">
          {categories.map((category) => (
            <Badge key={category} variant="secondary" className="text-[10px]">
              {category}
            </Badge>
          ))}
        </div>
      )}

      {/* AI Analysis — always expanded */}
      {message.ai_analysis ? (
        <div
          className={`rounded-lg border-l-[3px] px-3 py-2 ${
            aiStatus === "flagged"
              ? "border-l-tertiary bg-tertiary/5"
              : "border-l-success bg-success-soft"
          }`}
        >
          <div className="flex items-start gap-2 text-[11px]">
            <span className="mt-0.5 shrink-0">
              {aiStatus === "flagged" ? "🚨" : "ℹ️"}
            </span>
            <div className="min-w-0 flex-1">
              <span className="block font-medium text-foreground/70 mb-1">
                {analysisSummary}
              </span>
              <div className="text-[12px] text-muted-foreground leading-relaxed whitespace-pre-wrap">
                {message.ai_analysis}
              </div>
            </div>
          </div>
        </div>
      ) : null}

      {/* AI Error */}
      {message.ai_error ? (
        <div className="rounded-lg bg-tertiary/5 px-3 py-2 text-[12px] text-tertiary">
          AI error: {message.ai_error}
        </div>
      ) : null}

      {/* Re-analyze button */}
      <div className="flex items-center gap-2">
        <Button
          size="sm"
          variant={aiStatus === "error" ? "destructive" : "outline"}
          onClick={handleReanalyze}
          disabled={aiStatus === "pending" || isReanalyzing}
          className="text-[11px] h-7 px-2.5"
        >
          <RotateCw
            className={`h-3 w-3 ${isReanalyzing ? "animate-spin" : ""}`}
          />
          {isReanalyzing ? "Reanalyzing..." : "Re-analyze"}
        </Button>
        {aiStatus === "error" && (
          <span className="text-[11px] text-tertiary/70">
            Click to retry analysis
          </span>
        )}
      </div>
    </div>
  );
}

// ─── Group card: one card per user group ─────────────────────────────────────

export function MessageCard({ messages, onReanalyze }: MessageCardProps) {
  const firstMsg = messages[0];
  const hasMultiple = messages.length > 1;
  const meta = useMemo(
    () => parseMetadata(firstMsg.metadata),
    [firstMsg.metadata],
  );
  const channelMeta = meta.channel;
  const locationLabel = useMemo(() => {
    if (channelMeta?.threadName) {
      return `# ${channelMeta.channelName || "unknown"} › ${channelMeta.threadName}`;
    }
    if (channelMeta?.channelName) {
      return `# ${channelMeta.channelName}`;
    }
    return null;
  }, [channelMeta]);

  return (
    <article
      className={`group rounded-xl border bg-card shadow-sm transition-all hover:border-primary/30 hover:shadow-md ${
        firstMsg.deleted_at ? "border-destructive/20 opacity-60" : "border-border"
      }`}
    >
      <div className="flex gap-3 p-4">
        {/* Avatar — only for first message */}
        <img
          src={
            firstMsg.avatar_url ??
            "https://cdn.discordapp.com/embed/avatars/0.png"
          }
          alt=""
          className="h-10 w-10 shrink-0 rounded-full object-cover ring-2 ring-primary/30"
        />

        <div className="min-w-0 flex-1">
          {/* Group header: username + location + timestamp */}
          <div className="flex items-baseline gap-2 mb-2">
            <span className="font-semibold text-sm text-foreground">
              {firstMsg.username || firstMsg.user_id}
            </span>
            {locationLabel && (
              <span className="flex items-center gap-1 text-[11px] text-muted-foreground/50 bg-muted/50 px-1.5 py-0.5 rounded-full">
                <Hash className="h-2.5 w-2.5" />
                {locationLabel}
              </span>
            )}
            <span
              className="text-[11px] text-muted-foreground/60"
              title={new Date(firstMsg.created_at).toLocaleString()}
            >
              {formatTimeAgo(firstMsg.created_at)}
              {hasMultiple && ` · ${messages.length} messages`}
            </span>
          </div>

          {/* Message rows — divided by separator when multiple */}
          <div
            className={
              hasMultiple ? "divide-y divide-border/30 space-y-2.5" : ""
            }
          >
            {messages.map((msg, idx) => (
              <div
                key={msg.id}
                className={hasMultiple && idx > 0 ? "pt-2.5" : ""}
              >
                <MessageRow message={msg} onReanalyze={onReanalyze} />
              </div>
            ))}
          </div>
        </div>
      </div>
    </article>
  );
}

// ─── Skeleton ────────────────────────────────────────────────────────────────

export function MessageCardSkeleton() {
  return (
    <article className="rounded-xl border border-border bg-card p-4 shadow-sm">
      <div className="flex gap-3">
        <Skeleton className="h-10 w-10 shrink-0 rounded-full" />
        <div className="min-w-0 flex-1 space-y-3">
          <Skeleton className="h-5 w-48" />
          <Skeleton className="h-4 w-full" />
          <Skeleton className="h-4 w-3/4" />
          <div className="flex gap-2">
            <Skeleton className="h-6 w-16 rounded-full" />
            <Skeleton className="h-6 w-20 rounded-full" />
          </div>
        </div>
      </div>
    </article>
  );
}
