import {
  type ChangeEvent,
  type FormEvent,
  type HTMLAttributes,
  type Ref,
} from "react";
import { Check, Loader2, Send, Wrench, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import {
  buildReasoningSteps,
  getToolTraceSummary,
  type AgentChatMessage,
  type AgentCitation,
  type AgentReasoningStep,
  type AgentSource,
  type AgentToolTrace,
} from "./agentChatModel";
export type { AgentChatMessage, AgentToolTrace } from "./agentChatModel";

type AgentConversationProps = HTMLAttributes<HTMLDivElement> & {
  messages: AgentChatMessage[];
  isSubmitting?: boolean;
  scrollRef?: Ref<HTMLDivElement>;
};

type AgentMessageProps = HTMLAttributes<HTMLDivElement> & {
  message: AgentChatMessage;
};

type AgentPromptInputProps = {
  value: string;
  placeholder: string;
  disabled: boolean;
  isSubmitting: boolean;
  onChange: (value: string) => void;
  onSubmit: (event: FormEvent<HTMLFormElement>) => void;
};

export type AgentActionPlanPreviewRow = {
  date?: string;
  description: string;
  amount?: number;
  currentCategoryName?: string;
  targetCategoryName?: string;
  action?: string;
};

export type AgentActionPlan = {
  _id: string;
  kind: "bulk_recategory" | "category_changes";
  summary: string;
  affectedCount: number;
  expiresAt: number;
  previewRows: AgentActionPlanPreviewRow[];
};

export function AgentConversation({
  messages,
  isSubmitting = false,
  scrollRef,
  className,
  ...props
}: AgentConversationProps) {
  return (
    <section
      aria-label="Chatverlauf"
      className={cn("h-[52vh] overflow-y-auto rounded-md border bg-background", className)}
      ref={scrollRef}
      {...props}
    >
      <div className="space-y-3 p-3">
        {messages.map((message) => (
          <AgentMessage key={message.id} message={message} />
        ))}
        {isSubmitting && <AgentThinkingIndicator />}
      </div>
    </section>
  );
}

export function AgentActionPlanList({
  plans,
  isApplying,
  onApply,
  onDismiss,
}: {
  plans: AgentActionPlan[];
  isApplying: boolean;
  onApply: (planId: string) => void;
  onDismiss: (planId: string) => void;
}) {
  if (plans.length === 0) return null;

  return (
    <section className="rounded-md border bg-card p-3" aria-label="Vorschläge zur Bestätigung">
      <div className="mb-3 flex items-center justify-between gap-3">
        <div>
          <p className="text-sm font-semibold">Vorschläge zur Bestätigung</p>
          <p className="text-xs text-muted-foreground">
            Änderungen werden erst nach deiner Bestätigung angewendet.
          </p>
        </div>
      </div>
      <div className="space-y-3">
        {plans.map((plan) => (
          <article className="rounded-md border bg-muted/20 p-3" key={plan._id}>
            <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
              <div className="min-w-0">
                <p className="text-sm font-medium">{plan.summary}</p>
                <p className="mt-1 text-xs text-muted-foreground">
                  {plan.affectedCount} {plan.affectedCount === 1 ? "Änderung" : "Änderungen"} · läuft ab{" "}
                  {formatActionPlanExpiry(plan.expiresAt)}
                </p>
              </div>
              <div className="flex shrink-0 gap-2">
                <Button
                  type="button"
                  size="sm"
                  onClick={() => onApply(plan._id)}
                  disabled={isApplying}
                >
                  {isApplying ? <Loader2 className="h-4 w-4 animate-spin" /> : <Check className="h-4 w-4" />}
                  Anwenden
                </Button>
                <Button
                  type="button"
                  size="sm"
                  variant="outline"
                  onClick={() => onDismiss(plan._id)}
                  disabled={isApplying}
                >
                  <X className="h-4 w-4" />
                  Verwerfen
                </Button>
              </div>
            </div>
            {plan.previewRows.length > 0 && (
              <div className="mt-3 overflow-hidden rounded-md border bg-background/80">
                {plan.previewRows.slice(0, 5).map((row, index) => (
                  <div
                    className="grid gap-1 border-b px-2 py-2 text-xs last:border-b-0 sm:grid-cols-[1fr_auto]"
                    key={`${plan._id}-${row.description}-${index}`}
                  >
                    <div className="min-w-0">
                      <p className="truncate font-medium text-foreground">
                        {row.date ? `${row.date} · ` : ""}
                        {row.description}
                      </p>
                      <p className="truncate text-muted-foreground">
                        {row.action ?? [row.currentCategoryName, row.targetCategoryName].filter(Boolean).join(" → ")}
                      </p>
                    </div>
                    {row.amount !== undefined && (
                      <p className="font-medium tabular-nums">{formatActionPlanAmount(row.amount)}</p>
                    )}
                  </div>
                ))}
              </div>
            )}
          </article>
        ))}
      </div>
    </section>
  );
}

export function AgentMessage({ message, className, ...props }: AgentMessageProps) {
  const isUser = message.role === "user";

  return (
    <article
      className={cn(
        "flex w-full",
        isUser ? "justify-end" : "justify-start",
        className,
      )}
      {...props}
    >
      <div
        className={cn(
          "max-w-[min(100%,46rem)] rounded-lg border px-3 py-2 text-sm",
          isUser ? "bg-muted/60" : "bg-card text-card-foreground",
        )}
      >
        <p className="text-[0.7rem] font-medium uppercase text-muted-foreground">
          {isUser ? "User" : "Assistant"}
        </p>
        <p className="mt-1 whitespace-pre-wrap leading-6">
          <MessageContentWithCitations
            content={message.content}
            citations={message.citations}
          />
        </p>
        {!isUser && message.toolTrace && message.toolTrace.length > 0 && (
          <AgentEvidencePanel sources={message.sources} toolTrace={message.toolTrace} />
        )}
        {!isUser && (!message.toolTrace || message.toolTrace.length === 0) && message.sources && message.sources.length > 0 && (
          <AgentSources sources={message.sources} />
        )}
      </div>
    </article>
  );
}

function MessageContentWithCitations({
  content,
  citations,
}: {
  content: string;
  citations?: AgentCitation[];
}) {
  if (!citations || citations.length === 0) return content;
  const citationByMarker = new Map(citations.map((citation) => [citation.marker, citation]));
  const parts = content.split(/(\[\d+\])/g);

  return (
    <>
      {parts.map((part, index) => {
        const marker = part.match(/^\[(\d+)\]$/)?.[1];
        const citation = marker ? citationByMarker.get(marker) : undefined;
        if (!citation) return <span key={`${part}-${index}`}>{part}</span>;

        return (
          <span
            className="font-medium text-foreground"
            aria-label={`Quelle ${citation.marker}: ${citation.sourceId}`}
            data-source-id={citation.sourceId}
            key={`${citation.sourceId}-${index}`}
          >
            {part}
          </span>
        );
      })}
    </>
  );
}

function formatActionPlanAmount(amount: number) {
  return new Intl.NumberFormat("de-DE", {
    style: "currency",
    currency: "EUR",
  }).format(amount);
}

function formatActionPlanExpiry(expiresAt: number) {
  return new Intl.DateTimeFormat("de-DE", {
    day: "2-digit",
    month: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  }).format(new Date(expiresAt));
}

function AgentSources({ sources }: { sources: AgentSource[] }) {
  return (
    <div className="mt-3 rounded-md border bg-muted/20 p-2">
      <p className="text-xs font-medium text-muted-foreground">Quellen</p>
      <div className="mt-2 space-y-2">
        {sources.map((source) => (
          <div
            className="rounded-md bg-background/80 p-2 text-xs"
            data-source-id={source.id}
            key={source.id}
          >
            <p className="font-medium text-foreground">{source.title}</p>
            {source.description && (
              <p className="mt-1 text-muted-foreground">{source.description}</p>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

function AgentEvidencePanel({
  sources,
  toolTrace,
}: {
  sources?: AgentSource[];
  toolTrace: AgentToolTrace[];
}) {
  const steps = buildReasoningSteps(toolTrace);

  return (
    <details className="mt-3 rounded-md border bg-muted/30 px-2 py-1.5">
      <summary className="flex cursor-pointer list-none items-center gap-2 text-xs font-medium text-muted-foreground">
        <Wrench className="h-3.5 w-3.5" />
        Nachweis & Arbeitsweg ({getToolTraceSummary(toolTrace)})
      </summary>
      <div className="mt-2 space-y-2">
        {steps.map((step, stepIndex) => (
          <ReasoningStep
            key={`${step.label}-${stepIndex}`}
            sourceId={sources?.[stepIndex]?.id}
            step={step}
          />
        ))}
      </div>
    </details>
  );
}

function ReasoningStep({
  sourceId,
  step,
}: {
  sourceId?: string;
  step: AgentReasoningStep;
}) {
  return (
    <div
      className="rounded-md bg-background/80 p-2 text-xs"
      data-source-id={sourceId}
      data-status={step.status}
    >
      <p className="font-medium text-foreground">{step.label}</p>
      <p className="mt-1 text-muted-foreground">{step.description}</p>
    </div>
  );
}

function AgentThinkingIndicator() {
  return (
    <div className="space-y-2 px-1 text-sm text-muted-foreground">
      <div className="flex items-center gap-2">
        <Loader2 className="h-4 w-4 animate-spin" />
        Denk mit der KI nach...
      </div>
      <div className="rounded-md border bg-muted/30 p-2 text-xs" data-status="active">
        <p className="font-medium text-foreground">Antwort wird vorbereitet</p>
        <p className="mt-1">Der Agent prueft den aktuellen Finanzkontext.</p>
      </div>
    </div>
  );
}

export function AgentPromptInput({
  value,
  placeholder,
  disabled,
  isSubmitting,
  onChange,
  onSubmit,
}: AgentPromptInputProps) {
  const submitDisabled = disabled || value.trim().length === 0;
  const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => onChange(event.target.value);

  return (
    <form
      className="rounded-lg border bg-card p-2 shadow-sm"
      aria-label="Chatnachricht senden"
      onSubmit={onSubmit}
    >
      <div className="flex items-end gap-2">
        <textarea
          className="min-h-11 flex-1 resize-none bg-transparent px-2 py-2 text-sm leading-6 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-60"
          value={value}
          onChange={handleChange}
          placeholder={placeholder}
          disabled={disabled}
          rows={1}
        />
        <Button type="submit" disabled={submitDisabled} className="shrink-0">
          {isSubmitting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
          {isSubmitting ? "Antwort laeuft" : "Senden"}
        </Button>
      </div>
    </form>
  );
}
