"use client";

import { useState, useRef, useEffect, useCallback, useMemo, memo, type FormEvent } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import type { Components } from "react-markdown";
import type { ChatMessage, InterruptPayload, AnalysisStateSnapshot } from "@optage/sdk/client";
import { MermaidDiagram } from "@/components/markdown/MermaidDiagram";
import { ToolCallCard } from "@/components/ToolCallCard";

interface ChatViewProps {
  messages: ChatMessage[];
  isStreaming: boolean;
  error: string | null;
  pendingInterrupt: InterruptPayload | null;
  analysisState: AnalysisStateSnapshot | null;
  onSend: (text: string) => void;
  onResolveInterrupt: (approved: boolean, reason?: string) => void;
}

export function ChatView({
  messages,
  isStreaming,
  pendingInterrupt,
  onSend,
  onResolveInterrupt,
}: ChatViewProps) {
  const [input, setInput] = useState("");
  const scrollRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLTextAreaElement>(null);

  useEffect(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, isStreaming, pendingInterrupt]);

  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  useEffect(() => {
    const el = inputRef.current;
    if (el) {
      el.style.height = "auto";
      el.style.height = Math.min(el.scrollHeight, 200) + "px";
    }
  }, [input]);

  const handleSubmit = useCallback(
    (e: FormEvent) => {
      e.preventDefault();
      if (!input.trim() || isStreaming) return;
      onSend(input.trim());
      setInput("");
    },
    [input, isStreaming, onSend],
  );

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        if (!input.trim() || isStreaming) return;
        onSend(input.trim());
        setInput("");
      }
    },
    [input, isStreaming, onSend],
  );

  const isEmpty = (!messages || messages.length === 0) && !isStreaming;
  const lastMsg = messages?.[messages.length - 1];
  const showTyping = isStreaming && lastMsg?.role === "user";

  return (
    <div className="flex flex-col h-full bg-rp-bg">
      <div ref={scrollRef} className="flex-1 overflow-y-auto">
        {isEmpty ? (
          <EmptyState />
        ) : (
          <div className="max-w-chat mx-auto px-4 py-6 space-y-1">
            {(messages || []).map((msg) => (
              <MessageBubble
                key={msg.id}
                message={msg}
                onResolveInterrupt={onResolveInterrupt}
              />
            ))}

            {showTyping && (
              <div className="py-4">
                <TypingIndicator />
              </div>
            )}
          </div>
        )}
      </div>

      <div className="shrink-0 pb-4 pt-2 px-4">
        <div className="max-w-chat mx-auto">
          <form onSubmit={handleSubmit}>
            <div className="relative bg-rp-surface-alt border border-rp-border/40 rounded-xl transition-colors focus-within:border-rp-accent/30">
              <textarea
                ref={inputRef}
                value={input}
                onChange={(e) => setInput(e.target.value)}
                onKeyDown={handleKeyDown}
                disabled={isStreaming}
                placeholder="Type a message..."
                rows={1}
                className="w-full bg-transparent text-rp-text text-r-base px-4 pt-3 pb-10 resize-none outline-none placeholder:text-rp-muted disabled:opacity-50 leading-relaxed"
              />
              <div className="absolute bottom-2 right-2 flex items-center gap-2">
                <button
                  type="submit"
                  disabled={isStreaming || !input.trim()}
                  className={`p-2 transition-colors disabled:opacity-30 disabled:cursor-not-allowed ${input.trim() ? "text-rp-accent" : "text-rp-muted"}`}
                  aria-label="Send message"
                >
                  <ArrowUpIcon />
                </button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}

const MessageBubble = memo(function MessageBubble({
  message,
  onResolveInterrupt,
}: {
  message: ChatMessage;
  onResolveInterrupt: (approved: boolean, reason?: string) => void;
}) {
  if (message.role === "user") {
    const textBlock = message.blocks.find((b) => b.type === "text");
    const content = textBlock?.type === "text" ? textBlock.text : "";
    return <UserEntry content={content} />;
  }

  return (
    <AssistantMessage
      message={message}
      onResolveInterrupt={onResolveInterrupt}
    />
  );
});

const AssistantMessage = memo(function AssistantMessage({
  message,
  onResolveInterrupt,
}: {
  message: ChatMessage;
  onResolveInterrupt: (approved: boolean, reason?: string) => void;
}) {
  const components = useMarkdownComponents();

  if (message.blocks.length === 0) return null;

  return (
    <div className="py-4">
      <div className="min-w-0 overflow-hidden flex flex-col gap-1">
        {message.blocks.map((block, idx) => {
          switch (block.type) {
            case "text":
              if (!block.text) return null;
              return (
                <div key={block.id} className="notion-prose assistant-message">
                  {idx === 0 && (
                    <span className="text-rp-muted text-r-2xs block mb-1">AI</span>
                  )}
                  <ReactMarkdown
                    remarkPlugins={[remarkGfm]}
                    components={components}
                  >
                    {block.text}
                  </ReactMarkdown>
                </div>
              );
            case "tool_call":
              return <ToolCallCard key={block.id} block={block} />;
            case "error":
              return (
                <div key={block.id} className="flex items-center gap-2 py-2">
                  <div className="w-5 h-5 rounded-full bg-rp-error/20 text-rp-error flex items-center justify-center text-r-xs font-semibold shrink-0">
                    !
                  </div>
                  <span className="text-r-sm text-rp-error">{block.message}</span>
                </div>
              );
            case "interrupt":
              return (
                <InterruptEntry
                  key={block.id}
                  interrupt={block.interrupt}
                  onResolve={onResolveInterrupt}
                />
              );
            default:
              return null;
          }
        })}
      </div>
    </div>
  );
});

