import { lerCodigos, apagarCodigo } from "@/lib/digitais/servidor/codigos";
import {
  adicionarCodigosAoProduto,
  adicionarEntregavel,
  alterarEntregavel,
  apagarProdutoDigital,
  criarProdutoDigital,
  lerProdutoDigital,
  listarProdutosDigitais,
  salvarProdutoDigital,
  tirarEntregavel,
} from "@/lib/digitais/servidor/acoes/produtos";
import type { ContextoDigital } from "@/lib/digitais/servidor/contexto";

import type { ContextoDoAssistente } from "../contexto";
import type { Campos } from "../esquema";
import { DESCRICAO_DO_CAMPO_DE_IMAGEM } from "../imagens";
import { AVISO_DE_DADOS, contagem, reais, recusar, texto } from "./comum";
import {
  abrirDigital,
  arquivoIndicado,
  guardarImagemDigital,
  naRota,
  pedidoDoAssistente,
  prepararImagemDigital,
  semContatoNovo,
  type ImagemDigital,
} from "./digitais-comum";
import { dataEHoraBr, instanteDeBrasilia, lerReferenciaDeArquivo, mesclarConfig, mudaPrecoNaLoja, type MudancasNaConfig } from "./digitais-regras";
import type { Ferramenta, FerramentaDeEscrita, FerramentaDeLeitura } from "./tipos";

/*
 * Produtos digitais pelo assistente: a lista, a ficha inteira (com a página de
 * venda do conteúdo em vídeo), o que o comprador recebe, os códigos e
 * licenças, publicar e apagar. Tudo pelas funções das rotas do painel
 * (lib/digitais/servidor/acoes/produtos.ts), com as permissões da tela:
 * ver = digital.products.read; mudar = digital.products.write.
 */

const TIPOS_QUE_CRIA = ["conteudo_em_video", "arquivos", "link", "codigo"] as const;
const TIPO_DA_ROTA: Record<(typeof TIPOS_QUE_CRIA)[number], string> = {
  conteudo_em_video: "curso",
  arquivos: "arquivos",
  link: "link",
  codigo: "codigo",
};
const NOME_DO_TIPO: Record<string, string> = {
  curso: "conteudo_em_video",
  arquivos: "arquivos",
  link: "link",
  codigo: "codigo",
  live: "live",
};

type ProdutoLido = Awaited<ReturnType<typeof lerProdutoDigital>>;

/* ------------------------------------------------------------ a ficha */

const CAMPOS_DA_FICHA: Campos = {
  nome: { tipo: "texto", descricao: "Nome do produto (aparece na loja e na área de membros).", max: 200 },
  descricao: { tipo: "texto", descricao: "Descrição da página de venda: para quem é, o que tem dentro, por que comprar.", max: 20000 },
  preco: { tipo: "numero", descricao: "Preço em reais (0 = grátis; grátis só para quem assina o Ktalogu).", min: 0, max: 1_000_000 },
  capa: { tipo: "texto", descricao: `Capa quadrada (vitrine, área de membros e e-mails). ${DESCRICAO_DO_CAMPO_DE_IMAGEM}`, max: 2000 },
  frase: { tipo: "texto", descricao: "Uma frase embaixo do nome, na loja: o que a pessoa consegue fazer depois.", max: 160 },
  perguntas_frequentes: {
    tipo: "lista",
    descricao: "Perguntas frequentes da página de venda (troca a lista inteira; [] apaga).",
    maxItens: 12,
    itens: {
      pergunta: { tipo: "texto", descricao: "A pergunta.", obrigatorio: true, max: 200 },
      resposta: { tipo: "texto", descricao: "A resposta.", obrigatorio: true, max: 1200 },
    },
  },
  funciona_com: { tipo: "textos", descricao: "Programas e aparelhos com que funciona (ex.: Canva, CorelDRAW). Troca a lista.", max: 40, maxItens: 12 },
  licenca: { tipo: "opcao", descricao: "Licença de uso dos arquivos.", opcoes: ["pessoal", "comercial", "livre", "texto", "nenhuma"] },
  texto_da_licenca: { tipo: "texto", descricao: "O texto da licença (quando licenca = texto, ou para detalhar).", max: 2000 },
  prazo_de_acesso: { tipo: "opcao", descricao: "Por quanto tempo o cliente acessa.", opcoes: ["igual_as_configuracoes", "para_sempre", "dias"] },
  prazo_de_acesso_dias: { tipo: "inteiro", descricao: "Os dias de acesso (com prazo_de_acesso = dias).", min: 1, max: 3650 },
  amostras: { tipo: "textos", descricao: `Imagens de amostra da página de venda (até 8; troca a lista; [] apaga). Cada uma: ${DESCRICAO_DO_CAMPO_DE_IMAGEM}`, max: 2000, maxItens: 8 },
  sob_encomenda: { tipo: "booleano", descricao: "Arquivos e link: true = a loja produz depois da compra e anexa o arquivo final no pedido; false = entrega na hora." },
  prazo_da_encomenda_dias: { tipo: "inteiro", descricao: "Sob encomenda: prazo em dias úteis.", min: 0, max: 90 },
  pre_venda_dia: { tipo: "data", descricao: "Pré-venda: vende hoje e libera para todos neste dia (com e-mail para quem comprou)." },
  pre_venda_hora: { tipo: "hora", descricao: "Hora da liberação da pré-venda (padrão 00:00)." },
  tirar_pre_venda: { tipo: "booleano", descricao: "true = desliga a pré-venda." },
  limite_de_downloads: { tipo: "inteiro", descricao: "Quantas vezes cada arquivo pode ser baixado (0 = sem limite).", min: 0, max: 1000 },
  marca_no_pdf: { tipo: "opcao", descricao: "Marcar o PDF com nome, e-mail e número do pedido.", opcoes: ["sim", "nao", "igual_as_configuracoes"] },
  avisar_codigos_com: { tipo: "inteiro", descricao: "Código ou licença: avisar quando restarem estes códigos.", min: 0, max: 1000 },
  campos_do_comprador: {
    tipo: "lista",
    descricao: "Sob encomenda: o que o comprador preenche na compra (troca a lista; [] apaga).",
    maxItens: 12,
    itens: {
      titulo: { tipo: "texto", descricao: "A pergunta (ex.: Nome no convite).", obrigatorio: true, max: 80 },
      tipo: { tipo: "opcao", descricao: "texto (uma linha), texto_longo ou numero.", opcoes: ["texto", "texto_longo", "numero"] },
      exemplo: { tipo: "texto", descricao: "Exemplo que aparece no campo.", max: 120 },
      obrigatorio: { tipo: "booleano", descricao: "Obrigatório." },
    },
  },
  o_que_vai_ver: { tipo: "textos", descricao: "Conteúdo em vídeo: \"O que você vai ver\" (até 12 frases curtas; troca a lista).", max: 140, maxItens: 12 },
  quem_apresenta: {
    tipo: "objeto",
    descricao: "Conteúdo em vídeo: quem apresenta (nome, uma linha de destaque, história e foto).",
    campos: {
      nome: { tipo: "texto", descricao: "Nome.", obrigatorio: true, max: 80 },
      destaque: { tipo: "texto", descricao: "Uma linha sobre quem apresenta.", max: 120 },
      historia: { tipo: "texto", descricao: "A história.", max: 1200 },
      foto: { tipo: "texto", descricao: `Foto quadrada do rosto. ${DESCRICAO_DO_CAMPO_DE_IMAGEM}`, max: 2000 },
    },
  },
  tirar_quem_apresenta: { tipo: "booleano", descricao: "true = tira quem apresenta." },
  video_de_apresentacao: {
    tipo: "texto",
    descricao: "Conteúdo em vídeo: o vídeo curto do topo da página de venda. Um vídeo da biblioteca (id ou \"envio:...\") ou um link do YouTube, Vimeo ou Panda Video.",
    max: 2000,
  },
  tirar_video_de_apresentacao: { tipo: "booleano", descricao: "true = tira o vídeo de apresentação." },
  garantia_dias: { tipo: "inteiro", descricao: "Conteúdo em vídeo: dias de garantia de satisfação (0 = não mostrar garantia).", min: 0, max: 90 },
  certificado: { tipo: "booleano", descricao: "Conteúdo em vídeo: este conteúdo dá certificado." },
  horas_do_certificado: { tipo: "inteiro", descricao: "Carga horária do certificado (0 = a soma dos vídeos).", min: 0, max: 2000 },
};

