"use client";

import { useMemo } from "react";
import { Badge } from "@/shared/components/ui/badge";
import type { RegistryEntry } from "../types";
import { cn } from "@/shared/lib/utils";

// ── Types ──

interface FlowNode {
  entry: RegistryEntry;
  /** Direct thread children (replied via "Inchide") */
  threadChildren: FlowNode[];
  /** Linked/conex entries (not part of thread chain) */
  linkedEntries: RegistryEntry[];
}

export interface FlowDiagramProps {
  /** The chain of entries (thread root + descendants), chronologically ordered */
  chain: RegistryEntry[];
  /** All entries in the system (for resolving linkedEntryIds) */
  allEntries: RegistryEntry[];
  /** Highlight this entry (current selection in detail panel) */
  highlightEntryId?: string;
  /** Compact mode for detail panel (smaller nodes) */
  compact?: boolean;
  /** Click handler for a node */
  onNodeClick?: (entry: RegistryEntry) => void;
  /** Max nodes to show (for compact mode) */
  maxNodes?: number;
}

// ── Build tree from flat chain ──

function buildFlowTree(
  chain: RegistryEntry[],
  allEntries: RegistryEntry[],
): FlowNode | null {
  if (chain.length === 0) return null;

  // Find root (entry without threadParentId in the chain, or first entry)
  const chainIds = new Set(chain.map((e) => e.id));
  const root =
    chain.find((e) => !e.threadParentId || !chainIds.has(e.threadParentId)) ??
    chain[0];
  if (!root) return null;

  const entryMap = new Map(chain.map((e) => [e.id, e]));

  function buildNode(entry: RegistryEntry): FlowNode {
    // Thread children: entries whose threadParentId is this entry
    const threadChildren = chain
      .filter((e) => e.threadParentId === entry.id)
      .sort((a, b) => a.date.localeCompare(b.date))
      .map((child) => buildNode(child));

    // Linked entries: resolve linkedEntryIds that aren't in the thread chain
    const linkedEntries = (entry.linkedEntryIds ?? [])
      .filter((id) => !entryMap.has(id)) // exclude entries already in the chain
      .map((id) => allEntries.find((e) => e.id === id))
      .filter((e): e is RegistryEntry => !!e);

    return { entry, threadChildren, linkedEntries };
  }

  return buildNode(root);
}

// ── Flatten tree to a linear main chain + branches ──

interface FlattenedChain {
  mainChain: RegistryEntry[];
  branches: Map<string, RegistryEntry[]>; // parentId -> linked entries
}

function flattenTree(root: FlowNode): FlattenedChain {
  const mainChain: RegistryEntry[] = [];
  const branches = new Map<string, RegistryEntry[]>();

  function walkMain(node: FlowNode) {
    mainChain.push(node.entry);

    if (node.linkedEntries.length > 0) {
      branches.set(node.entry.id, node.linkedEntries);
    }

    // Follow the first thread child as "main" chain, others as branches
    if (node.threadChildren.length > 0) {
      walkMain(node.threadChildren[0]!);
      // Additional thread children treated as branches
      for (let i = 1; i < node.threadChildren.length; i++) {
        const child = node.threadChildren[i]!;
        const branchEntries = branches.get(node.entry.id) ?? [];
        branchEntries.push(child.entry);
        branches.set(node.entry.id, branchEntries);
      }
    }
  }

  walkMain(root);
  return { mainChain, branches };
}

// ── Component ──

