import { apiFetch } from "@/lib/apiFetch";
import { config } from "@config/config";

import type {
  ChatSessionSummary,
  LoadedChatState,
  Message,
} from "./GlobalChatbox.types";
import { cloneMessages } from "./globalChatboxUtils";

type BackendSessionPayload = {
  id?: string;
  title?: string;
  created_at?: string | number;
  updated_at?: string | number;
  is_streaming?: boolean;
  run_status?: string;
};

export const createEmptyChatState = (): LoadedChatState => ({
  title: undefined,
  isTitleManuallyEdited: false,
  messages: [],
  sessionId: undefined,
});

const sanitizeMessages = (messages: Message[] | undefined) =>
  Array.isArray(messages) ? cloneMessages(messages) : [];

const compareSessionsByAnchorTime = (
  left: Pick<ChatSessionSummary, "id" | "createdAt" | "updatedAt">,
  right: Pick<ChatSessionSummary, "id" | "createdAt" | "updatedAt">,
) => {
  const createdAtDiff = right.createdAt - left.createdAt;
  if (createdAtDiff !== 0) return createdAtDiff;

  const updatedAtDiff = right.updatedAt - left.updatedAt;
  if (updatedAtDiff !== 0) return updatedAtDiff;

  return right.id.localeCompare(left.id);
};

const toMillis = (value: string | number | undefined) =>
  typeof value === "number" ? value : value ? new Date(value).getTime() : Date.now();

const normalizeTitle = (value?: string) => value?.trim() || "新对话";

const fetchBackendChatSessions = async (): Promise<ChatSessionSummary[]> => {
  const response = await apiFetch(`${config.AGENT_URL}/api/v1/agent/sessions`, {
    method: "GET",
    projectHeaderMode: "include",
    skipAuthRedirect: true,
  });
  if (!response.ok) {
    throw new Error(await response.text());
  }
  const payload = (await response.json()) as {
    sessions?: BackendSessionPayload[];
  };
  return (payload.sessions ?? [])
    .map((session) => ({
      id: session.id ?? "",
      title: normalizeTitle(session.title),
      createdAt: toMillis(session.created_at),
      updatedAt: toMillis(session.updated_at),
      isStreaming: session.is_streaming,
      runStatus: session.run_status,
    }))
    .filter((session) => Boolean(session.id))
    .sort(compareSessionsByAnchorTime);
};

const fetchBackendChatSession = async (sessionId: string): Promise<LoadedChatState> => {
  const response = await apiFetch(
    `${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}`,
    {
      method: "GET",
      projectHeaderMode: "include",
      skipAuthRedirect: true,
    },
  );
  if (!response.ok) {
    if (response.status === 404) {
      return createEmptyChatState();
    }
    throw new Error(await response.text());
  }
  const payload = (await response.json()) as {
    id: string;
    title?: string;
    is_title_manually_edited?: boolean;
    session_id?: string;
    messages?: Message[];
    is_streaming?: boolean;
    run_status?: string;
  };
  return {
    title: normalizeTitle(payload.title),
    isTitleManuallyEdited: payload.is_title_manually_edited ?? false,
    messages: sanitizeMessages(payload.messages),
    sessionId: payload.session_id ?? payload.id,
    isStreaming: payload.is_streaming ?? false,
    runStatus: payload.run_status,
  };
};

const updateBackendChatSessionTitle = async (
  sessionId: string,
  title: string,
  isTitleManuallyEdited?: boolean,
) => {
  const response = await apiFetch(
    `${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}`,
    {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        title,
        is_title_manually_edited: isTitleManuallyEdited,
      }),
      projectHeaderMode: "include",
      skipAuthRedirect: true,
    },
  );
  if (!response.ok) {
    throw new Error(await response.text());
  }
};

const deleteBackendChatSession = async (sessionId: string) => {
  const response = await apiFetch(
    `${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}`,
    {
      method: "DELETE",
      projectHeaderMode: "include",
      skipAuthRedirect: true,
    },
  );
  if (!response.ok && response.status !== 404) {
    throw new Error(await response.text());
  }
};

export const listChatSessions = async (): Promise<ChatSessionSummary[]> => {
  if (typeof window === "undefined") return [];
  return await fetchBackendChatSessions();
};

export const updateChatSessionTitle = async (
  sessionId: string,
  title: string,
  options?: {
    isTitleManuallyEdited?: boolean;
  },
): Promise<void> => {
  if (typeof window === "undefined") return;

  const normalizedTitle = title.trim();
  if (!normalizedTitle) return;
  await updateBackendChatSessionTitle(
    sessionId,
    normalizedTitle,
    options?.isTitleManuallyEdited,
  );
};

export const loadChatSessionById = async (
  sessionId: string,
): Promise<LoadedChatState> => {
  if (typeof window === "undefined") return createEmptyChatState();

  return await fetchBackendChatSession(sessionId);
};

export const deleteChatSession = async (
  sessionId: string,
): Promise<string | undefined> => {
  if (typeof window === "undefined") return undefined;

  await deleteBackendChatSession(sessionId);
  const nextActiveSession = (await listChatSessions())[0];
  return nextActiveSession?.id;
};