type FichaPronta = {
  corpo: Record<string, unknown>;
  capa: ImagemDigital | null;
  fotoDeQuemApresenta: ImagemDigital | null;
  amostras: ImagemDigital[] | null;
  previa: Record<string, unknown>;
};

const CAMPO_DO_COMPRADOR: Record<string, string> = { texto: "text", texto_longo: "textarea", numero: "number" };

/** Lê os campos da ficha e monta o corpo que a rota de salvar recebe (sem gravar imagem nenhuma ainda). */
async function lerFicha(ctx: ContextoDoAssistente, contexto: ContextoDigital, args: Record<string, unknown>, atual: ProdutoLido["produto"] | null, tipo: string): Promise<FichaPronta> {
  const corpo: Record<string, unknown> = {};
  const previa: Record<string, unknown> = {};
  const curso = tipo === "curso";

  if (args.nome !== undefined) {
    corpo.nome = args.nome;
    previa.nome = args.nome;
  }
  if (args.descricao !== undefined) {
    corpo.descricao = args.descricao;
    previa.descricao = texto(args.descricao, 300);
  }
  if (args.preco !== undefined) {
    corpo.preco = args.preco;
    previa.preco = reais(args.preco);
  }

  const m: MudancasNaConfig = {};
  if (args.frase !== undefined) m.resumo = String(args.frase);
  if (args.perguntas_frequentes !== undefined) m.perguntas = args.perguntas_frequentes as Array<{ pergunta: string; resposta: string }>;
  if (args.funciona_com !== undefined) m.funcionaCom = args.funciona_com as string[];
  if (args.licenca !== undefined) {
    m.licenca = args.licenca === "nenhuma" ? null : { tipo: String(args.licenca), texto: (args.texto_da_licenca as string | undefined) ?? atual?.config.licenca?.texto ?? null };
  } else if (args.texto_da_licenca !== undefined) {
    m.licenca = { tipo: atual?.config.licenca?.tipo ?? "texto", texto: String(args.texto_da_licenca) };
  }
  if (args.prazo_de_acesso !== undefined) {
    if (args.prazo_de_acesso === "dias" && !args.prazo_de_acesso_dias) recusar("Diga os dias em prazo_de_acesso_dias.");
    m.prazoDeAcessoDias = args.prazo_de_acesso === "igual_as_configuracoes" ? null : args.prazo_de_acesso === "para_sempre" ? 0 : Number(args.prazo_de_acesso_dias);
  } else if (args.prazo_de_acesso_dias !== undefined) {
    m.prazoDeAcessoDias = Number(args.prazo_de_acesso_dias);
  }
  if (args.sob_encomenda !== undefined || args.prazo_da_encomenda_dias !== undefined) {
    if (args.sob_encomenda === true && tipo !== "arquivos" && tipo !== "link") recusar("Sob encomenda é só para produtos de arquivos ou de link.");
    m.entrega = {
      ...(args.sob_encomenda !== undefined ? { modo: args.sob_encomenda ? "encomenda" : "na_hora" } : {}),
      ...(args.prazo_da_encomenda_dias !== undefined ? { prazoDias: Number(args.prazo_da_encomenda_dias) } : {}),
    };
  }
  if (args.tirar_pre_venda === true) m.preVendaEm = null;
  else if (args.pre_venda_dia !== undefined) {
    const em = instanteDeBrasilia(String(args.pre_venda_dia), (args.pre_venda_hora as string | undefined) ?? "00:00");
    if (!em) recusar("Confira o dia e a hora da pré-venda.");
    if (new Date(em).getTime() <= Date.now()) recusar("A data da pré-venda precisa ser depois de hoje.");
    m.preVendaEm = em;
  }
  if (args.limite_de_downloads !== undefined) m.limiteDeDownloads = Number(args.limite_de_downloads) || null;
  if (args.marca_no_pdf !== undefined) m.marcaNoPdf = args.marca_no_pdf === "igual_as_configuracoes" ? null : args.marca_no_pdf === "sim";
  if (args.avisar_codigos_com !== undefined) m.avisarCodigosCom = Number(args.avisar_codigos_com);

  /* A página de venda do conteúdo em vídeo. */
  const daPaginaDoConteudo = ["o_que_vai_ver", "quem_apresenta", "tirar_quem_apresenta", "video_de_apresentacao", "tirar_video_de_apresentacao", "garantia_dias", "certificado", "horas_do_certificado"];
  let fotoDeQuemApresenta: ImagemDigital | null = null;
  if (daPaginaDoConteudo.some((campo) => args[campo] !== undefined)) {
    if (!curso) recusar("Página de venda (o que vai ver, quem apresenta, vídeo de apresentação, garantia, certificado) é só do conteúdo em vídeo.");
    m.curso = {};
    if (args.o_que_vai_ver !== undefined) m.curso.aprendizados = args.o_que_vai_ver as string[];
    if (args.tirar_quem_apresenta === true) m.curso.professor = null;
    else if (args.quem_apresenta !== undefined) {
      const q = args.quem_apresenta as Record<string, unknown>;
      if (q.foto) fotoDeQuemApresenta = await prepararImagemDigital(ctx, q.foto, "quadrada");
      m.curso.professor = {
        nome: String(q.nome),
        destaque: (q.destaque as string | undefined) ?? null,
        bio: (q.historia as string | undefined) ?? null,
        foto: q.foto ? "__foto__" : atual?.config.curso?.professor?.foto ?? null,
      };
    }
    if (args.tirar_video_de_apresentacao === true) m.curso.apresentacao = null;
    else if (args.video_de_apresentacao !== undefined) {
      if (lerReferenciaDeArquivo(args.video_de_apresentacao)) {
        const arquivo = await arquivoIndicado(ctx, contexto, args.video_de_apresentacao);
        if (arquivo.categoria !== "video") recusar("O vídeo de apresentação precisa ser um vídeo (MP4, WebM ou MOV).");
        m.curso.apresentacao = { arquivoId: arquivo.id };
      } else {
        m.curso.apresentacao = { link: String(args.video_de_apresentacao) };
      }
    }
    if (args.garantia_dias !== undefined) m.curso.garantiaDias = Number(args.garantia_dias) || null;
    if (args.certificado !== undefined || args.horas_do_certificado !== undefined) {
      m.curso.certificado = {
        ...(args.certificado !== undefined ? { emitir: args.certificado === true } : {}),
        ...(args.horas_do_certificado !== undefined ? { cargaHoras: Number(args.horas_do_certificado) || null } : {}),
      };
    }
  }

  let amostras: ImagemDigital[] | null = null;
  if (args.amostras !== undefined) {
    amostras = [];
    for (const valor of args.amostras as string[]) amostras.push(await prepararImagemDigital(ctx, valor, "livre"));
    m.amostras = [];
  }

  if (Object.keys(m).length) {
    corpo.config = mesclarConfig(atual?.config ?? { tipo }, m);
    previa.ajustes = Object.keys(m);
  }

  if (args.campos_do_comprador !== undefined) {
    corpo.campos = (args.campos_do_comprador as Array<Record<string, unknown>>).map((c, i) => ({
      id: `cf_${i + 1}`,
      title: c.titulo,
      field_type: CAMPO_DO_COMPRADOR[String(c.tipo ?? "texto")] ?? "text",
      placeholder: c.exemplo ?? "",
      required: c.obrigatorio === true,
      active: true,
    }));
    previa.campos_do_comprador = (args.campos_do_comprador as unknown[]).length;
  }

  let capa: ImagemDigital | null = null;
  if (args.capa !== undefined) {
    capa = await prepararImagemDigital(ctx, args.capa, "quadrada");
    previa.capa = capa.origem;
  }
  if (fotoDeQuemApresenta) previa.foto_de_quem_apresenta = fotoDeQuemApresenta.origem;
  if (amostras) previa.amostras = amostras.length;

  /* Texto que o cliente lê: nada de contato novo. */
  const juntar = (p: { nome?: unknown; descricao?: unknown; config?: unknown } | null) => {
    if (!p) return "";
    const c = (p.config ?? {}) as { resumo?: unknown; perguntas?: unknown; licenca?: unknown; curso?: { professor?: unknown; aprendizados?: unknown } };
    return JSON.stringify([p.nome, p.descricao, c.resumo, c.perguntas, c.licenca, c.curso?.professor, c.curso?.aprendizados]);
  };
  semContatoNovo(atual ? juntar(atual) : "", juntar({ nome: corpo.nome ?? atual?.nome, descricao: corpo.descricao ?? atual?.descricao, config: corpo.config ?? atual?.config }), "na tela do produto digital");

  return { corpo, capa, fotoDeQuemApresenta, amostras, previa };
}

