import parseGrokStream from "../parsers/grok.js";

const DEFAULT_MODEL = "grok-3-latest";

export async function createConversation() {
  const res = await this.graphql("CreateGrokConversation", { body: { variables: {} } });
  return res?.data?.create_grok_conversation?.conversation_id ?? res;
}

export async function respond(conversationId, message, opts = {}) {
  if (!conversationId) throw new Error("respond requires a conversationId");

  const body = {
    responses: [
      {
        message: message ?? "",
        sender: 1,
        promptSource: opts.promptSource ?? "",
        fileAttachments: opts.fileAttachments || [],
      },
      ...(opts.responses || []),
    ],
    systemPromptName: opts.systemPromptName ?? "",
    grokModelOptionId: opts.model || DEFAULT_MODEL,
    conversationId,
    returnSearchResults: opts.returnSearchResults ?? true,
    returnCitations: opts.returnCitations ?? true,
    promptMetadata: opts.promptMetadata || { promptSource: "NATURAL", action: "INPUT" },
    imageGenerationCount: opts.imageGenerationCount ?? 4,
    requestFeatures: opts.requestFeatures || { eagerTweets: true, serverHistory: true },
    enableSideBySide: opts.enableSideBySide ?? true,
    toolOverrides: opts.toolOverrides || {},
    isDeepsearch: opts.deepsearch ?? false,
    isReasoning: opts.reasoning ?? false,
    ...opts.body,
  };

  const res = await this.grokApi("add_response.json", { method: "POST", body });
  if (res.status !== 200) {
    let detail = res.text;
    try {
      detail = res.json()?.errors?.map((e) => e.message).join(", ") || res.text;
    } catch {}
    throw new Error(`grok add_response failed (${res.status}): ${detail}`);
  }

  if (opts.raw) return res.text;
  return parseGrokStream(res.text);
}

export async function ask(message, opts = {}) {
  const conversationId = opts.conversationId || (await createConversation.call(this));
  const result = await respond.call(this, conversationId, message, opts);
  if (opts.raw) return result;
  return { ...result, conversationId: result.conversationId || conversationId };
}

export async function home() {
  const res = await this.graphql("GrokHome", { variables: {} });
  return res?.data?.grok_home ?? res;
}

export async function models() {
  const h = await home.call(this);
  return h?.grok_model_options ?? [];
}

export async function history(opts = {}) {
  const res = await this.graphql("GrokHistory", {
    variables: { count: opts.count, cursor: opts.cursor, ...opts.variables },
  });
  return res?.data?.grok_conversation_history ?? res;
}

export async function mediaHistory(opts = {}) {
  const res = await this.graphql("GrokMediaHistory", {
    variables: { count: opts.count, cursor: opts.cursor, ...opts.variables },
  });
  return res?.data ?? res;
}

export async function conversation(restId, opts = {}) {
  if (!restId) throw new Error("conversation requires a rest id");
  const res = await this.graphql("GrokConversationItemsByRestId", {
    variables: { restId, ...opts.variables },
  });
  return res?.data ?? res;
}

export async function search(query, opts = {}) {
  const res = await this.graphql("SearchGrokConversations", {
    variables: { query, ...opts.variables },
  });
  return res?.data ?? res;
}

export async function pinned() {
  const res = await this.graphql("GrokPinnedConversations", { variables: {} });
  return res?.data?.grok_pinned_conversations ?? res;
}

export async function pin(conversationId) {
  if (!conversationId) throw new Error("pin requires a conversationId");
  const res = await this.graphql("GrokPinConversation", {
    body: { variables: { conversationId } },
  });
  return res?.data?.grokconversation_pin ?? res;
}

export async function unpin(conversationId) {
  if (!conversationId) throw new Error("unpin requires a conversationId");
  const res = await this.graphql("GrokUnpinConversation", {
    body: { variables: { conversationId } },
  });
  return res?.data?.grokconversation_unpin ?? res;
}

export async function deleteMessage(conversationId, chatItemId) {
  if (!conversationId || !chatItemId) {
    throw new Error("deleteMessage requires (conversationId, chatItemId)");
  }
  return await this.graphql("DeleteGrokMessage", {
    body: { variables: { conversation_id: conversationId, chat_item_id: chatItemId } },
  });
}

export async function clear() {
  return await this.graphql("ClearGrokConversations", { body: { variables: {} } });
}

export async function share(shareId) {
  if (!shareId) throw new Error("share requires a grok_share_id");
  const res = await this.graphql("GrokShare", { variables: { grok_share_id: shareId } });
  return res?.data ?? res;
}

export async function setPreferences(params = {}) {
  return await this.graphql("SetGrokPreferences", { body: { variables: { ...params } } });
}
