<script setup lang="ts">
import { useAgentSessions } from "~/composables/useAgentSessions";
import { useAgentChatStore } from "~/composables/useAgentChatStore";
import { useAuthSession } from "~/composables/useAuthSession";

definePageMeta({
  layout: "agent",
});

const auth = useAuthSession();
const sessions = useAgentSessions();
const isMobile = useMediaQuery('(max-width: 767.98px)');
const sidebarCollapsed = ref(false);
const mobileSidebarOpen = ref(false);
const showPromptModal = ref(false);
const systemPromptText = ref("");
const preferredModelId = ref<number | null>(null);
const guestDefaultModelId = ref<number | null>(null);

interface ModelOption {
  id: number;
  name: string;
  modelId: string;
  providerName: string;
  supportsTools: number;
}

const models = ref<ModelOption[]>([]);

const currentModelId = computed({
  get: () => {
    const sessionModelId = sessions.currentSession.value?.modelId ?? null;
    if (sessionModelId !== null && models.value.length > 0 && !models.value.some((m) => m.id === sessionModelId)) {
      return null;
    }
    return sessionModelId;
  },
  set: (val: number | null) => {
    if (sessions.currentSessionId.value) {
      sessions.updateSessionConfig(sessions.currentSessionId.value, { modelId: val });
    }
  },
});

watch(
  () => [sessions.currentSessionId.value, models.value] as const,
  ([sid, modelList]) => {
    if (!sid || modelList.length === 0) return;
    const session = sessions.currentSession.value;
    const mid = session?.modelId ?? null;
    if (mid !== null && !modelList.some((m) => m.id === mid)) {
      currentModelId.value = null;
    } else if (mid === null) {
      const fallbackSource = auth.loggedIn.value
        ? (preferredModelId.value && modelList.some((m) => m.id === preferredModelId.value) ? preferredModelId.value : null)
        : (guestDefaultModelId.value && modelList.some((m) => m.id === guestDefaultModelId.value) ? guestDefaultModelId.value : null);
      const fallback = fallbackSource ?? modelList[0].id;
      currentModelId.value = fallback;
    }
  },
);

const currentModelSupportsTools = computed(() => {
  const mid = currentModelId.value;
  if (mid === null) return true;
  const model = models.value.find((m) => m.id === mid);
  return model ? model.supportsTools === 1 : true;
});

const enableTools = computed({
  get: () => {
    if (!currentModelSupportsTools.value) return false;
    return !!(sessions.currentSession.value?.enableTools);
  },
  set: (val: boolean) => {
    if (!currentModelSupportsTools.value) return;
    if (sessions.currentSessionId.value) {
      sessions.updateSessionConfig(sessions.currentSessionId.value, { enableTools: val });
    }
  },
});

const chat = useAgentChatStore({
  modelId: () => currentModelId.value,
  enableThinking: () => false,
  enableTools: () => enableTools.value,
  onStreamComplete: (sid) => {
    if (!sid) return;
    setTimeout(() => sessions.refreshSessionTitle(sid), 3000);
  },
});

const rateLimitInfo = computed(() => {
  if (auth.loggedIn.value) return undefined;
  return {
    sessionRemaining: chat.rateLimit.value.sessionRemaining.value,
    ipRemaining: chat.rateLimit.value.ipRemaining.value,
  };
});

async function loadModels() {
  try {
    const isGuest = !auth.loggedIn.value;
    const endpoint = isGuest ? "/api/agent/models" : "/api/llm/models";
    const res = await $fetch<{ code: number; data: { list: any[]; defaultModelId?: number | null } }>(endpoint);
    const list = res.data?.list ?? [];
    models.value = list.map((m) => ({
      id: m.id,
      name: m.name,
      modelId: m.modelId,
      providerName: m.providerName ?? "—",
      supportsTools: m.supportsTools ?? 1,
    }));
    if (isGuest) {
      guestDefaultModelId.value = res.data?.defaultModelId ?? null;
    }
  } catch {
    models.value = [];
  }
}

async function loadUserConfig() {
  if (!auth.loggedIn.value) return;
  try {
    const res = await $fetch<{ code: number; data: { config: Record<string, unknown> } }>(
      "/api/config/me",
    );
    const val = res.data?.config?.preferredLlmModelId;
    preferredModelId.value = typeof val === "number" && val > 0 ? val : null;
  } catch {
    preferredModelId.value = null;
  }
}

