-- +goose Up
-- Server-driven advertising banner ("advertising network"): operator-managed campaigns rotated in
-- the client's one-line announcement strip. A campaign is one placement order with a show weight
-- (percent); simultaneously active campaigns compete for shows in proportion to their weights. The
-- single perpetual default campaign fills the unsold remainder up to 100%. Each campaign carries
-- one or more bilingual messages (en + ru, both mandatory), shown by the viewer's bot (service)
-- language. Display timings are global (one settings row). Eligibility (who sees a banner at all)
-- reuses account fields + the no_banner role, so it needs no schema here. See docs/ARCHITECTURE.md
-- and internal/ads.
SET search_path = backend, pg_catalog;

-- One advertising campaign = one placement order. weight is the show percentage (1..100). is_default
-- marks the single perpetual house campaign that fills the remainder up to 100% and is never deleted;
-- it has no validity window (its stored weight is nominal — the rotation derives its effective weight
-- as max(0, 100 - sum of active timed weights)). A time-limited campaign is active while now() lies in
-- [starts_at, ends_at] (a null bound is open-ended on that side). enabled toggles a campaign without
-- deleting it.
CREATE TABLE ad_campaigns (
    campaign_id uuid        PRIMARY KEY,
    name        text        NOT NULL,
    weight      integer     NOT NULL,
    is_default  boolean     NOT NULL DEFAULT false,
    enabled     boolean     NOT NULL DEFAULT true,
    starts_at   timestamptz,
    ends_at     timestamptz,
    created_at  timestamptz NOT NULL DEFAULT now(),
    updated_at  timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT ad_campaigns_weight_chk CHECK (weight BETWEEN 1 AND 100),
    -- The default campaign is perpetual (no window).
    CONSTRAINT ad_campaigns_default_window_chk CHECK (NOT is_default OR (starts_at IS NULL AND ends_at IS NULL)),
    -- A closed window must not be inverted.
    CONSTRAINT ad_campaigns_window_chk CHECK (starts_at IS NULL OR ends_at IS NULL OR starts_at <= ends_at)
);
-- At most one default campaign.
CREATE UNIQUE INDEX ad_campaigns_default_idx ON ad_campaigns (is_default) WHERE is_default;

-- One bilingual message of a campaign. Both languages are mandatory: the client shows the variant for
-- the viewer's bot (service) language. position orders the messages within a campaign (the round-robin
-- order when the campaign wins a display slot). body_* is minimal markdown (text + links).
CREATE TABLE ad_messages (
    message_id  uuid        PRIMARY KEY,
    campaign_id uuid        NOT NULL REFERENCES ad_campaigns (campaign_id) ON DELETE CASCADE,
    position    integer     NOT NULL DEFAULT 0,
    body_en     text        NOT NULL,
    body_ru     text        NOT NULL,
    created_at  timestamptz NOT NULL DEFAULT now(),
    updated_at  timestamptz NOT NULL DEFAULT now()
);
-- Messages of a campaign are read in display order.
CREATE INDEX ad_messages_campaign_idx ON ad_messages (campaign_id, position);

-- Global banner display timings, a single row (id is always TRUE). The client rotator reads these:
-- hold_ms is how long one message shows; edge_pause_ms and scroll_px_per_sec drive the scroll of a
-- message wider than the strip; the transition between messages is fade_out_ms -> gap_ms -> fade_in_ms.
-- All are clamped in Go on update.
CREATE TABLE ad_settings (
    id                boolean     PRIMARY KEY DEFAULT true,
    hold_ms           integer     NOT NULL,
    edge_pause_ms     integer     NOT NULL,
    scroll_px_per_sec integer     NOT NULL,
    fade_out_ms       integer     NOT NULL,
    gap_ms            integer     NOT NULL,
    fade_in_ms        integer     NOT NULL,
    updated_at        timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT ad_settings_singleton_chk CHECK (id)
);

-- Seed the perpetual default campaign with one bilingual house message, and the default timings
-- (the previous hardcoded UI defaults plus the new fade sequence). Fixed UUIDs keep the seed
-- deterministic across environments.
INSERT INTO ad_campaigns (campaign_id, name, weight, is_default, enabled)
VALUES ('00000000-0000-0000-0000-0000000000ad', 'Default (house)', 100, true, true);
INSERT INTO ad_messages (message_id, campaign_id, position, body_en, body_ru)
VALUES (
    '00000000-0000-0000-0000-0000000000a1', '00000000-0000-0000-0000-0000000000ad', 0,
    'Tip: a play using all 7 tiles earns a +50 bonus.',
    'Совет: ход всеми 7 фишками приносит бонус +50 очков.'
);
INSERT INTO ad_settings (id, hold_ms, edge_pause_ms, scroll_px_per_sec, fade_out_ms, gap_ms, fade_in_ms)
VALUES (true, 60000, 5000, 40, 1000, 250, 1000);

-- +goose Down
SET search_path = backend, pg_catalog;
DROP TABLE IF EXISTS ad_settings;
DROP TABLE IF EXISTS ad_messages;
DROP TABLE IF EXISTS ad_campaigns;