function EmptyState() {
  return (
    <div className="flex flex-col items-center justify-center h-full px-4">
      <div className="max-w-md text-center space-y-4">
        <h1 className="text-2xl font-semibold text-rp-text">
          What would you like to explore?
        </h1>
        <div className="flex flex-wrap justify-center gap-2 pt-2">
          <SuggestionChip label="What CBS message schemas exist?" />
          <SuggestionChip label="Show me the class hierarchy" />
          <SuggestionChip label="How many Java files are indexed?" />
        </div>
      </div>
    </div>
  );
}

function SuggestionChip({ label }: { label: string }) {
  return (
    <button className="px-3 py-2 text-r-sm text-rp-muted bg-rp-surface hover:bg-rp-surface/80 rounded-lg hover:text-rp-text transition-colors">
      {label}
    </button>
  );
}

function TypingIndicator() {
  return (
    <div className="text-rp-muted text-r-lg animate-pulse">...</div>
  );
}

function ArrowUpIcon() {
  return (
    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M8 12V4" />
      <path d="M4 7L8 3L12 7" />
    </svg>
  );
}

function UserEntry({ content }: { content: string }) {
  return (
    <div className="flex justify-end py-3">
      <div className="max-w-[85%] bg-rp-accent text-white rounded-2xl px-4 py-3 text-r-base leading-relaxed whitespace-pre-wrap">
        {content}
      </div>
    </div>
  );
}

function useMarkdownComponents(): Components {
  return useMemo(
    (): Components => ({
      code({ className, children, ...props }) {
        const match = /language-(\w+)/.exec(className || "");
        const language = match ? match[1] : null;
        const codeString = String(children).replace(/\n$/, "");

        if (!className) {
          return <code {...props}>{children}</code>;
        }

        if (language === "mermaid") {
          return <MermaidDiagram chart={codeString} />;
        }

        return (
          <div className="relative group my-2">
            <div className="absolute top-2 right-3 flex items-center gap-2 z-10">
              <div className="opacity-0 group-hover:opacity-100 transition-opacity">
                <CopyButton text={codeString} />
              </div>
              <span className="text-rp-faint text-r-2xs">{language}</span>
            </div>
            <pre><code className={className} {...props}>{codeString}</code></pre>
          </div>
        );
      },
      pre({ children }) {
        return <>{children}</>;
      },
      table({ children }) {
        return (
          <div className="my-2 overflow-x-auto">
            <table>{children}</table>
          </div>
        );
      },
    }),
    [],
  );
}

function CopyButton({ text }: { text: string }) {
  const [copied, setCopied] = useState(false);

  const handleCopy = useCallback(() => {
    navigator.clipboard.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }, [text]);

  return (
    <button
      onClick={handleCopy}
      className="text-rp-muted hover:text-rp-text transition-colors text-r-2xs flex items-center gap-1"
    >
      {copied ? (
        <>
          <CheckIcon /> copied
        </>
      ) : (
        <>
          <CopyIcon /> copy
        </>
      )}
    </button>
  );
}

function InterruptEntry({
  interrupt,
  onResolve,
}: {
  interrupt: InterruptPayload;
  onResolve: (approved: boolean, reason?: string) => void;
}) {
  const [decided, setDecided] = useState(false);
  const [approved, setApproved] = useState(false);

  const handleApprove = () => {
    setApproved(true);
    setDecided(true);
    onResolve(true);
  };

  const handleReject = () => {
    setApproved(false);
    setDecided(true);
    onResolve(false, "User declined execution.");
  };

  return (
    <div className={`py-2 ${decided ? "opacity-60" : ""}`}>
      <div className="bg-rp-surface rounded-lg p-4 max-w-lg">
        <div className="mb-2">
          <span className="font-semibold text-rp-text text-r-sm">Action required</span>
        </div>
        <div className="text-rp-text text-r-sm mb-1">{interrupt.action}</div>
        {interrupt.description && (
          <div className="text-rp-muted text-r-xs mb-3">{interrupt.description}</div>
        )}

        {decided ? (
          <div className={`font-medium text-r-sm ${approved ? "text-rp-success" : "text-rp-error"}`}>
            {approved ? "Approved" : "Rejected"}
          </div>
        ) : (
          <div className="flex gap-2">
            <button
              onClick={handleApprove}
              className="btn-accent"
            >
              Allow
            </button>
            <button
              onClick={handleReject}
              className="btn-ghost"
            >
              Deny
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

function CheckIcon() {
  return (
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      <path d="M3 7.5L5.5 10L11 4" />
    </svg>
  );
}

function CopyIcon() {
  return (
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
      <rect x="4" y="4" width="8" height="8" rx="1.5" />
      <path d="M10 4V2.5A1.5 1.5 0 008.5 1H2.5A1.5 1.5 0 001 2.5V8.5A1.5 1.5 0 002.5 10H4" />
    </svg>
  );
}