async function loadSystemPrompt() {
  try {
    const res = await $fetch<{ code: number; data: { systemPrompt?: string } }>(
      "/api/agent/system-prompt",
    );
    systemPromptText.value = res.data?.systemPrompt ?? "";
  } catch {
    systemPromptText.value = "";
  }
}

watch(
  () => sessions.currentSessionId.value,
  async (sid) => {
    chat.setCurrentSessionId(sid);
    if (sid) {
      await chat.loadMessages(sid);
    } else {
      chat.clear();
    }
  },
);

watch(isMobile, (mobile) => {
  if (mobile) {
    mobileSidebarOpen.value = false;
  } else {
    sidebarCollapsed.value = false;
  }
}, { immediate: true });

async function handleSend(content: string) {
  if (!sessions.currentSessionId.value) {
    await sessions.newSession();
  }
  if (sessions.currentSessionId.value) {
    const sid = sessions.currentSessionId.value;
    const inst = chat.getInstance(sid);
    const wasNewSession = inst.messages.value.filter((m) => m.role === "assistant").length === 0;
    await chat.send(content);
    sessions.touchSessionOrder(sid);
    if (wasNewSession) {
      refreshTitleWithRetry(sid);
    }
  }
}

function refreshTitleWithRetry(sid: string) {
  const delays = [3000, 6000, 10000, 15000, 22000];
  delays.forEach((delay) => {
    setTimeout(() => sessions.refreshSessionTitle(sid), delay);
  });
}

async function handleApprove(toolCallId: string, approved: boolean) {
  await chat.respondToApproval(toolCallId, approved);
}

async function handleDeleteSession(id: string) {
  chat.forceStop();
  chat.removeInstance(id);
  await sessions.deleteSession(id);
}

async function handleFeedback(messageId: string, feedback: "like" | "dislike") {
  await chat.sendFeedback(messageId, feedback);
}

function handleEdit(messageId: string, content: string) {
  chat.send(content, { editMessageId: messageId });
}

function handleRegenerate() {
  const lastUserMsg = [...chat.messages.value].reverse().find((m) => m.role === "user");
  if (lastUserMsg) {
    chat.send(lastUserMsg.content, { regenerate: true });
  }
}

function handleExample(content: string) {
  handleSend(content);
}

function handleLogin() {
  navigateTo("/auth/login");
}

onMounted(async () => {
  await Promise.all([sessions.init(), loadModels(), loadSystemPrompt(), loadUserConfig()]);
});
</script>

<template>
  <AgentSidebar
    :sessions="sessions.sessions.value"
    :current-session-id="sessions.currentSessionId.value"
    :logged-in="auth.loggedIn.value"
    :user="auth.user.value"
    :collapsed="isMobile ? !mobileSidebarOpen : sidebarCollapsed"
    :mobile="isMobile"
    @new-session="sessions.newSession(); if (isMobile) mobileSidebarOpen = false"
    @select="sessions.selectSession($event); if (isMobile) mobileSidebarOpen = false"
    @rename="sessions.renameSession"
    @delete="handleDeleteSession"
    @login="handleLogin"
    @toggle="isMobile ? (mobileSidebarOpen = !mobileSidebarOpen) : (sidebarCollapsed = !sidebarCollapsed)"
    @close="mobileSidebarOpen = false"
  />

  <AgentChatArea
    :messages="chat.messages.value"
    :is-loading="chat.isLoading.value"
    :has-pending-approval="chat.hasPendingApproval.value"
    :logged-in="auth.loggedIn.value"
    :model-id="currentModelId"
    :models="models"
    :enable-tools="enableTools"
    :tools-disabled="!currentModelSupportsTools"
    :rate-limit-info="rateLimitInfo"
    :sidebar-collapsed="sidebarCollapsed"
    :error-message="chat.errorMessage.value"
    :system-prompt="systemPromptText"
    @send="handleSend"
    @stop="chat.stopGeneration()"
    @update:model-id="currentModelId = $event"
    @update:enable-tools="enableTools = $event"
    @approve="handleApprove"
    @feedback="handleFeedback"
    @edit="handleEdit"
    @regenerate="handleRegenerate"
    @toggle-sidebar="isMobile ? (mobileSidebarOpen = !mobileSidebarOpen) : (sidebarCollapsed = !sidebarCollapsed)"
    @show-prompt="showPromptModal = true"
    @example="handleExample"
  />

  <AgentSystemPromptModal
    :show="showPromptModal"
    :system-prompt="systemPromptText"
    @close="showPromptModal = false"
  />
</template>