/* Guarda as imagens (só agora, na gravação) e põe os endereços no corpo. */
async function gravarImagensDaFicha(ctx: ContextoDoAssistente, ficha: FichaPronta) {
  const corpo = { ...ficha.corpo };
  if (ficha.capa) corpo.imagem = await guardarImagemDigital(ctx, ficha.capa, "digitais/capas");
  if (corpo.config && typeof corpo.config === "object") {
    const config = { ...(corpo.config as Record<string, unknown>) };
    if (ficha.amostras) {
      const enderecos: string[] = [];
      for (const amostra of ficha.amostras) enderecos.push(await guardarImagemDigital(ctx, amostra, "digitais/amostras"));
      config.amostras = enderecos;
    }
    const curso = config.curso as { professor?: { foto?: string | null } | null } | undefined;
    if (ficha.fotoDeQuemApresenta && curso?.professor) {
      const foto = await guardarImagemDigital(ctx, ficha.fotoDeQuemApresenta, "digitais/professores");
      config.curso = { ...curso, professor: { ...curso.professor, foto } };
    }
    corpo.config = config;
  }
  return corpo;
}

function produtoParaOAssistente(lido: ProdutoLido) {
  const p = lido.produto;
  const c = p.config;
  return {
    id: p.id,
    nome: p.nome,
    tipo: NOME_DO_TIPO[p.tipo] ?? p.tipo,
    tipo_na_tela: p.rotuloDoTipo,
    preco: reais(p.preco),
    na_loja: p.naLoja,
    link_na_loja: p.enderecoNaLoja,
    capa: p.imagem,
    descricao: texto(p.descricao, 3000),
    frase: c.resumo,
    perguntas_frequentes: c.perguntas,
    funciona_com: c.funcionaCom,
    licenca: c.licenca,
    prazo_de_acesso: c.acesso === null ? "igual às configurações" : c.acesso.prazoDias ? `${c.acesso.prazoDias} dias` : "para sempre",
    amostras: c.amostras,
    entrega: c.entrega.modo === "encomenda" ? `sob encomenda (${c.entrega.prazoDias} dias úteis)` : "na hora",
    pre_venda: c.preVenda ? dataEHoraBr(c.preVenda.em) : null,
    limite_de_downloads: c.limiteDeDownloads ?? "sem limite",
    marca_no_pdf: c.marcaNoPdf === null ? "igual às configurações" : c.marcaNoPdf ? "sim" : "não",
    ...(p.tipo === "codigo" ? { avisar_codigos_com: c.avisarCodigosCom } : {}),
    campos_do_comprador: p.campos.map((campo) => ({ titulo: campo.title, tipo: campo.field_type, obrigatorio: campo.required })),
    ...(c.curso
      ? {
          pagina_de_venda: {
            o_que_vai_ver: c.curso.aprendizados,
            quem_apresenta: c.curso.professor,
            video_de_apresentacao: c.curso.apresentacao
              ? "arquivoId" in c.curso.apresentacao
                ? { arquivo_id: c.curso.apresentacao.arquivoId }
                : { link: c.curso.apresentacao.link.url }
              : null,
            garantia_dias: c.curso.garantiaDias,
            certificado: c.curso.certificado.emitir ? `sim (${c.curso.certificado.cargaHoras ? `${c.curso.certificado.cargaHoras} horas` : "carga = soma dos vídeos"})` : "não",
          },
          conteudo: { modulos: c.curso.conteudo.modulos.length, videos: c.curso.conteudo.aulas, materiais: c.curso.conteudo.materiais },
        }
      : {}),
    o_que_o_comprador_recebe: lido.entregaveis.map((e) => ({
      item_id: e.id,
      tipo: e.tipo,
      titulo: e.titulo,
      descricao: e.descricao,
      link: e.tipo === "link" ? e.url : undefined,
      texto: e.tipo === "texto" || e.tipo === "link" ? texto(e.instrucoes, 600) : undefined,
      arquivo: e.arquivo ? { id: e.arquivo.id, nome: e.arquivo.nome, tamanho: e.arquivo.tamanhoLegivel, situacao: e.arquivo.status } : undefined,
      ligado: e.ativo,
    })),
    vendas: p.vendas,
    numeros_30_dias: { pedidos: lido.numeros.pedidos30, receita: reais(lido.numeros.receita30), com_acesso: lido.numeros.comAcesso, downloads: lido.numeros.downloads },
  };
}