export function FlowDiagram({
  chain,
  allEntries,
  highlightEntryId,
  compact = false,
  onNodeClick,
  maxNodes,
}: FlowDiagramProps) {
  const { mainChain, branches, truncated } = useMemo(() => {
    const tree = buildFlowTree(chain, allEntries);
    if (!tree) return { mainChain: [], branches: new Map(), truncated: 0 };

    const flat = flattenTree(tree);
    let mc = flat.mainChain;
    let trunc = 0;

    if (maxNodes && mc.length > maxNodes) {
      // Show entries around the highlighted one, or the last N
      if (highlightEntryId) {
        const idx = mc.findIndex((e) => e.id === highlightEntryId);
        if (idx >= 0) {
          const start = Math.max(0, idx - Math.floor(maxNodes / 2));
          const end = Math.min(mc.length, start + maxNodes);
          trunc = mc.length - (end - start);
          mc = mc.slice(start, end);
        } else {
          trunc = mc.length - maxNodes;
          mc = mc.slice(-maxNodes);
        }
      } else {
        trunc = mc.length - maxNodes;
        mc = mc.slice(-maxNodes);
      }
    }

    return { mainChain: mc, branches: flat.branches, truncated: trunc };
  }, [chain, allEntries, highlightEntryId, maxNodes]);

  if (mainChain.length === 0) {
    return (
      <p className="text-xs text-muted-foreground">Niciun document in lant.</p>
    );
  }

  return (
    <div className={cn("flex items-start gap-0 overflow-x-auto py-2", compact && "py-1")}>
      {truncated > 0 && (
        <div className="flex shrink-0 items-center self-center px-2">
          <span className="text-xs text-muted-foreground">
            +{truncated} ...
          </span>
          <Arrow />
        </div>
      )}

      {mainChain.map((entry, i) => {
        const branchEntries: RegistryEntry[] = branches.get(entry.id) ?? [];
        const isHighlighted = entry.id === highlightEntryId;
        const isLast = i === mainChain.length - 1;

        return (
          <div key={entry.id} className="flex shrink-0 items-start">
            <div className="flex flex-col items-center gap-1">
              {/* Main node */}
              <FlowNode
                entry={entry}
                isHighlighted={isHighlighted}
                compact={compact}
                onClick={() => onNodeClick?.(entry)}
              />
              {/* Branch entries below */}
              {branchEntries.length > 0 && (
                <div className="flex flex-col items-center gap-1">
                  <div className="h-3 w-px border-l border-dashed border-muted-foreground/40" />
                  {branchEntries.map((be) => (
                    <FlowNode
                      key={be.id}
                      entry={be}
                      isHighlighted={be.id === highlightEntryId}
                      compact={compact}
                      isBranch
                      onClick={() => onNodeClick?.(be)}
                    />
                  ))}
                </div>
              )}
            </div>
            {/* Arrow to next */}
            {!isLast && (
              <div className="flex items-center self-center">
                <Arrow />
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ── Arrow connector ──

function Arrow() {
  return (
    <div className="flex items-center px-1">
      <div className="h-px w-6 bg-border" />
      <div className="border-y-[4px] border-l-[6px] border-y-transparent border-l-border" />
    </div>
  );
}

// ── Single flow node ──

function FlowNode({
  entry,
  isHighlighted,
  compact,
  isBranch,
  onClick,
}: {
  entry: RegistryEntry;
  isHighlighted?: boolean;
  compact?: boolean;
  isBranch?: boolean;
  onClick?: () => void;
}) {
  const isIntrat = entry.direction === "intrat";
  const isOpen = entry.status === "deschis";
  const hasDeadlines = (entry.trackedDeadlines ?? []).some(
    (dl) => dl.resolution === "pending",
  );

  return (
    <button
      onClick={onClick}
      className={cn(
        "group relative flex flex-col rounded-lg border text-left transition-all hover:shadow-sm",
        compact ? "w-[130px] p-2" : "w-[160px] p-2.5",
        isHighlighted
          ? "border-primary ring-2 ring-primary/30"
          : "border-border hover:border-foreground/20",
        isBranch && "border-dashed",
      )}
    >
      {/* Direction bar */}
      <div
        className={cn(
          "absolute top-0 left-0 right-0 h-1 rounded-t-lg",
          isIntrat
            ? "bg-blue-500"
            : "bg-orange-500",
        )}
      />

      {/* Number */}
      <div className="mt-1 flex items-center gap-1.5">
        <span
          className={cn(
            "font-mono font-semibold",
            compact ? "text-[10px]" : "text-xs",
          )}
        >
          {entry.number}
        </span>
        {hasDeadlines && (
          <span className="h-1.5 w-1.5 rounded-full bg-amber-500" />
        )}
      </div>

      {/* Subject */}
      <p
        className={cn(
          "mt-1 text-muted-foreground",
          compact
            ? "line-clamp-1 text-[9px]"
            : "line-clamp-2 text-[10px] leading-tight",
        )}
      >
        {entry.subject || "—"}
      </p>

      {/* Date + status */}
      <div className="mt-1.5 flex items-center justify-between">
        <span className="text-[9px] text-muted-foreground">
          {formatShortDate(entry.date)}
        </span>
        <Badge
          variant="outline"
          className={cn(
            "h-4 px-1 text-[8px]",
            isOpen
              ? "border-green-300 text-green-700 dark:border-green-800 dark:text-green-400"
              : "border-muted text-muted-foreground",
          )}
        >
          {isOpen ? "Deschis" : "Inchis"}
        </Badge>
      </div>
    </button>
  );
}

function formatShortDate(iso: string): string {
  try {
    const d = new Date(iso);
    return `${String(d.getDate()).padStart(2, "0")}.${String(d.getMonth() + 1).padStart(2, "0")}.${d.getFullYear()}`;
  } catch {
    return iso;
  }
}
