-- =====================================================================
-- Install Etapa 1 — schema base do f19 OPERACIONAL (w19_clikil41_eleicao)
-- Projeto: f19
-- Data:    2026-05-27 (Ciclo 02, ajustado pós-decisões Sr. Diplomata)
--
-- 7 TABELAS (sem tb_access — ela vive em w19_clikil41_main; sem tb_log_query
-- — logs ficam só em log.w19.com.br/<categoria>/YYYY-MM.jsonl).
--
-- IDEMPOTENTE: CREATE TABLE IF NOT EXISTS + INSERT ON DUPLICATE KEY UPDATE.
-- Funciona em phpMyAdmin Importar OU mysql CLI.
--
-- Ordem por dependências:
--   1. tb_adm_user            (sem FK p/ tb_access — cross-DB, validado na app)
--   2. tb_detail              (catálogo de tipos de detalhe, sem seed)
--   3. tb_adm_user_detail     (FK -> tb_adm_user + tb_detail)
--   4. tb_campaign            (sem FK)
--   5. tb_campaign_adm_user   (FK -> tb_campaign + tb_adm_user)
--   6. tb_api                 (FK -> tb_adm_user)
--   7. tb_campaign_api        (FK -> tb_campaign + tb_api)
-- =====================================================================

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;


-- ===== tb_adm_user =====
-- =====================================================================
-- Tabela: tb_adm_user
-- Banco:  w19_clikil41_eleicao (operacional)
-- Projeto: f19
--
-- Escopo: SÓ pessoas com login/acesso ao painel adm (admin, manager,
-- candidate, supporter). Pessoas em geral (eleitores, leads do WhatsApp)
-- ficam em tb_contact (ciclo futuro).
--
-- Sem endereço aqui — vai em tb_adm_user_detail (EAV via tb_detail).
-- Sem id_campaign — vínculo com campanha vai em tb_campaign_adm_user
-- (N:M com papel local por campanha).
--
-- id_access referencia tb_access em w19_clikil41_main (banco diferente —
-- NÃO há CONSTRAINT FK; integridade validada na aplicação).
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_adm_user` (
  `id_adm_user`            BIGINT UNSIGNED  NOT NULL AUTO_INCREMENT,
  `id_access`              TINYINT UNSIGNED NOT NULL DEFAULT 4,         -- soft-ref -> w19_clikil41_main.tb_access (1..4)

  -- Identidade
  `adm_user_name`          VARCHAR(150)     NOT NULL,
  `adm_user_email`         VARCHAR(150)     NOT NULL,
  `adm_user_cpf`           VARCHAR(14)      DEFAULT NULL,                -- '000.000.000-00'
  `adm_user_whatsapp`      VARCHAR(20)      DEFAULT NULL,                -- '+55 (00) 0.0000-0000'
  `adm_user_password_hash` VARCHAR(255)     NOT NULL,                    -- password_hash() PHP (NUNCA plaintext)
  `adm_user_photo_url`     VARCHAR(500)     DEFAULT NULL,

  -- Controle / auditoria mínima
  `adm_user_status`        TINYINT(1)       NOT NULL DEFAULT 1,          -- 1 ativo, 0 inativo, -1 bloqueado
  `adm_user_register_ip`   VARCHAR(45)      DEFAULT NULL,
  `adm_user_last_login_ip` VARCHAR(45)      DEFAULT NULL,
  `adm_user_last_login_at` DATETIME         DEFAULT NULL,
  `adm_user_created_at`    DATETIME         NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `adm_user_updated_at`    DATETIME         NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_adm_user`),
  UNIQUE KEY `uk_adm_user_email` (`adm_user_email`),
  UNIQUE KEY `uk_adm_user_cpf`   (`adm_user_cpf`),
  KEY `ix_adm_user_status` (`adm_user_status`),
  KEY `ix_adm_user_access` (`id_access`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_detail =====
-- =====================================================================
-- Tabela: tb_detail (catálogo de tipos de detalhe — EAV)
-- Projeto: f19 — banco w19_clikil41_eleicao
--
-- Catálogo compartilhado dos tipos de "detalhe extra" que podem
-- pendurar em qualquer entidade (user agora; contact/campaign no futuro).
-- Inspirado em tb_form_field do Cliki, mas simplificado (sem tb_form
-- intermediário — valor liga direto detail ↔ entidade via tb_<X>_detail).
--
-- Sem seed agora (decisão 2026-05-27 #5) — adicionamos sob demanda
-- conforme as features pedirem.
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_detail` (
  `id_detail`         SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,

  -- Identidade do tipo
  `detail_slug`       VARCHAR(60)  NOT NULL,           -- chave técnica em inglês: 'address_zipcode', 'social_instagram', 'phone_secondary'
  `detail_label`      VARCHAR(100) NOT NULL,           -- label exibido em UI (pt-BR): 'CEP', 'Instagram', 'Telefone secundário'
  `detail_category`   VARCHAR(40)  NOT NULL,           -- agrupador: 'address','contact','social','personal','custom'

  -- Comportamento de UI (espelho enxuto de tb_form_field do Cliki)
  `detail_data_type`  ENUM('string','text','url','phone','email','date','number','json') NOT NULL DEFAULT 'string',
  `detail_placeholder` VARCHAR(200) DEFAULT NULL,      -- texto exibido no input vazio
  `detail_mask`       VARCHAR(50)  DEFAULT NULL,       -- máscara JS: 'phone','cpf','cnpj','cep','date',...
  `detail_options`    JSON         DEFAULT NULL,       -- pra data_type='string' com lista fixa (vira select): ['op1','op2',...]
  `detail_required`   TINYINT(1)   NOT NULL DEFAULT 0,

  -- Operação
  `detail_order`      SMALLINT     NOT NULL DEFAULT 0, -- ordem na UI (dentro da categoria)
  `detail_status`     TINYINT(1)   NOT NULL DEFAULT 1, -- soft-disable
  `detail_created_at` DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `detail_updated_at` DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_detail`),
  UNIQUE KEY `uk_detail_slug` (`detail_slug`),
  KEY `ix_detail_category` (`detail_category`),
  KEY `ix_detail_status`   (`detail_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_adm_user_detail =====
-- =====================================================================
-- Tabela: tb_adm_user_detail (valor de detalhe por adm_user — EAV)
-- Banco:  w19_clikil41_eleicao (operacional)
-- Projeto: f19
--
-- Ponte entre tb_adm_user e tb_detail. Cada linha = 1 valor de 1 tipo
-- de detalhe pra 1 adm_user. UNIQUE (id_adm_user, id_detail) — pra
-- múltiplos valores do mesmo tipo (ex: 2 telefones secundários), criar
-- variantes no catálogo tb_detail (phone_secondary_1, phone_secondary_2).
--
-- No futuro tb_contact_detail seguirá o mesmo padrão usando o mesmo
-- catálogo tb_detail (compartilhado entre adm_user e contact).
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_adm_user_detail` (
  `id_adm_user_detail`         BIGINT UNSIGNED   NOT NULL AUTO_INCREMENT,
  `id_adm_user`                BIGINT UNSIGNED   NOT NULL,
  `id_detail`                  SMALLINT UNSIGNED NOT NULL,

  `adm_user_detail_value`      TEXT              DEFAULT NULL,   -- valor literal (qualquer tipo serializado como string;
                                                                  -- JSON quando tb_detail.detail_data_type='json')
  `adm_user_detail_status`     TINYINT(1)        NOT NULL DEFAULT 1,
  `adm_user_detail_created_at` DATETIME          NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `adm_user_detail_updated_at` DATETIME          NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_adm_user_detail`),
  UNIQUE KEY `uk_aud_pair`   (`id_adm_user`,`id_detail`),
  KEY `ix_aud_user`   (`id_adm_user`),
  KEY `ix_aud_detail` (`id_detail`),
  CONSTRAINT `fk_aud_user`   FOREIGN KEY (`id_adm_user`) REFERENCES `tb_adm_user` (`id_adm_user`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_aud_detail` FOREIGN KEY (`id_detail`)   REFERENCES `tb_detail`   (`id_detail`)   ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_campaign =====
-- =====================================================================
-- Tabela: tb_campaign
-- Projeto: f19 — banco w19_clikil41_eleicao
--
-- Cada linha = uma campanha eleitoral. Vínculo com candidato/manager/
-- supporter vai por tb_campaign_user (com id_access local por campanha).
--
-- Campos mínimos por enquanto — ALTER TABLE depois se precisar
-- (slogan, vice, coligação, estado/cidade, datas de janela, etc).
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_campaign` (
  `id_campaign`           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,

  -- Identidade
  `campaign_name`         VARCHAR(100)    NOT NULL,                  -- "André Aguiar"
  `campaign_slug`         VARCHAR(120)    NOT NULL,                  -- "andre-aguiar-deputado-2026"
  `campaign_office`       VARCHAR(60)     NOT NULL,                  -- "Deputado Federal", "Senador", "Vereador", "Prefeito"
  `campaign_party_abbr`   VARCHAR(10)     NOT NULL,                  -- "PSDB" (futura FK para tb_metadata_party)
  `campaign_party_number` VARCHAR(10)     NOT NULL,                  -- "4523" (número de urna)
  `campaign_year`         SMALLINT UNSIGNED NOT NULL,                 -- 2026

  -- Branding básico (override do default do tema)
  `campaign_color_hex`    CHAR(7)         NOT NULL DEFAULT '#ff0079',
  `campaign_photo_url`    VARCHAR(500)    DEFAULT NULL,              -- foto do candidato

  -- Operação
  `campaign_status`       TINYINT(1)      NOT NULL DEFAULT 1,        -- 1 ativa, 0 pausada, -1 arquivada
  `campaign_created_at`   DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `campaign_updated_at`   DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_campaign`),
  UNIQUE KEY `uk_campaign_slug` (`campaign_slug`),
  KEY `ix_campaign_status` (`campaign_status`),
  KEY `ix_campaign_year`   (`campaign_year`),
  KEY `ix_campaign_party`  (`campaign_party_abbr`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_campaign_adm_user =====
-- =====================================================================
-- Tabela: tb_campaign_adm_user (adm_user <-> campanha, N:M com papel)
-- Banco:  w19_clikil41_eleicao (operacional)
-- Projeto: f19
--
-- Sustenta:
--   - candidato dono da campanha (id_access=3 na linha)
--   - gerentes atribuídos (id_access=2)
--   - apoiadores da campanha (id_access=4)
--   - admins do sistema operando uma campanha específica (id_access=1)
--
-- Permite: 1 adm_user em N campanhas com papéis distintos.
--
-- REGRA DE NEGÓCIO (validada na camada de aplicação, NÃO no schema):
--   Exatamente 1 candidato ATIVO por campanha:
--     SELECT COUNT(*) FROM tb_campaign_adm_user
--      WHERE id_campaign=? AND id_access=3 AND campaign_adm_user_status=1
--   deve = 1.
--
-- id_access referencia tb_access em w19_clikil41_main (cross-DB, sem FK).
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_campaign_adm_user` (
  `id_campaign_adm_user`         BIGINT UNSIGNED  NOT NULL AUTO_INCREMENT,
  `id_campaign`                  BIGINT UNSIGNED  NOT NULL,
  `id_adm_user`                  BIGINT UNSIGNED  NOT NULL,
  `id_access`                    TINYINT UNSIGNED NOT NULL,                 -- papel NESTA campanha (1..4); pode diferir de tb_adm_user.id_access

  `campaign_adm_user_status`     TINYINT(1)       NOT NULL DEFAULT 1,        -- 1 ativo, 0 desligado
  `campaign_adm_user_joined_at`  DATETIME         NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `campaign_adm_user_left_at`    DATETIME         DEFAULT NULL,

  PRIMARY KEY (`id_campaign_adm_user`),
  UNIQUE KEY `uk_cau_pair`     (`id_campaign`,`id_adm_user`),
  KEY `ix_cau_campaign` (`id_campaign`),
  KEY `ix_cau_user`     (`id_adm_user`),
  KEY `ix_cau_access`   (`id_access`),
  KEY `ix_cau_status`   (`campaign_adm_user_status`),
  CONSTRAINT `fk_cau_campaign` FOREIGN KEY (`id_campaign`) REFERENCES `tb_campaign` (`id_campaign`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_cau_user`     FOREIGN KEY (`id_adm_user`) REFERENCES `tb_adm_user` (`id_adm_user`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_api =====
-- =====================================================================
-- Tabela: tb_api
-- Projeto: f19 — banco w19_clikil41_eleicao
--
-- Pool de instâncias/tokens de serviços externos (Z-API, Claude, ChatGPT,
-- RapidAPI, Meta, Sendflow, gateways de pagamento, etc).
--
-- Vínculo com campanha vai por tb_campaign_api (N:M com priority).
-- Permite: 1 instância usada por N campanhas (token Claude global) OU
-- 1 instância dedicada a 1 campanha (Z-API do apoiador).
--
-- CRIPTOGRAFIA dos tokens (decisão 2026-05-27): api_token_primary e
-- api_token_secondary armazenam o ciphertext AES-256-GCM produzido por
-- helper PHP fn_api_secret.php (usa APP_CRYPT_KEY do bootstrap). NUNCA
-- gravar plaintext nem fazer SELECT direto destes campos no app —
-- sempre via fn_api_get_token(id_api, 'primary'|'secondary').
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_api` (
  `id_api`               BIGINT UNSIGNED  NOT NULL AUTO_INCREMENT,
  `id_adm_user_owner`    BIGINT UNSIGNED  DEFAULT NULL,                 -- FK -> tb_adm_user. Apoiador dono da instância (ex: Z-API dedicada).
                                                                        -- NULL = instância GLOBAL (token Claude compartilhado).

  -- Identidade
  `api_service`          VARCHAR(40)      NOT NULL,                     -- 'zapi','claude','chatgpt','rapid','meta','sendflow','stripe',...
  `api_label`            VARCHAR(150)     NOT NULL,                     -- "Z-API Apoiador #123 principal", "Claude Sonnet 4.7 global"
  `api_environment`      VARCHAR(20)      NOT NULL DEFAULT 'prod',       -- 'dev','staging','prod'

  -- Credenciais (CRIPTOGRAFADAS — ver header). Comprimento sobrado pro
  -- ciphertext + IV + tag base64 caber.
  `api_instance_id`      VARCHAR(150)     DEFAULT NULL,                  -- ID externo da instância (Z-API entrega esse). Sem criptografia (é ID, não segredo).
  `api_token_primary`    VARCHAR(800)     NOT NULL,                     -- ciphertext: token principal (z-api: instance_token)
  `api_token_secondary`  VARCHAR(800)     DEFAULT NULL,                  -- ciphertext: token secundário (z-api: client_token)
  `api_endpoint_url`     VARCHAR(500)     DEFAULT NULL,                  -- URL base custom
  `api_webhook_url`      VARCHAR(500)     DEFAULT NULL,                  -- URL pra qual o serviço envia callbacks (ex: hook.w19.com.br/zapi/enviar.php)

  -- Metadados livres (campos específicos do serviço)
  `api_meta`             JSON             DEFAULT NULL,                  -- ex: {phone:"+5511...", connected:true, account_id:"..."}

  -- Operação
  `api_status`           TINYINT(1)       NOT NULL DEFAULT 1,            -- 1 ativa, 0 pausada, -1 expirada/revogada
  `api_health`           ENUM('ok','warn','down','unknown') NOT NULL DEFAULT 'unknown',
  `api_last_used_at`     DATETIME         DEFAULT NULL,
  `api_last_check_at`    DATETIME         DEFAULT NULL,
  `api_created_at`       DATETIME         NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `api_updated_at`       DATETIME         NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_api`),
  KEY `ix_api_service` (`api_service`),
  KEY `ix_api_owner`   (`id_adm_user_owner`),
  KEY `ix_api_status`  (`api_status`),
  CONSTRAINT `fk_api_adm_user_owner` FOREIGN KEY (`id_adm_user_owner`) REFERENCES `tb_adm_user` (`id_adm_user`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ===== tb_campaign_api =====
-- =====================================================================
-- Tabela: tb_campaign_api (campanha <-> instância de api, N:M com priority)
-- Projeto: f19 — banco w19_clikil41_eleicao
--
-- Permite:
--   - 1 Z-API por apoiador → instância DEDICADA (1 row ligando à
--     campanha do apoiador)
--   - 1 token Claude/ChatGPT global → COMPARTILHADO (1 row em tb_api
--     ligado a N campanhas via N rows aqui)
-- =====================================================================

CREATE TABLE IF NOT EXISTS `tb_campaign_api` (
  `id_campaign_api`         BIGINT UNSIGNED  NOT NULL AUTO_INCREMENT,
  `id_campaign`             BIGINT UNSIGNED  NOT NULL,
  `id_api`                  BIGINT UNSIGNED  NOT NULL,

  `campaign_api_label`      VARCHAR(150)     DEFAULT NULL,            -- override do api_label neste contexto
  `campaign_api_priority`   TINYINT(1)       NOT NULL DEFAULT 0,       -- 0 normal, 1 preferida (desempate quando há 2+ instâncias do mesmo serviço)
  `campaign_api_status`     TINYINT(1)       NOT NULL DEFAULT 1,
  `campaign_api_assigned_at` DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (`id_campaign_api`),
  UNIQUE KEY `uk_ca_pair` (`id_campaign`,`id_api`),
  KEY `ix_ca_campaign` (`id_campaign`),
  KEY `ix_ca_api`      (`id_api`),
  KEY `ix_ca_status`   (`campaign_api_status`),
  CONSTRAINT `fk_ca_campaign` FOREIGN KEY (`id_campaign`) REFERENCES `tb_campaign` (`id_campaign`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_ca_api`      FOREIGN KEY (`id_api`)      REFERENCES `tb_api`      (`id_api`)      ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- =====================================================================
-- SEED: 4 usuários iniciais + campanha modelo "André Aguiar"
-- Senha padrão pros 3 logins de teste: 123456 (bcrypt cost 10).
-- TROCAR ANTES DE PRODUÇÃO REAL.
-- =====================================================================

INSERT INTO `tb_adm_user`
  (`id_adm_user`, `id_access`, `adm_user_name`, `adm_user_email`, `adm_user_password_hash`, `adm_user_status`)
VALUES
  -- Candidato MODELO/DEMO (id=1) — sempre presente como referência comercial
  (1, 3, 'André Aguiar',         'andre@andreaguiar.w19.com.br',
   '$2y$10$yMJrv4j4zrIs0PjcSi7lJu8mGaEO4rq.7ZHp4hxNsaOzoEm0Cdehy', 1),
  -- Logins de teste (senha = 123456)
  (2, 1, 'Administrador (demo)', 'adm@cliki.com.br',
   '$2y$10$yMJrv4j4zrIs0PjcSi7lJu8mGaEO4rq.7ZHp4hxNsaOzoEm0Cdehy', 1),
  (3, 2, 'Gerente (demo)',       'manager@cliki.com.br',
   '$2y$10$yMJrv4j4zrIs0PjcSi7lJu8mGaEO4rq.7ZHp4hxNsaOzoEm0Cdehy', 1),
  (4, 3, 'Candidato (demo)',     'candidato@cliki.com.br',
   '$2y$10$yMJrv4j4zrIs0PjcSi7lJu8mGaEO4rq.7ZHp4hxNsaOzoEm0Cdehy', 1),
  (5, 4, 'Apoiador (demo)',      'apoiador@cliki.com.br',
   '$2y$10$yMJrv4j4zrIs0PjcSi7lJu8mGaEO4rq.7ZHp4hxNsaOzoEm0Cdehy', 1)
ON DUPLICATE KEY UPDATE
  `adm_user_name`          = VALUES(`adm_user_name`),
  `id_access`              = VALUES(`id_access`),
  `adm_user_password_hash` = VALUES(`adm_user_password_hash`),
  `adm_user_status`        = VALUES(`adm_user_status`);

INSERT INTO `tb_campaign`
  (`id_campaign`, `campaign_name`, `campaign_slug`, `campaign_office`,
   `campaign_party_abbr`, `campaign_party_number`, `campaign_year`,
   `campaign_color_hex`, `campaign_photo_url`, `campaign_status`)
VALUES
  (1, 'André Aguiar', 'andre-aguiar-deputado-2026',
   'Deputado Federal', 'PSDB', '4523', 2026,
   '#ff0079',
   'https://global.w19.com.br/content/uploads/perfil/andre0aguiar.jpg', 1)
ON DUPLICATE KEY UPDATE
  `campaign_name` = VALUES(`campaign_name`);

INSERT INTO `tb_campaign_adm_user`
  (`id_campaign_adm_user`, `id_campaign`, `id_adm_user`, `id_access`, `campaign_adm_user_status`)
VALUES
  (1, 1, 1, 3, 1)
ON DUPLICATE KEY UPDATE
  `id_access` = VALUES(`id_access`);