async function lerProduto(ctx: ContextoDoAssistente, contexto: ContextoDigital, id: string) {
  return naRota(() => lerProdutoDigital(contexto, id, pedidoDoAssistente(ctx)));
}

/* ------------------------------------------------------------ leituras */

export const listarProdutosDigitaisFerramenta: FerramentaDeLeitura = {
  nome: "listar_produtos_digitais",
  titulo: "Ver os produtos digitais",
  descricao:
    "Lista os produtos digitais da loja (conteúdo em vídeo, arquivos para baixar, link de acesso, código ou licença, live): preço, se está na loja, vendas e receita dos últimos 30 dias, quantos têm acesso, códigos sobrando, pré-venda e sob encomenda.",
  campos: {
    tipo: { tipo: "opcao", descricao: "Filtrar por tipo.", opcoes: ["conteudo_em_video", "arquivos", "link", "codigo", "live", "todos"] },
    busca: { tipo: "texto", descricao: "Parte do nome.", max: 80 },
  },
  tipo: "leitura",
  permissoes: ["digital.products.read"],
  async executar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.read", "ver os produtos digitais");
    const lista = await naRota(() => listarProdutosDigitais(contexto));
    const busca = String(args.busca ?? "").trim().toLowerCase();
    const produtos = lista.produtos
      .filter((p) => !args.tipo || args.tipo === "todos" || NOME_DO_TIPO[p.tipo] === args.tipo)
      .filter((p) => !busca || p.nome.toLowerCase().includes(busca))
      .map((p) => ({
        id: p.id,
        nome: p.nome,
        tipo: NOME_DO_TIPO[p.tipo] ?? p.tipo,
        tipo_na_tela: p.rotuloDoTipo,
        preco: reais(p.preco),
        na_loja: p.naLoja,
        live_id: p.liveId,
        pedidos_30_dias: p.pedidos30,
        receita_30_dias: reais(p.receita30),
        com_acesso: p.comAcesso,
        downloads: p.downloads,
        codigos: p.codigos ? { para_vender: p.codigos.livres, total: p.codigos.total, esperando: p.codigos.esperando, situacao: p.codigos.situacao } : null,
        sob_encomenda: p.sobEncomenda,
        pre_venda: p.preVenda ? dataEHoraBr(p.preVenda) : null,
      }));
    return {
      dados: { _observacao: AVISO_DE_DADOS, produtos, total: produtos.length, dica: "Live se edita com as ferramentas de live (ver_live com o live_id)." },
      resumo: `Consultou os produtos digitais (${produtos.length})`,
    };
  },
};

