-- 0026 — conversas salvas do widget
--
-- A sessao do embed dura 30 minutos. A conversa nao pode durar isso: alguem
-- que perguntou o faturamento na terca quer reabrir na quinta e continuar dali,
-- sem reconstruir o contexto todo na mao.
--
-- Por isso a conversa NAO pende da sessao. Ela pende do USUARIO — o end_user
-- que o backend do cliente grava ao emitir o token. Sessoes vao e vem; a
-- conversa fica.
--
-- E por isso end_user e NOT NULL aqui, mesmo sendo opcional na sessao: sem
-- dono nao ha a quem devolver a conversa depois, e uma conversa que ninguem
-- consegue reabrir e so custo de armazenamento. Sessao sem end_user continua
-- funcionando, apenas nao salva — do mesmo jeito que sessao sem e-mail nao
-- oferece envio.

CREATE TABLE embed_conversations (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  tenant_id       BIGINT UNSIGNED NOT NULL,

  -- NULL quando a conversa nasceu numa sessao de alcance TENANT. Nao e
  -- detalhe: uma conversa que atravessou TODAS as empresas NAO pode reaparecer numa
  -- sessao aberta para uma empresa so, e e este campo que decide.
  project_id      BIGINT UNSIGNED NULL,
  scope           VARCHAR(16) NOT NULL DEFAULT 'project',

  -- O dono. Toda leitura filtra por (tenant_id, end_user) antes de qualquer
  -- outra coisa — do mesmo jeito que project_id filtra os dados.
  end_user        VARCHAR(190) NOT NULL,
  end_user_label  VARCHAR(190) NULL,

  -- Derivado da primeira pergunta, e editavel. Uma lista de "Conversa 1,
  -- Conversa 2" nao ajuda ninguem a achar aquela do faturamento de junho.
  title           VARCHAR(180) NOT NULL,

  message_count   INT UNSIGNED NOT NULL DEFAULT 0,
  last_message_at DATETIME NULL,

  -- Sem expurgo automatico: a conversa vive ate o usuario apagar. O expurgo
  -- em massa por usuario existe na CLI, para o dia em que alguem exercer o
  -- direito de apagar os proprios dados.
  deleted_at      DATETIME NULL,

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

  PRIMARY KEY (id),
  -- O indice da unica consulta que importa: "as conversas DESTE usuario, a
  -- mais recente primeiro".
  KEY idx_embed_conv_dono (tenant_id, end_user, deleted_at, last_message_at),
  KEY idx_embed_conv_projeto (project_id),
  CONSTRAINT fk_embed_conv_tenant  FOREIGN KEY (tenant_id)  REFERENCES tenants(id),
  CONSTRAINT fk_embed_conv_project FOREIGN KEY (project_id) REFERENCES projects(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE embed_messages (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  conversation_id BIGINT UNSIGNED NOT NULL,

  -- Redundante com a conversa, e de proposito: toda consulta de mensagem
  -- filtra por tenant tambem. Um erro de join nao pode ser suficiente para
  -- vazar conversa entre clientes.
  tenant_id       BIGINT UNSIGNED NOT NULL,

  role            VARCHAR(16) NOT NULL,
  content         MEDIUMTEXT NOT NULL,

  -- Graficos, tabelas, indicadores e sugestoes, como o widget os desenhou.
  -- Sem isso, reabrir a conversa mostraria "segue o grafico" e nenhum grafico
  -- — o que parece defeito.
  --
  -- As LINHAS dos relatorios ficam de fora: uma resposta tipica pesa 7 KB, e
  -- com um relatorio de 2000 linhas passa de 79 KB. Guarda-se o cabecalho do
  -- relatorio e o widget oferece gerar de novo.
  outputs         JSON NULL,
  tools_used      JSON NULL,

  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (id),
  KEY idx_embed_msg_conversa (conversation_id, id),
  KEY idx_embed_msg_tenant (tenant_id),
  CONSTRAINT fk_embed_msg_conversa FOREIGN KEY (conversation_id)
    REFERENCES embed_conversations(id) ON DELETE CASCADE,
  CONSTRAINT fk_embed_msg_tenant FOREIGN KEY (tenant_id) REFERENCES tenants(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
