import { writable, derived, get } from "svelte/store";
import type {
  TerminalLine,
  ConnectionStatus,
  PermissionRequest,
  UserQuestionEvent,
  Attachment,
} from "$lib/types/messages";
import type { CharacterState } from "$lib/types/states";
import { cleanupConversationTracking } from "$lib/tauri";
import { characterState } from "$lib/stores/character";
import { sessionsStore } from "$lib/stores/sessions";

export interface Conversation {
  id: string;
  name: string;
  terminalLines: TerminalLine[];
  sessionId: string | null;
  connectionStatus: ConnectionStatus;
  workingDirectory: string;
  characterState: CharacterState;
  isProcessing: boolean;
  grantedTools: Set<string>;
  pendingPermission: PermissionRequest | null;
  pendingQuestion: UserQuestionEvent | null;
  scrollPosition: number;
  createdAt: Date;
  lastActivityAt: Date;
  attachments: Attachment[];
}

function createConversationsStore() {
  const conversations = writable<Map<string, Conversation>>(new Map());
  const activeConversationId = writable<string | null>(null);
  const pendingRetryMessage = writable<string | null>(null);

  let conversationCounter = 0;
  let lineIdCounter = 0;

  function generateConversationId(): string {
    return `conv-${Date.now()}-${conversationCounter++}`;
  }

  function generateLineId(): string {
    return `line-${Date.now()}-${lineIdCounter++}`;
  }

  function createNewConversation(name?: string): Conversation {
    const id = generateConversationId();
    return {
      id,
      name: name || `Conversation ${conversationCounter}`,
      terminalLines: [],
      sessionId: null,
      connectionStatus: "disconnected",
      workingDirectory: "",
      characterState: "idle",
      isProcessing: false,
      grantedTools: new Set(),
      pendingPermission: null,
      pendingQuestion: null,
      scrollPosition: -1, // -1 means "scroll to bottom" (auto-scroll)
      createdAt: new Date(),
      lastActivityAt: new Date(),
      attachments: [],
    };
  }

  // Initialize with first conversation lazily
  let initialized = false;
  function ensureInitialized() {
    if (!initialized) {
      initialized = true;
      const initialConversation = createNewConversation("Main");
      conversations.update((convs) => {
        convs.set(initialConversation.id, initialConversation);
        return convs;
      });
      activeConversationId.set(initialConversation.id);
    }
  }

  // Derived store for current conversation
  const activeConversation = derived(
    [conversations, activeConversationId],
    ([$conversations, $activeId]) => {
      if (!$activeId) return null;
      return $conversations.get($activeId) || null;
    }
  );

  // Derived stores for compatibility with existing code
  const connectionStatus = derived(
    activeConversation,
    ($conv) => $conv?.connectionStatus || "disconnected"
  );
  const terminalLines = derived(activeConversation, ($conv) => {
    return $conv?.terminalLines || [];
  });
  const sessionId = derived(activeConversation, ($conv) => $conv?.sessionId || null);
  const currentWorkingDirectory = derived(
    activeConversation,
    ($conv) => $conv?.workingDirectory || ""
  );
  const isProcessing = derived(activeConversation, ($conv) => $conv?.isProcessing || false);
  const grantedTools = derived(
    activeConversation,
    ($conv) => $conv?.grantedTools || new Set<string>()
  );
  const pendingPermission = derived(
    activeConversation,
    ($conv) => $conv?.pendingPermission || null
  );
  const pendingQuestion = derived(activeConversation, ($conv) => $conv?.pendingQuestion || null);
  const scrollPosition = derived(activeConversation, ($conv) => $conv?.scrollPosition ?? -1);
  const attachments = derived(activeConversation, ($conv) => $conv?.attachments || []);

  return {
    // Expose derived stores for compatibility
    connectionStatus: { subscribe: connectionStatus.subscribe },
    sessionId: { subscribe: sessionId.subscribe },
    currentWorkingDirectory: { subscribe: currentWorkingDirectory.subscribe },
    terminalLines: { subscribe: terminalLines.subscribe },
    pendingPermission: { subscribe: pendingPermission.subscribe },
    pendingQuestion: { subscribe: pendingQuestion.subscribe },
    isProcessing: { subscribe: isProcessing.subscribe },
    grantedTools: { subscribe: grantedTools.subscribe },
    pendingRetryMessage: { subscribe: pendingRetryMessage.subscribe },
    scrollPosition: { subscribe: scrollPosition.subscribe },
    attachments: { subscribe: attachments.subscribe },

    // New conversation-specific stores
    conversations: { subscribe: conversations.subscribe },
    activeConversationId: { subscribe: activeConversationId.subscribe },
    activeConversation: { subscribe: activeConversation.subscribe },

    // Connection management
    setConnectionStatus: (status: ConnectionStatus) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.connectionStatus = status;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    setConnectionStatusForConversation: (conversationId: string, status: ConnectionStatus) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.connectionStatus = status;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    setCharacterStateForConversation: (conversationId: string, state: CharacterState) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.characterState = state;
          // If this is the active conversation, update the global character state
          if (conversationId === get(activeConversationId)) {
            characterState.setState(state);
          }
        }
        return convs;
      });
    },
    requestPermission: (request: PermissionRequest) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.pendingPermission = request;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    clearPermission: () => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.pendingPermission = null;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    requestPermissionForConversation: (conversationId: string, request: PermissionRequest) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.pendingPermission = request;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    clearPermissionForConversation: (conversationId: string) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.pendingPermission = null;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    requestQuestion: (question: UserQuestionEvent) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.pendingQuestion = question;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    clearQuestion: () => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.pendingQuestion = null;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    requestQuestionForConversation: (conversationId: string, question: UserQuestionEvent) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.pendingQuestion = question;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    clearQuestionForConversation: (conversationId: string) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.pendingQuestion = null;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },
    setPendingRetryMessage: (message: string | null) => pendingRetryMessage.set(message),

    // Conversation management
    createConversation: (name?: string) => {
      ensureInitialized();
      const newConv = createNewConversation(name);
      conversations.update((convs) => {
        convs.set(newConv.id, newConv);
        return convs;
      });
      activeConversationId.set(newConv.id);
      return newConv.id;
    },

    deleteConversation: async (id: string) => {
      ensureInitialized();
      const convs = get(conversations);
      const activeId = get(activeConversationId);

      if (convs.size <= 1) {
        // Don't delete the last conversation
        return false;
      }

      // Cancel any pending auto-save for this conversation
      sessionsStore.cancelAutoSave(id);

      // Clean up tracking for this conversation (including temp files)
      await cleanupConversationTracking(id);

      conversations.update((c) => {
        c.delete(id);
        return c;
      });

      // If we deleted the active conversation, switch to another
      if (activeId === id) {
        const remaining = Array.from(get(conversations).keys());
        if (remaining.length > 0) {
          activeConversationId.set(remaining[0]);
        }
      }
      return true;
    },

    switchConversation: async (id: string) => {
      const convs = get(conversations);
      if (!convs.has(id)) return;

      const currentId = get(activeConversationId);
      const targetConv = convs.get(id);

      // If switching to a different conversation
      if (currentId !== id) {
        activeConversationId.set(id);

        // Update the global character state to match the conversation's state
        if (targetConv) {
          characterState.setState(targetConv.characterState);
        }
      }
    },

    renameConversation: (id: string, newName: string) => {
      conversations.update((convs) => {
        const conv = convs.get(id);
        if (conv) {
          conv.name = newName;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    saveScrollPosition: (id: string, position: number) => {
      conversations.update((convs) => {
        const conv = convs.get(id);
        if (conv) {
          conv.scrollPosition = position;
        }
        return convs;
      });
    },

    getScrollPosition: (id: string): number => {
      const convs = get(conversations);
      const conv = convs.get(id);
      return conv?.scrollPosition ?? -1;
    },

    // Methods that operate on the active conversation
    setSessionId: (id: string | null) => {
      ensureInitialized();
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.sessionId = id;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    setSessionIdForConversation: (conversationId: string, id: string | null) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.sessionId = id;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    setWorkingDirectory: (dir: string) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.workingDirectory = dir;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    setWorkingDirectoryForConversation: (conversationId: string, dir: string) => {
      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.workingDirectory = dir;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    setProcessing: (processing: boolean) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.isProcessing = processing;
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    addLine: (type: TerminalLine["type"], content: string, toolName?: string) => {
      ensureInitialized();
      const activeId = get(activeConversationId);
      if (!activeId) return "";

      const line: TerminalLine = {
        id: generateLineId(),
        type,
        content,
        timestamp: new Date(),
        toolName,
      };

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.terminalLines.push(line);
          conv.lastActivityAt = new Date();
          // Schedule auto-save for this conversation
          sessionsStore.scheduleAutoSave(conv);
        }
        return convs;
      });

      return line.id;
    },

    addLineToConversation: (
      conversationId: string,
      type: TerminalLine["type"],
      content: string,
      toolName?: string
    ) => {
      ensureInitialized();

      const line: TerminalLine = {
        id: generateLineId(),
        type,
        content,
        timestamp: new Date(),
        toolName,
      };

      conversations.update((convs) => {
        const conv = convs.get(conversationId);
        if (conv) {
          conv.terminalLines.push(line);
          conv.lastActivityAt = new Date();
          // Schedule auto-save for this conversation
          sessionsStore.scheduleAutoSave(conv);
        }
        return convs;
      });

      return line.id;
    },

    updateLine: (id: string, content: string) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          const line = conv.terminalLines.find((l) => l.id === id);
          if (line) {
            line.content = content;
            conv.lastActivityAt = new Date();
          }
        }
        return convs;
      });
    },

    appendToLine: (id: string, additionalContent: string) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          const line = conv.terminalLines.find((l) => l.id === id);
          if (line) {
            line.content += additionalContent;
            conv.lastActivityAt = new Date();
          }
        }
        return convs;
      });
    },

    clearTerminal: () => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.terminalLines = [];
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    getConversationHistory: (): string => {
      const activeId = get(activeConversationId);
      if (!activeId) return "";

      const convs = get(conversations);
      const conv = convs.get(activeId);
      if (!conv) return "";

      const relevantLines = conv.terminalLines.filter(
        (line) => line.type === "user" || line.type === "assistant"
      );

      if (relevantLines.length === 0) return "";

      return relevantLines
        .map((line) => {
          const role = line.type === "user" ? "User" : "Assistant";
          return `${role}: ${line.content}`;
        })
        .join("\n\n");
    },

    grantTool: (toolName: string) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.grantedTools.add(toolName);
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    revokeAllTools: () => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.grantedTools.clear();
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    isToolGranted: (toolName: string): boolean => {
      const activeId = get(activeConversationId);
      if (!activeId) return false;

      const convs = get(conversations);
      const conv = convs.get(activeId);
      return conv?.grantedTools.has(toolName) || false;
    },

    // Attachment management
    addAttachment: (attachment: Attachment) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.attachments.push(attachment);
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    removeAttachment: (id: string) => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.attachments = conv.attachments.filter((a) => a.id !== id);
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    clearAttachments: () => {
      const activeId = get(activeConversationId);
      if (!activeId) return;

      conversations.update((convs) => {
        const conv = convs.get(activeId);
        if (conv) {
          conv.attachments = [];
          conv.lastActivityAt = new Date();
        }
        return convs;
      });
    },

    getAttachments: (): Attachment[] => {
      const activeId = get(activeConversationId);
      if (!activeId) return [];

      const convs = get(conversations);
      const conv = convs.get(activeId);
      return conv?.attachments || [];
    },

    // Add initialization helper
    initialize: () => {
      ensureInitialized();
    },
  };
}

export const conversationsStore = createConversationsStore();
// Initialize immediately
conversationsStore.initialize();