export const verProdutoDigital: FerramentaDeLeitura = {
  nome: "ver_produto_digital",
  titulo: "Ver um produto digital",
  descricao:
    "A ficha inteira de um produto digital, como na tela: preço, capa, descrição, frase, perguntas, licença, prazo de acesso, entrega, pré-venda, downloads, o que o comprador recebe (com o item_id de cada um), a página de venda do conteúdo em vídeo e os números dos últimos 30 dias. Código ou licença: traz também os códigos (mascarados).",
  campos: { produto_id: { tipo: "id", descricao: "Id do produto (de listar_produtos_digitais).", obrigatorio: true } },
  tipo: "leitura",
  permissoes: ["digital.products.read"],
  async executar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.read", "ver os produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    const dados: Record<string, unknown> = { _observacao: AVISO_DE_DADOS, produto: produtoParaOAssistente(lido) };
    if (lido.produto.tipo === "codigo") {
      const codigos = await naRota(() => lerCodigos(contexto.admin, contexto.lojaId, lido.produto.id));
      dados.codigos = resumoDosCodigos(codigos);
    }
    if (lido.produto.tipo === "curso") dados.proximo_passo = "Para os módulos e vídeos, chame ver_conteudo_em_video com este id.";
    if (lido.produto.tipo === "live") dados.proximo_passo = "Live se edita com ver_live / alterar_live (o live_id está em listar_produtos_digitais).";
    return { dados, resumo: `Consultou o produto digital ${lido.produto.nome}` };
  },
};

function resumoDosCodigos(c: Awaited<ReturnType<typeof lerCodigos>>) {
  return {
    para_vender: c.aVenda,
    livres: c.livres,
    entregues: c.entregues,
    esperando_codigo: c.esperando,
    guardados_para_pre_venda: c.reservados,
    situacao: c.situacao,
    avisar_com: c.avisarCom,
    lista: c.codigos.slice(0, 100).map((x) => ({ codigo_id: x.id, codigo: x.mascarado, situacao: x.situacao, cliente: x.cliente, pedido: x.pedido })),
  };
}

export const verCodigosDoProduto: FerramentaDeLeitura = {
  nome: "ver_codigos_do_produto",
  titulo: "Ver os códigos de um produto",
  descricao: "Código ou licença: quantos códigos sobram para vender, quantos foram entregues, quem espera código e a lista (mascarada, como na tela) com o codigo_id de cada um.",
  campos: { produto_id: { tipo: "id", descricao: "Id do produto de código ou licença.", obrigatorio: true } },
  tipo: "leitura",
  permissoes: ["digital.products.read"],
  async executar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.read", "ver os produtos digitais");
    const codigos = await naRota(() => lerCodigos(contexto.admin, contexto.lojaId, String(args.produto_id)));
    return { dados: { codigos: resumoDosCodigos(codigos) }, resumo: `Consultou os códigos de um produto (${codigos.livres} livres)` };
  },
};

/* ------------------------------------------------------------ criar e alterar */

type CargaDaFicha = { produtoId: string | null; tipo: string; nome: string | null; ficha: FichaPronta };

export const criarProdutoDigitalFerramenta: FerramentaDeEscrita<CargaDaFicha> = {
  nome: "criar_produto_digital",
  titulo: "Criar um produto digital",
  descricao:
    "Cria um produto digital como rascunho (fora da loja até publicar_produto_digital). Tipos: conteudo_em_video (área de membros com módulos e vídeos; nasce com o módulo \"Boas-vindas\"), arquivos (para baixar), link (de acesso) e codigo (código ou licença). Live se cria com criar_live. Já dá para mandar a ficha junto (preço, capa, descrição, página de venda...).",
  campos: {
    tipo: { tipo: "opcao", descricao: "O tipo do produto (não muda depois).", opcoes: TIPOS_QUE_CRIA, obrigatorio: true },
    ...CAMPOS_DA_FICHA,
  },
  tipo: "escrita",
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "criar produtos digitais");
    const tipo = TIPO_DA_ROTA[args.tipo as (typeof TIPOS_QUE_CRIA)[number]];
    const ficha = await lerFicha(ctx, contexto, args, null, tipo);
    delete ficha.corpo.nome;
    return {
      previa: { tipo: args.tipo, nome: args.nome ?? "(nome padrão)", ...ficha.previa, fica: "fora da loja (rascunho)" },
      resumo: `Prévia de produto digital novo (${args.tipo})`,
      avisos: [],
      carga: { produtoId: null, tipo, nome: (args.nome as string | undefined) ?? null, ficha },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "criar produtos digitais");
    const criado = await naRota(() => criarProdutoDigital(contexto, { tipo: carga.tipo, nome: carga.nome }));
    const corpo = await gravarImagensDaFicha(ctx, carga.ficha);
    let aviso: string | null = null;
    if (Object.keys(corpo).length) {
      try {
        await naRota(() => salvarProdutoDigital(contexto, criado.id, corpo, pedidoDoAssistente(ctx)));
      } catch (erro) {
        aviso = `O produto foi criado, mas parte da ficha não foi salva: ${erro instanceof Error ? erro.message : "erro"}. Corrija com alterar_produto_digital.`;
      }
    }
    const lido = await lerProduto(ctx, contexto, criado.id);
    return {
      dados: {
        produto: produtoParaOAssistente(lido),
        ...(aviso ? { aviso } : {}),
        proximo_passo:
          carga.tipo === "curso"
            ? "Monte os módulos e vídeos (criar_modulo, adicionar_video_ao_conteudo) e publique com publicar_produto_digital quando a pessoa pedir."
            : carga.tipo === "codigo"
              ? "Coloque os códigos com adicionar_codigos e publique com publicar_produto_digital quando a pessoa pedir."
              : "Diga o que o comprador recebe com adicionar_item_ao_produto e publique com publicar_produto_digital quando a pessoa pedir.",
      },
      resumo: `Criou o produto digital ${lido.produto.nome}`,
    };
  },
};

