-- 0032 — prompts prontos: o menu de perguntas do assistente
--
-- O PROBLEMA
--
-- O widget hoje e um campo em branco. Quem conhece o dado escreve "quanto
-- faturamos por empresa nos ultimos 3 meses" e recebe um grafico; quem nao
-- conhece olha o campo, nao sabe o que pedir, e fecha. A pergunta certa e o
-- conhecimento que o cliente NAO tem -- e e justamente o que a operacao dele
-- repete toda semana.
--
-- Um catalogo de perguntas prontas, apresentado como MENU, transforma isso: o
-- usuario reconhece "Faturamento nos ultimos 3 meses" numa lista, clica, e a
-- pergunta vai. Nao ha o que aprender.
--
--
-- A CAMADA E A AUSENCIA DE PROJETO -- COMO EM 0019, 0021 E 0023
--
--   project_id = 7      o prompt e do projeto 7
--   project_id IS NULL  o prompt e do TENANT, herdado por todos os projetos
--
-- E o mesmo desenho dos context servers, e pelo mesmo motivo: um ERP
-- multi-empresa faz as MESMAS perguntas em todos os clientes dele. "Contas a
-- pagar vencidas" nao muda de empresa para empresa -- muda o dado, nao a
-- pergunta. Sem a camada do tenant, cadastrar 40 itens de menu em 33 projetos
-- daria 1.320 linhas para manter sincronizadas a mao, e a primeira correcao de
-- texto ja sairia divergente.
--
-- tenant_id entra NOT NULL porque e A BARREIRA, nao conveniencia: a leitura com
-- heranca pergunta "os prompts deste projeto MAIS os do tenant dele", e sem a
-- coluna a segunda metade precisaria de um JOIN com projects em toda consulta.
-- Alguem escreveria a versao sem o JOIN, e o menu de um cliente mostraria a
-- pergunta de outro -- que aqui vaza VOCABULARIO DE NEGOCIO ("Comissao de
-- representante por regiao" diz o que a operacao do vizinho controla).
--
--
-- POR QUE O GRUPO E UMA STRING, E NAO UMA TABELA
--
-- O menu tem dois niveis -- "Relatorios" > "Faturamento" -- e a tentacao e
-- criar embed_prompt_groups com FK. Nao vale, e o proprio produto ja decidiu
-- isso uma vez: `group` no envelope de dataset e uma string, e o grupo nasce na
-- primeira ocorrencia.
--
-- Uma tabela de grupos obrigaria a duplicar TODA a sutileza da heranca --
-- camada, sobrescrita por nome, opt-out -- numa entidade que nao tem
-- comportamento nenhum: um grupo e um rotulo. Pior, criaria estados que nao
-- significam nada (grupo do tenant vazio porque o unico item foi sobrescrito no
-- projeto) e a pergunta "quem manda no rotulo" em toda tela.
--
-- Com string, o grupo e derivado: agrupa por group_label, e a ORDEM dos grupos
-- sai do menor `position` de cada um. Renomear um grupo e um UPDATE numa
-- coluna; mover um item entre grupos tambem. Nada disso precisa de FK.
--
--
-- SOBRESCRITA POR (grupo, rotulo)
--
-- A UNIQUE e (tenant_id, scope_project_id, group_label, label), sobre a coluna
-- GERADA que troca NULL por 0 -- em InnoDB um indice UNIQUE aceita qualquer
-- numero de linhas com NULL, entao a camada do tenant seria a unica SEM
-- garantia, exatamente a que mais precisa dela (ver 0021, que explica isso por
-- extenso).
--
-- Duas linhas com o mesmo (grupo, rotulo) em camadas diferentes NAO sao
-- colisao: sao SOBRESCRITA. O projeto que cadastra "Relatorios" > "Faturamento"
-- passa a responder por aquele item ali, e o do tenant segue valendo para os
-- demais projetos. E como se diz "neste cliente, faturamento se pergunta
-- diferente" sem tocar no de ninguem.
--
--
-- POR QUE OPT-OUT E TABELA, E NAO A COLUNA `enabled`
--
-- `enabled` e propriedade da LINHA: desligar o item do tenant o desliga para
-- todos os 33 clientes. Um cliente que nao deve ver "Impostos" -- porque a
-- contabilidade dele e externa -- precisaria, sem uma saida, de uma copia do
-- item so para desliga-la. Que e a duplicacao que esta tabela existe para
-- eliminar.
--
-- Quem desliga e o PAR (projeto, prompt), e por isso e tabela de ligacao. A
-- ausencia de linha e o estado normal (herdado nasce visivel, que e o ponto da
-- heranca); a presenca e a excecao explicita, com data.
--
--
-- O QUE ESTA TABELA NAO GUARDA
--
-- Nao guarda resposta, nao guarda cache, nao guarda historico de uso. Um prompt
-- pronto e TEXTO que vai para o campo de pergunta -- o mesmo caminho de uma
-- pergunta digitada, com o mesmo limite de perguntas, a mesma cobranca e a
-- mesma auditoria. Um atalho que pulasse o laco do agente seria uma segunda
-- porta para os dados, com outras regras.

CREATE TABLE embed_prompts (
  id             BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

  -- A barreira. Primeira condicao de todo WHERE, inclusive na leitura herdada.
  tenant_id      BIGINT UNSIGNED NOT NULL,

  -- NULL = camada do TENANT, herdada por todos os projetos.
  project_id     BIGINT UNSIGNED NULL,

  -- Existe para a UNIQUE alcancar a camada do tenant. VIRTUAL: nao ocupa espaco.
  scope_project_id BIGINT UNSIGNED
    GENERATED ALWAYS AS (COALESCE(project_id, 0)) VIRTUAL,

  -- O primeiro nivel do menu: "Relatorios", "Graficos". String de proposito.
  group_label    VARCHAR(120) NOT NULL,

  -- O segundo nivel, o que se clica: "Faturamento nos ultimos 3 meses".
  label          VARCHAR(160) NOT NULL,

  -- A pergunta que sai daqui e entra no campo, igual a uma digitada.
  prompt         TEXT NOT NULL,

  -- Uma linha de explicacao, mostrada como dica ao passar o mouse. Um rotulo de
  -- menu tem oito palavras; as vezes a pergunta precisa de mais para nao
  -- prometer o que nao entrega.
  hint           VARCHAR(255) NULL,

  -- Ordem DENTRO do grupo. A ordem dos GRUPOS e derivada do menor position de
  -- cada um -- sem coluna propria, porque grupo e rotulo e nao entidade.
  position       INT NOT NULL DEFAULT 0,

  -- Desliga a linha, nas duas camadas. Para esconder um HERDADO em um projeto
  -- so, o instrumento e embed_prompt_optouts.
  enabled        TINYINT(1) NOT NULL DEFAULT 1,

  created_at     DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at     DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (id),

  -- As duas camadas protegidas pela MESMA chave. Ver o cabecalho.
  UNIQUE KEY uq_embed_prompts_camada (tenant_id, scope_project_id, group_label, label),

  -- A FK para projects precisa de um indice comecando por project_id, e a
  -- UNIQUE acima nem menciona a coluna (usa a gerada).
  KEY idx_embed_prompts_project (project_id),

  -- Serve a leitura do menu: tenant + camada + ligados, na ordem de exibicao.
  KEY idx_embed_prompts_menu (tenant_id, project_id, enabled, position),

  CONSTRAINT fk_embed_prompts_tenant  FOREIGN KEY (tenant_id)  REFERENCES tenants(id),
  CONSTRAINT fk_embed_prompts_project FOREIGN KEY (project_id) REFERENCES projects(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Esconder um prompt HERDADO em um projeto so, sem apagar para os outros.
CREATE TABLE embed_prompt_optouts (
  id          BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  project_id  BIGINT UNSIGNED NOT NULL,
  prompt_id   BIGINT UNSIGNED NOT NULL,
  created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (id),
  UNIQUE KEY uq_embed_prompt_optouts (project_id, prompt_id),
  KEY idx_embed_prompt_optouts_prompt (prompt_id),

  CONSTRAINT fk_embed_prompt_optouts_project FOREIGN KEY (project_id)
    REFERENCES projects(id),
  -- CASCADE: apagado o prompt do tenant, o opt-out dele nao significa mais nada.
  CONSTRAINT fk_embed_prompt_optouts_prompt FOREIGN KEY (prompt_id)
    REFERENCES embed_prompts(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
