import type { CompanyPermission } from "@/lib/company-context";

import type { ContextoDoAssistente } from "../contexto";
import type { Campos } from "../esquema";

/**
 * O formato de uma ferramenta do assistente.
 *
 * Leitura consulta e responde. Escrita tem dois tempos: `preparar` confere
 * tudo e monta a prévia, sem gravar nada; `gravar` executa o que a prévia
 * mostrou. Quem costura os dois tempos, com o código de confirmação no meio, é
 * o executor em `index.ts`. A ferramenta só sabe do assunto dela.
 */

export type Argumentos = Record<string, unknown>;

/* `dados` é o que o assistente lê. `resumo` é a linha que vai para o registro
   de atividade, em português de gente. */
/* `imagens`: fotos para o assistente VER (a prévia de uma arte), em base64; não vão no registro. */
export type Saida = { dados: Record<string, unknown>; resumo: string; imagens?: Array<{ dados: string; tipo: string }> };

export type Preparo<Carga = unknown> = {
  previa: Record<string, unknown>;
  resumo: string;
  avisos: string[];
  /* Sensível pelo RESULTADO (um cupom que acaba grande, um pedido que vai
     para entregue): o executor troca a gravação direta pela prévia com código,
     mesmo que os argumentos sozinhos não denunciassem isso. */
  sensivel?: boolean;
  /* O que `gravar` precisa para executar, já conferido. Não vai ao assistente. */
  carga: Carga;
};

type Base = {
  nome: string;
  titulo: string;
  descricao: string;
  campos: Campos;
  /* Basta uma destas para a ferramenta aparecer. Vazia = qualquer pessoa da
     empresa. A ferramenta ainda confere a permissão exata lá dentro. */
  permissoes: CompanyPermission[];
  /* Vai a sites de fora (ler outra loja, baixar fotos): o programa do
     assistente recebe isso como aviso de que o comando sai da conta. */
  abertoAoMundo?: boolean;
  /* Mexe em dinheiro, nota fiscal, exclusão, cancelamento ou domínio: sempre
     passa pela prévia com código (as outras gravam direto, a não ser que a
     empresa tenha escolhido "sempre" em Assistentes e Apps). */
  sensivel?: boolean | ((argumentos: Argumentos) => boolean);
};

export type FerramentaDeLeitura = Base & {
  tipo: "leitura";
  executar(ctx: ContextoDoAssistente, args: Argumentos): Promise<Saida>;
};

export type FerramentaDeEscrita<Carga = unknown> = Base & {
  tipo: "escrita";
  /* Troca ou apaga algo que já existia (um preço, um texto), em vez de só
     criar. O programa do assistente recebe isso como aviso de ação
     destrutiva e costuma pedir a confirmação da pessoa antes de chamar. */
  sobrescreve?: boolean;
  preparar(ctx: ContextoDoAssistente, args: Argumentos): Promise<Preparo<Carga>>;
  gravar(ctx: ContextoDoAssistente, carga: Carga): Promise<Saida>;
};

export type Ferramenta = FerramentaDeLeitura | FerramentaDeEscrita;

/** Erro cuja mensagem pode ir ao assistente: é para ele (e a pessoa) se corrigir. */
export class ErroDaFerramenta extends Error {}