export const alterarProdutoDigital: FerramentaDeEscrita<CargaDaFicha> = {
  nome: "alterar_produto_digital",
  titulo: "Alterar um produto digital",
  descricao:
    "Muda a ficha de um produto digital, em qualquer detalhe da tela: nome, descrição, preço, capa, frase, perguntas, licença, prazo de acesso, amostras, sob encomenda, pré-venda, downloads, marca no PDF, aviso de códigos, campos do comprador e, no conteúdo em vídeo, a página de venda (o que vai ver, quem apresenta, vídeo de apresentação, garantia, certificado). Mande só o que muda. Mudar o preço de produto que está na loja pede confirmação.",
  campos: { produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true }, ...CAMPOS_DA_FICHA },
  tipo: "escrita",
  sobrescreve: true,
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    if (lido.produto.tipo === "live") recusar("Este produto é uma live: use alterar_live.");
    const ficha = await lerFicha(ctx, contexto, args, lido.produto, lido.produto.tipo);
    if (!Object.keys(ficha.corpo).length && !ficha.capa) recusar("Nada para mudar: mande ao menos um campo.");
    const sensivel = mudaPrecoNaLoja({ naLoja: lido.produto.naLoja, precoAtual: lido.produto.preco, precoNovo: args.preco as number | undefined });
    return {
      previa: { produto: lido.produto.nome, ...(sensivel ? { preco_antes: reais(lido.produto.preco) } : {}), ...ficha.previa },
      resumo: `Prévia da mudança no produto digital ${lido.produto.nome}`,
      avisos: sensivel ? ["O produto está na loja: o preço novo vale para as próximas compras assim que confirmar."] : [],
      sensivel,
      carga: { produtoId: lido.produto.id, tipo: lido.produto.tipo, nome: null, ficha },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const corpo = await gravarImagensDaFicha(ctx, carga.ficha);
    await naRota(() => salvarProdutoDigital(contexto, carga.produtoId!, corpo, pedidoDoAssistente(ctx)));
    const lido = await lerProduto(ctx, contexto, carga.produtoId!);
    return { dados: { produto: produtoParaOAssistente(lido) }, resumo: `Alterou o produto digital ${lido.produto.nome}` };
  },
};

type CargaDePublicar = { produtoId: string; naLoja: boolean; nome: string };

export const publicarProdutoDigital: FerramentaDeEscrita<CargaDePublicar> = {
  nome: "publicar_produto_digital",
  titulo: "Pôr ou tirar um produto digital da loja",
  descricao:
    "Põe o produto digital na loja virtual (na_loja = true) ou tira (false). Para pôr, confere antes o que falta, como a tela (capa, o que o comprador recebe, arquivos prontos, códigos, vídeos prontos) e devolve a lista. Quem já comprou continua com acesso ao tirar. Só publique quando a pessoa pedir.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    na_loja: { tipo: "booleano", descricao: "true = na loja; false = fora da loja.", obrigatorio: true },
  },
  tipo: "escrita",
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "publicar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    if (lido.produto.tipo === "live") recusar("Este produto é uma live: use alterar_live com na_loja.");
    return {
      previa: { produto: lido.produto.nome, na_loja: args.na_loja === true },
      resumo: `Prévia de ${args.na_loja ? "publicar" : "tirar da loja"} ${lido.produto.nome}`,
      avisos: [],
      carga: { produtoId: lido.produto.id, naLoja: args.na_loja === true, nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "publicar produtos digitais");
    await naRota(() => salvarProdutoDigital(contexto, carga.produtoId, { naLoja: carga.naLoja }, pedidoDoAssistente(ctx)));
    const lido = await lerProduto(ctx, contexto, carga.produtoId);
    return {
      dados: { produto: lido.produto.nome, na_loja: lido.produto.naLoja, link_na_loja: lido.produto.enderecoNaLoja },
      resumo: `${carga.naLoja ? "Publicou na loja" : "Tirou da loja"} o produto digital ${carga.nome}`,
    };
  },
};

export const apagarProdutoDigitalFerramenta: FerramentaDeEscrita<CargaDePublicar> = {
  nome: "apagar_produto_digital",
  titulo: "Apagar um produto digital",
  descricao:
    "Apaga um produto digital que nunca vendeu nem deu acesso a ninguém (como a tela). Produto com compra ou acesso não some: tire da loja com publicar_produto_digital. Sempre pede confirmação.",
  campos: { produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true } },
  tipo: "escrita",
  sobrescreve: true,
  sensivel: true,
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "apagar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    if (lido.produto.tipo === "live") recusar("Este produto é uma live: para tirar, use cancelar_live.");
    if (lido.produto.vendas > 0 || lido.numeros.comAcesso > 0) {
      recusar("Este produto já tem quem comprou ou recebeu acesso, e ele continua valendo. Tire da loja (publicar_produto_digital com na_loja false) em vez de apagar.");
    }
    return {
      previa: { apagar: lido.produto.nome, tipo: lido.produto.rotuloDoTipo, na_loja: lido.produto.naLoja },
      resumo: `Prévia de apagar o produto digital ${lido.produto.nome}`,
      avisos: ["Apagar não tem volta. Os arquivos continuam na biblioteca (Arquivos e espaço)."],
      carga: { produtoId: lido.produto.id, naLoja: false, nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "apagar produtos digitais");
    await naRota(() => apagarProdutoDigital(contexto, carga.produtoId, pedidoDoAssistente(ctx)));
    return { dados: { apagado: carga.nome }, resumo: `Apagou o produto digital ${carga.nome}` };
  },
};

