import { randomUUID } from 'node:crypto';
import type { Sql } from '../db.js';

export const DEFAULT_SKILL_USER_MESSAGE = 'Apply this skill.';

export interface SkillInvokeTransactionResult {
  synth_assistant_id: string;
  tool_message_id: string;
  user_message_id: string;
  assistant_message_id: string;
}

export interface SkillInvokeToolCall {
  id: string;
  name: 'skill_use';
  args: { name: string };
}

export type SkillInvokeSessionFrame = Record<string, unknown> & { type: string };

export async function runSkillInvokeTransaction(
  sql: Sql,
  args: {
    sessionId: string;
    chatId: string;
    skillName: string;
    skillBody: string;
    userText: string;
  },
): Promise<{ result: SkillInvokeTransactionResult; toolCall: SkillInvokeToolCall }> {
  const toolCallId = randomUUID();
  const toolCall: SkillInvokeToolCall = {
    id: toolCallId,
    name: 'skill_use',
    args: { name: args.skillName },
  };
  const toolResults = {
    tool_call_id: toolCallId,
    output: args.skillBody,
    truncated: false,
  };

  const result = await sql.begin(async (tx) => {
    const [synthAssistant] = await tx<{ id: string }[]>`
      INSERT INTO messages (session_id, chat_id, role, content, status, created_at)
      VALUES (${args.sessionId}, ${args.chatId}, 'assistant', '', 'complete', clock_timestamp())
      RETURNING id
    `;
    await tx`
      INSERT INTO message_parts (message_id, sequence, kind, payload)
      VALUES (${synthAssistant!.id}, 0, 'tool_call', ${tx.json({
        id: toolCallId,
        name: 'skill_use',
        args: { name: args.skillName },
      } as never)})
    `;
    const [toolMsg] = await tx<{ id: string }[]>`
      INSERT INTO messages (session_id, chat_id, role, content, status, created_at)
      VALUES (${args.sessionId}, ${args.chatId}, 'tool', '', 'complete', clock_timestamp())
      RETURNING id
    `;
    await tx`
      INSERT INTO message_parts (message_id, sequence, kind, payload)
      VALUES (${toolMsg!.id}, 0, 'tool_result', ${tx.json(toolResults as never)})
    `;
    const [userMsg] = await tx<{ id: string }[]>`
      INSERT INTO messages (session_id, chat_id, role, content, status, created_at)
      VALUES (${args.sessionId}, ${args.chatId}, 'user', ${args.userText}, 'complete', clock_timestamp())
      RETURNING id
    `;
    const [assistantMsg] = await tx<{ id: string }[]>`
      INSERT INTO messages (session_id, chat_id, role, content, status, created_at)
      VALUES (${args.sessionId}, ${args.chatId}, 'assistant', '', 'streaming', clock_timestamp())
      RETURNING id
    `;
    await tx`UPDATE sessions SET updated_at = clock_timestamp() WHERE id = ${args.sessionId}`;
    await tx`UPDATE chats SET updated_at = clock_timestamp() WHERE id = ${args.chatId}`;
    return {
      synth_assistant_id: synthAssistant!.id,
      tool_message_id: toolMsg!.id,
      user_message_id: userMsg!.id,
      assistant_message_id: assistantMsg!.id,
    };
  });

  return { result, toolCall };
}

export function buildSkillInvokeSyntheticFrames(
  chatId: string,
  result: SkillInvokeTransactionResult,
  toolCall: SkillInvokeToolCall,
  skillBody: string,
): SkillInvokeSessionFrame[] {
  return [
    {
      type: 'message_started',
      message_id: result.synth_assistant_id,
      chat_id: chatId,
      role: 'assistant',
    },
    {
      type: 'tool_call',
      message_id: result.synth_assistant_id,
      chat_id: chatId,
      tool_call: toolCall,
    },
    {
      type: 'message_complete',
      message_id: result.synth_assistant_id,
      chat_id: chatId,
    },
    {
      type: 'tool_result',
      tool_message_id: result.tool_message_id,
      tool_call_id: toolCall.id,
      chat_id: chatId,
      output: skillBody,
      truncated: false,
    },
  ];
}

export function buildSkillInvokeUserFrames(
  chatId: string,
  userMessageId: string,
  userText: string,
): SkillInvokeSessionFrame[] {
  return [
    {
      type: 'message_started',
      message_id: userMessageId,
      chat_id: chatId,
      role: 'user',
    },
    {
      type: 'delta',
      message_id: userMessageId,
      chat_id: chatId,
      content: userText,
    },
    {
      type: 'message_complete',
      message_id: userMessageId,
      chat_id: chatId,
    },
  ];
}
