-- Migración: PTC (Paid-To-Click). TODO en UTC. USD en DECIMAL(14,6) (micropagos, sin fuga por
-- redondeo). La aritmética de dinero se hace con shared/utils/decimal.js (BigInt 8 decimales):
-- todos los valores del modelo son exactos a <= 6 decimales, así que se guardan sin pérdida.

-- Billetera USD del anunciante (Ad Balance). VÍA DE UN SOLO SENTIDO: se fondea SOLO por depósito
-- externo y NO se retira ni se convierte a cripto. Separada del balance cripto del faucet.
ALTER TABLE `users`
  ADD COLUMN IF NOT EXISTS `ad_balance_usd` DECIMAL(14,6) NOT NULL DEFAULT 0;

-- Propósito del depósito: 'upgrade' (boost de recompensa, lo actual) o 'ad_balance' (recarga la
-- billetera USD para anuncios). Default 'upgrade' => las órdenes viejas quedan intactas y
-- applyPendingDepositsForUser sigue mandándolas al upgrade.
ALTER TABLE `deposit_orders`
  ADD COLUMN IF NOT EXISTS `purpose` VARCHAR(20) NOT NULL DEFAULT 'upgrade';

-- Campañas de anuncios. La DURACIÓN es INMUTABLE (amarra el costo por impresión pagado); el
-- unit_cost y el reward del viewer se congelan al crear para que un cambio de config no altere
-- retroactivamente la economía que el anunciante ya pagó.
CREATE TABLE IF NOT EXISTS `ptc_campaigns` (
  `id`                BIGINT        NOT NULL AUTO_INCREMENT,
  `advertiser_id`     VARCHAR(191)  NOT NULL,             -- users.id (coin_type:email)
  `title`             VARCHAR(255)  NOT NULL,
  `description`       VARCHAR(1024) NOT NULL DEFAULT '',
  `target_url`        VARCHAR(2048) NOT NULL,
  `duration_seconds`  INT           NOT NULL,             -- INMUTABLE
  `unit_cost_usd`     DECIMAL(14,6) NOT NULL,             -- costo por impresión (según duración)
  `reward_usd`        DECIMAL(14,6) NOT NULL,             -- lo que cobra el viewer (share del unit)
  `budget_usd`        DECIMAL(14,6) NOT NULL DEFAULT 0,   -- total inyectado acumulado (auditoría)
  `impressions_total` INT           NOT NULL DEFAULT 0,   -- impresiones compradas (budget/unit)
  `impressions_used`  INT           NOT NULL DEFAULT 0,   -- impresiones ya cobradas (definitivas)
  `status`            VARCHAR(20)   NOT NULL DEFAULT 'inactive',
  `version`           BIGINT        NOT NULL DEFAULT 0,   -- optimistic locking (igual que users)
  `created_at`        DATETIME(3)   NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `funded_at`         DATETIME(3)   NULL,                 -- primera vez que se fondeó/activó
  `updated_at`        DATETIME(3)   NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
                        ON UPDATE CURRENT_TIMESTAMP(3),

  PRIMARY KEY (`id`),
  KEY `idx_ptc_advertiser` (`advertiser_id`),
  KEY `idx_ptc_status_duration` (`status`, `duration_seconds`),  -- tabla pública: filtrar+ordenar
  KEY `idx_ptc_cleanup` (`status`, `created_at`),                -- limpieza lazy de inactivas 24h
  CONSTRAINT `chk_ptc_status` CHECK (`status` IN ('inactive','active','paused','depleted')),
  CONSTRAINT `chk_ptc_impressions` CHECK (`impressions_used` <= `impressions_total`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Escrow de impresiones EN BD (no en memoria): al pulsar "Start" se reserva el puesto mientras
-- corre el timer. Las impresiones disponibles = total - used - (reservas vivas). Una reserva
-- vencida (expires_at <= NOW()) se ignora y se borra de forma perezosa al leerla: si el server
-- reinicia o hay varias instancias, nada se descuadra (la impresión vuelve sola al pozo).
CREATE TABLE IF NOT EXISTS `ptc_reservations` (
  `id`           VARCHAR(191)  NOT NULL,               -- token opaco de la reserva
  `campaign_id`  BIGINT        NOT NULL,
  `viewer_id`    VARCHAR(191)  NOT NULL,               -- users.id
  `day_key`      CHAR(10)      NOT NULL,               -- YYYY-MM-DD (UTC) del inicio
  `started_at`   DATETIME(3)   NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
  `expires_at`   DATETIME(3)   NOT NULL,               -- started_at + duración + gracia

  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_ptc_resv_pair` (`campaign_id`, `viewer_id`),  -- una reserva viva por par
  KEY `idx_ptc_resv_campaign` (`campaign_id`),
  KEY `idx_ptc_resv_expires` (`expires_at`)                    -- liberación perezosa por vencidas
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Vistas cobradas (dinero que SALE al viewer). El UNIQUE(campaign,viewer,day) es a la vez el
-- candado anti-doble-cobro (un segundo claim choca 1062 y se rechaza SIN pagar) y la fuente del
-- "una vez al día / desaparece": la tabla pública excluye lo que el viewer ya cobró hoy.
CREATE TABLE IF NOT EXISTS `ptc_views` (
  `id`           BIGINT        NOT NULL AUTO_INCREMENT,
  `campaign_id`  BIGINT        NOT NULL,
  `viewer_id`    VARCHAR(191)  NOT NULL,
  `day_key`      CHAR(10)      NOT NULL,               -- YYYY-MM-DD (UTC)
  `reward_usd`   DECIMAL(14,6) NOT NULL,               -- USD pagado (auditoría)
  `reward_coin`  DECIMAL(30,8) NOT NULL,               -- cripto acreditada al viewer (auditoría)
  `created_at`   DATETIME(3)   NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_ptc_view_daily` (`campaign_id`, `viewer_id`, `day_key`),  -- once/day + idempotencia
  KEY `idx_ptc_view_viewer_day` (`viewer_id`, `day_key`),  -- filtro "ya visto hoy" en la tabla
  KEY `idx_ptc_view_campaign` (`campaign_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
