import { useState, useEffect, useCallback, useRef } from "react";
import type { Message, StreamEvent } from "@/types/electron";
import { useMessageQueue } from "./use-message-queue";
import type { ImageAttachment } from "@/store/app-store";

interface UseElectronAgentOptions {
  sessionId: string;
  workingDirectory?: string;
  onToolUse?: (toolName: string, toolInput: unknown) => void;
}

interface UseElectronAgentResult {
  messages: Message[];
  isProcessing: boolean;
  isConnected: boolean;
  sendMessage: (content: string, images?: ImageAttachment[]) => Promise<void>;
  stopExecution: () => Promise<void>;
  clearHistory: () => Promise<void>;
  error: string | null;
  // Queue-related state
  queuedMessages: { id: string; content: string; images?: ImageAttachment[]; timestamp: Date }[];
  isQueueProcessing: boolean;
  clearMessageQueue: () => void;
}

/**
 * React hook for interacting with the Electron-based Claude agent
 *
 * This hook provides a clean interface to the agent running in the Electron
 * main process, which survives Next.js restarts.
 */
export function useElectronAgent({
  sessionId,
  workingDirectory,
  onToolUse,
}: UseElectronAgentOptions): UseElectronAgentResult {
  const [messages, setMessages] = useState<Message[]>([]);
  const [isProcessing, setIsProcessing] = useState(false);
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const unsubscribeRef = useRef<(() => void) | null>(null);
  const currentMessageRef = useRef<Message | null>(null);

  // Send message directly to the agent (bypassing queue)
  const sendMessageDirectly = useCallback(
    async (content: string, images?: ImageAttachment[]) => {
      if (!window.electronAPI?.agent) {
        setError("Electron API not available");
        return;
      }

      if (isProcessing) {
        throw new Error("Agent is already processing a message");
      }

      setIsProcessing(true);
      setError(null);

      try {
        console.log("[useElectronAgent] Sending message directly", {
          hasImages: images && images.length > 0,
          imageCount: images?.length || 0
        });

        // Save images to .automaker/images and get paths
        let imagePaths: string[] | undefined;
        if (images && images.length > 0) {
          imagePaths = [];
          for (const image of images) {
            const result = await window.electronAPI.saveImageToTemp(
              image.data,
              image.filename,
              image.mimeType,
              workingDirectory // Pass workingDirectory as projectPath
            );
            if (result.success && result.path) {
              imagePaths.push(result.path);
              console.log("[useElectronAgent] Saved image to .automaker/images:", result.path);
            } else {
              console.error("[useElectronAgent] Failed to save image:", result.error);
            }
          }
        }

        const result = await window.electronAPI.agent.send(
          sessionId,
          content,
          workingDirectory,
          imagePaths
        );

        if (!result.success) {
          setError(result.error || "Failed to send message");
          setIsProcessing(false);
        }
        // Note: We don't set isProcessing to false here because
        // it will be set by the "complete" or "error" stream event
      } catch (err) {
        console.error("[useElectronAgent] Failed to send message:", err);
        setError(err instanceof Error ? err.message : "Failed to send message");
        setIsProcessing(false);
        throw err;
      }
    },
    [sessionId, workingDirectory, isProcessing]
  );

  // Message queue for queuing messages when agent is busy
  const {
    queuedMessages,
    isProcessingQueue,
    addToQueue,
    clearQueue,
    processNext,
  } = useMessageQueue({
    onProcessNext: async (queuedMessage) => {
      await sendMessageDirectly(queuedMessage.content, queuedMessage.images);
    },
  });

  // Initialize connection and load history
  useEffect(() => {
    if (!window.electronAPI?.agent) {
      setError("Electron API not available. Please run in Electron.");
      return;
    }

    if (!sessionId) {
      // No session selected - reset state
      setMessages([]);
      setIsConnected(false);
      setIsProcessing(false);
      setError(null);
      return;
    }

    let mounted = true;

    const initialize = async () => {
      // Reset error state when switching sessions
      setError(null);

      try {
        console.log("[useElectronAgent] Starting session:", sessionId);
        const result = await window.electronAPI.agent.start(
          sessionId,
          workingDirectory
        );

        if (!mounted) return;

        if (result.success && result.messages) {
          console.log("[useElectronAgent] Loaded", result.messages.length, "messages");
          setMessages(result.messages);
          setIsConnected(true);

          // Check if the agent is currently running for this session
          const historyResult = await window.electronAPI.agent.getHistory(sessionId);
          if (mounted && historyResult.success) {
            const isRunning = historyResult.isRunning || false;
            console.log("[useElectronAgent] Session running state:", isRunning);
            setIsProcessing(isRunning);
          }
        } else {
          setError(result.error || "Failed to start session");
          setIsProcessing(false);
        }
      } catch (err) {
        if (!mounted) return;
        console.error("[useElectronAgent] Failed to initialize:", err);
        setError(err instanceof Error ? err.message : "Failed to initialize");
        setIsProcessing(false);
      }
    };

    initialize();

    return () => {
      mounted = false;
    };
  }, [sessionId, workingDirectory]);

  // Auto-process queue when agent finishes processing
  useEffect(() => {
    if (!isProcessing && !isProcessingQueue && queuedMessages.length > 0) {
      console.log("[useElectronAgent] Auto-processing next queued message");
      processNext();
    }
  }, [isProcessing, isProcessingQueue, queuedMessages.length, processNext]);

  // Subscribe to streaming events
  useEffect(() => {
    if (!window.electronAPI?.agent) return;
    if (!sessionId) return; // Don't subscribe if no session

    console.log("[useElectronAgent] Subscribing to stream events for session:", sessionId);

    const handleStream = (event: StreamEvent) => {
      // CRITICAL: Only process events for our specific session
      if (event.sessionId !== sessionId) {
        console.log("[useElectronAgent] Ignoring event for different session:", event.sessionId);
        return;
      }

      console.log("[useElectronAgent] Stream event for", sessionId, ":", event.type);

      switch (event.type) {
        case "message":
          // User message added
          setMessages((prev) => [...prev, event.message]);
          break;

        case "stream":
          // Assistant message streaming
          if (event.isComplete) {
            // Final update
            setMessages((prev) =>
              prev.map((msg) =>
                msg.id === event.messageId
                  ? { ...msg, content: event.content }
                  : msg
              )
            );
            currentMessageRef.current = null;
          } else {
            // Streaming update
            setMessages((prev) => {
              const existingIndex = prev.findIndex((m) => m.id === event.messageId);
              if (existingIndex >= 0) {
                // Update existing message
                return prev.map((msg) =>
                  msg.id === event.messageId
                    ? { ...msg, content: event.content }
                    : msg
                );
              } else {
                // Create new message
                const newMessage: Message = {
                  id: event.messageId,
                  role: "assistant",
                  content: event.content,
                  timestamp: new Date().toISOString(),
                };
                currentMessageRef.current = newMessage;
                return [...prev, newMessage];
              }
            });
          }
          break;

        case "tool_use":
          // Tool being used
          console.log("[useElectronAgent] Tool use:", event.tool.name);
          onToolUse?.(event.tool.name, event.tool.input);
          break;

        case "complete":
          // Agent finished processing for THIS session
          console.log("[useElectronAgent] Processing complete for session:", sessionId);
          setIsProcessing(false);
          if (event.messageId) {
            setMessages((prev) =>
              prev.map((msg) =>
                msg.id === event.messageId
                  ? { ...msg, content: event.content }
                  : msg
              )
            );
          }
          break;

        case "error":
          // Error occurred for THIS session
          console.error("[useElectronAgent] Agent error for session:", sessionId, event.error);
          setIsProcessing(false);
          setError(event.error);
          if (event.message) {
            const errorMessage = event.message;
            setMessages((prev) => [...prev, errorMessage]);
          }
          break;
      }
    };

    unsubscribeRef.current = window.electronAPI.agent.onStream(handleStream);

    return () => {
      if (unsubscribeRef.current) {
        console.log("[useElectronAgent] Unsubscribing from stream events for session:", sessionId);
        unsubscribeRef.current();
        unsubscribeRef.current = null;
      }
    };
  }, [sessionId, onToolUse]);

  // Send a message to the agent
  const sendMessage = useCallback(
    async (content: string, images?: ImageAttachment[]) => {
      if (!window.electronAPI?.agent) {
        setError("Electron API not available");
        return;
      }

      if (isProcessing) {
        console.warn("[useElectronAgent] Already processing a message");
        return;
      }

      setIsProcessing(true);
      setError(null);

      try {
        console.log("[useElectronAgent] Sending message", {
          hasImages: images && images.length > 0,
          imageCount: images?.length || 0
        });

        // Save images to .automaker/images and get paths
        let imagePaths: string[] | undefined;
        if (images && images.length > 0) {
          imagePaths = [];
          for (const image of images) {
            const result = await window.electronAPI.saveImageToTemp(
              image.data,
              image.filename,
              image.mimeType,
              workingDirectory // Pass workingDirectory as projectPath
            );
            if (result.success && result.path) {
              imagePaths.push(result.path);
              console.log("[useElectronAgent] Saved image to .automaker/images:", result.path);
            } else {
              console.error("[useElectronAgent] Failed to save image:", result.error);
            }
          }
        }

        const result = await window.electronAPI.agent.send(
          sessionId,
          content,
          workingDirectory,
          imagePaths
        );

        if (!result.success) {
          setError(result.error || "Failed to send message");
          setIsProcessing(false);
        }
        // Note: We don't set isProcessing to false here because
        // it will be set by the "complete" or "error" stream event
      } catch (err) {
        console.error("[useElectronAgent] Failed to send message:", err);
        setError(err instanceof Error ? err.message : "Failed to send message");
        setIsProcessing(false);
      }
    },
    [sessionId, workingDirectory, isProcessing]
  );

  // Stop current execution
  const stopExecution = useCallback(async () => {
    if (!window.electronAPI?.agent) {
      setError("Electron API not available");
      return;
    }

    try {
      console.log("[useElectronAgent] Stopping execution");
      const result = await window.electronAPI.agent.stop(sessionId);

      if (!result.success) {
        setError(result.error || "Failed to stop execution");
      } else {
        setIsProcessing(false);
      }
    } catch (err) {
      console.error("[useElectronAgent] Failed to stop:", err);
      setError(err instanceof Error ? err.message : "Failed to stop execution");
    }
  }, [sessionId]);

  // Clear conversation history
  const clearHistory = useCallback(async () => {
    if (!window.electronAPI?.agent) {
      setError("Electron API not available");
      return;
    }

    try {
      console.log("[useElectronAgent] Clearing history");
      const result = await window.electronAPI.agent.clear(sessionId);

      if (result.success) {
        setMessages([]);
        setError(null);
      } else {
        setError(result.error || "Failed to clear history");
      }
    } catch (err) {
      console.error("[useElectronAgent] Failed to clear:", err);
      setError(err instanceof Error ? err.message : "Failed to clear history");
    }
  }, [sessionId]);

  return {
    messages,
    isProcessing,
    isConnected,
    sendMessage,
    stopExecution,
    clearHistory,
    error,
    queuedMessages,
    isQueueProcessing: isProcessingQueue,
    clearMessageQueue: clearQueue,
  };
}