/* ------------------------------------------------------------ o que o comprador recebe */

type CargaDoItem = { produtoId: string; itemId: string | null; corpo: Record<string, unknown>; nome: string };

export const adicionarItemAoProduto: FerramentaDeEscrita<CargaDoItem> = {
  nome: "adicionar_item_ao_produto",
  titulo: "Acrescentar o que o comprador recebe",
  descricao:
    "Produtos de arquivos e de link: acrescenta um item ao que o comprador recebe — um arquivo da biblioteca (id de listar_arquivos_digitais ou \"envio:...\" de pedir_arquivo_digital/pedir_video), um link de acesso (com instruções) ou um texto. Até 20 itens.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    tipo: { tipo: "opcao", descricao: "arquivo, link ou texto.", opcoes: ["arquivo", "link", "texto"], obrigatorio: true },
    titulo: { tipo: "texto", descricao: "Nome do item (padrão: o nome do arquivo, \"Link de acesso\" ou \"Instruções\").", max: 160 },
    descricao: { tipo: "texto", descricao: "Uma linha sobre o item (aparece em \"O que você recebe\").", max: 1000 },
    arquivo: { tipo: "texto", descricao: "Tipo arquivo: o id do arquivo na biblioteca ou o código \"envio:...\".", max: 200 },
    link: { tipo: "texto", descricao: "Tipo link: o endereço que o comprador recebe (https://...).", max: 2000 },
    instrucoes: { tipo: "texto", descricao: "Tipo link: como usar o link. Tipo texto: o texto que o comprador recebe.", max: 4000 },
  },
  tipo: "escrita",
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    const corpo: Record<string, unknown> = { tipo: args.tipo, titulo: args.titulo, descricao: args.descricao };
    if (args.tipo === "arquivo") {
      if (!args.arquivo) recusar("Diga o arquivo (id da biblioteca ou \"envio:...\").");
      const arquivo = await arquivoIndicado(ctx, contexto, args.arquivo);
      corpo.fileId = arquivo.id;
    } else if (args.tipo === "link") {
      if (!args.link) recusar("Diga o link que o comprador recebe.");
      corpo.url = args.link;
      corpo.instrucoes = args.instrucoes;
    } else {
      corpo.instrucoes = args.instrucoes;
    }
    semContatoNovo("", `${args.titulo ?? ""}\n${args.descricao ?? ""}\n${args.tipo === "texto" ? args.instrucoes ?? "" : ""}`, "no produto digital, em O que o comprador recebe");
    return {
      previa: { produto: lido.produto.nome, item: corpo },
      resumo: `Prévia de item novo em ${lido.produto.nome}`,
      avisos: [],
      carga: { produtoId: lido.produto.id, itemId: null, corpo, nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const feito = await naRota(() => adicionarEntregavel(contexto, carga.produtoId, carga.corpo, pedidoDoAssistente(ctx)));
    return { dados: { item_id: feito.id, produto: carga.nome }, resumo: `Acrescentou um item ao produto digital ${carga.nome}` };
  },
};

export const alterarItemDoProduto: FerramentaDeEscrita<CargaDoItem> = {
  nome: "alterar_item_do_produto",
  titulo: "Mudar um item do que o comprador recebe",
  descricao: "Muda um item do que o comprador recebe: título, descrição, link, texto/instruções, ligado ou desligado, ou sobe/desce na lista. O item_id vem de ver_produto_digital.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    item_id: { tipo: "id", descricao: "Id do item.", obrigatorio: true },
    titulo: { tipo: "texto", descricao: "Novo nome.", max: 160 },
    descricao: { tipo: "texto", descricao: "Nova descrição.", max: 1000 },
    link: { tipo: "texto", descricao: "Novo link (só item de link).", max: 2000 },
    instrucoes: { tipo: "texto", descricao: "Novo texto/instruções (item de link ou de texto).", max: 4000 },
    ligado: { tipo: "booleano", descricao: "false = o item some para as compras novas." },
    mover: { tipo: "opcao", descricao: "Subir ou descer na lista.", opcoes: ["cima", "baixo"] },
  },
  tipo: "escrita",
  sobrescreve: true,
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    const item = lido.entregaveis.find((e) => e.id === args.item_id);
    if (!item) recusar("Esse item não está no produto. Veja os itens em ver_produto_digital.");
    const corpo: Record<string, unknown> = {};
    if (args.titulo !== undefined) corpo.titulo = args.titulo;
    if (args.descricao !== undefined) corpo.descricao = args.descricao;
    if (args.link !== undefined) corpo.url = args.link;
    if (args.instrucoes !== undefined) corpo.instrucoes = args.instrucoes;
    if (args.ligado !== undefined) corpo.ativo = args.ligado;
    if (args.mover !== undefined) corpo.mover = args.mover;
    if (!Object.keys(corpo).length) recusar("Nada para mudar.");
    semContatoNovo(`${item.titulo}\n${item.descricao ?? ""}\n${item.instrucoes ?? ""}`, `${args.titulo ?? item.titulo}\n${args.descricao ?? item.descricao ?? ""}\n${args.instrucoes ?? item.instrucoes ?? ""}`, "no produto digital");
    return {
      previa: { produto: lido.produto.nome, item: item.titulo, mudancas: corpo },
      resumo: `Prévia da mudança num item de ${lido.produto.nome}`,
      avisos: [],
      carga: { produtoId: lido.produto.id, itemId: item.id, corpo, nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    await naRota(() => alterarEntregavel(contexto, carga.produtoId, carga.itemId!, carga.corpo, pedidoDoAssistente(ctx)));
    return { dados: { item_id: carga.itemId, alterado: true }, resumo: `Mudou um item do produto digital ${carga.nome}` };
  },
};

export const tirarItemDoProduto: FerramentaDeEscrita<CargaDoItem> = {
  nome: "tirar_item_do_produto",
  titulo: "Tirar um item do que o comprador recebe",
  descricao:
    "Tira um item do que o comprador recebe. Quem já comprou continua recebendo (o item some só para as compras novas); sem compra nenhuma, ele sai de vez. O arquivo continua na biblioteca. Sempre pede confirmação.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    item_id: { tipo: "id", descricao: "Id do item (de ver_produto_digital).", obrigatorio: true },
  },
  tipo: "escrita",
  sobrescreve: true,
  sensivel: true,
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    const item = lido.entregaveis.find((e) => e.id === args.item_id);
    if (!item) recusar("Esse item não está no produto. Veja os itens em ver_produto_digital.");
    return {
      previa: { produto: lido.produto.nome, tirar: item.titulo, tipo: item.tipo },
      resumo: `Prévia de tirar um item de ${lido.produto.nome}`,
      avisos: ["Quem já comprou continua recebendo este item."],
      carga: { produtoId: lido.produto.id, itemId: item.id, corpo: {}, nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const feito = await naRota(() => tirarEntregavel(contexto, carga.produtoId, carga.itemId!, pedidoDoAssistente(ctx)));
    return { dados: { tirado: true, compradores_mantidos: feito.compradoresMantidos }, resumo: `Tirou um item do produto digital ${carga.nome}` };
  },
};

/* ------------------------------------------------------------ códigos */

type CargaDosCodigos = { produtoId: string; texto: string; nome: string };

export const adicionarCodigos: FerramentaDeEscrita<CargaDosCodigos> = {
  nome: "adicionar_codigos",
  titulo: "Acrescentar códigos ou licenças",
  descricao:
    "Código ou licença: acrescenta códigos (um por linha; até o limite da tela por vez). Repetidos são ignorados. Se há compradores esperando código, eles recebem na hora (por e-mail) — por isso pede confirmação nesse caso.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto de código ou licença.", obrigatorio: true },
    codigos: { tipo: "texto", descricao: "Os códigos, um por linha.", obrigatorio: true, max: 200000 },
  },
  tipo: "escrita",
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const atuais = await naRota(() => lerCodigos(contexto.admin, contexto.lojaId, String(args.produto_id)));
    const lido = await lerProduto(ctx, contexto, String(args.produto_id));
    const linhas = String(args.codigos).split(/\r?\n/).filter((l) => l.trim()).length;
    const esperando = atuais.esperando;
    return {
      previa: { produto: lido.produto.nome, codigos_mandados: linhas, compradores_esperando: esperando },
      resumo: `Prévia de ${contagem(linhas, "código", "códigos")} em ${lido.produto.nome}`,
      avisos: esperando ? [`${contagem(esperando, "comprador recebe", "compradores recebem")} o código por e-mail assim que confirmar.`] : [],
      sensivel: esperando > 0,
      carga: { produtoId: lido.produto.id, texto: String(args.codigos), nome: lido.produto.nome },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const feito = await naRota(() => adicionarCodigosAoProduto(contexto, carga.produtoId, { texto: carga.texto }, pedidoDoAssistente(ctx)));
    return {
      dados: { adicionados: feito.adicionados, repetidos: feito.repetidos, grandes_demais: feito.grandesDemais, entregues_a_quem_esperava: feito.entregues },
      resumo: `Acrescentou ${contagem(feito.adicionados, "código", "códigos")} em ${carga.nome}`,
    };
  },
};

type CargaDoCodigo = { produtoId: string; codigoId: string; mascarado: string };

export const tirarCodigo: FerramentaDeEscrita<CargaDoCodigo> = {
  nome: "tirar_codigo",
  titulo: "Tirar um código ainda não entregue",
  descricao: "Tira um código que ainda não foi entregue (o entregue fica guardado). O codigo_id vem de ver_codigos_do_produto. Sempre pede confirmação.",
  campos: {
    produto_id: { tipo: "id", descricao: "Id do produto.", obrigatorio: true },
    codigo_id: { tipo: "id", descricao: "Id do código.", obrigatorio: true },
  },
  tipo: "escrita",
  sobrescreve: true,
  sensivel: true,
  permissoes: ["digital.products.write"],
  async preparar(ctx, args) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    const codigos = await naRota(() => lerCodigos(contexto.admin, contexto.lojaId, String(args.produto_id)));
    const codigo = codigos.codigos.find((c) => c.id === args.codigo_id);
    if (!codigo) recusar("Código não encontrado nos últimos 300 deste produto. Veja ver_codigos_do_produto.");
    if (codigo.situacao === "entregue") recusar("Este código já foi entregue a um comprador e fica guardado.");
    return {
      previa: { tirar_codigo: codigo.mascarado },
      resumo: "Prévia de tirar um código",
      avisos: [],
      carga: { produtoId: String(args.produto_id), codigoId: codigo.id, mascarado: codigo.mascarado },
    };
  },
  async gravar(ctx, carga) {
    const contexto = await abrirDigital(ctx, "digital.products.write", "alterar produtos digitais");
    await naRota(() => apagarCodigo(contexto.admin, { lojaId: contexto.lojaId, produtoId: carga.produtoId, codigoId: carga.codigoId }));
    return { dados: { tirado: carga.mascarado }, resumo: "Tirou um código de um produto digital" };
  },
};

export const FERRAMENTAS_DE_PRODUTOS_DIGITAIS: Ferramenta[] = [
  listarProdutosDigitaisFerramenta,
  verProdutoDigital,
  verCodigosDoProduto,
  criarProdutoDigitalFerramenta,
  alterarProdutoDigital,
  publicarProdutoDigital,
  apagarProdutoDigitalFerramenta,
  adicionarItemAoProduto,
  alterarItemDoProduto,
  tirarItemDoProduto,
  adicionarCodigos,
  tirarCodigo,
] as Ferramenta[];
