CREATE TABLE IF NOT EXISTS supplier_media_resources (
    id                    BIGSERIAL PRIMARY KEY,
    supplier              VARCHAR(32) NOT NULL,
    supplier_resource_id  VARCHAR(64) NOT NULL,
    model_id              INT NOT NULL,
    name                  VARCHAR(500) NOT NULL,
    status                VARCHAR(32) NOT NULL DEFAULT 'unknown',
    cost_price_cents      BIGINT NOT NULL DEFAULT 0,
    cost_prices_json      JSONB NOT NULL DEFAULT '{}'::jsonb,
    sale_price_label      VARCHAR(64),
    resource_url          TEXT,
    baidu_weight          INT,
    resource_remark       TEXT,
    customer_visible      BOOLEAN NOT NULL DEFAULT TRUE,
    channel_type          VARCHAR(128),
    region                VARCHAR(128),
    inclusion_effect      VARCHAR(128),
    link_type             VARCHAR(128),
    publish_rate          VARCHAR(64),
    delivery_speed        VARCHAR(128),
    supplier_updated_at   TIMESTAMPTZ,
    last_synced_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    raw_json              JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at            TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at            TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at            TIMESTAMPTZ,
    CONSTRAINT uk_supplier_media_resources_supplier_id UNIQUE (supplier, supplier_resource_id)
);

CREATE INDEX IF NOT EXISTS idx_supplier_media_resources_model_status
    ON supplier_media_resources (supplier, model_id, status, updated_at DESC);

CREATE INDEX IF NOT EXISTS idx_supplier_media_resources_name_trgm_fallback
    ON supplier_media_resources (supplier, name);

CREATE TABLE IF NOT EXISTS supplier_media_price_overrides (
    id                    BIGSERIAL PRIMARY KEY,
    resource_id            BIGINT NOT NULL REFERENCES supplier_media_resources(id) ON DELETE CASCADE,
    price_type             VARCHAR(64) NOT NULL DEFAULT 'price',
    sell_price_cents       BIGINT NOT NULL,
    enabled                BOOLEAN NOT NULL DEFAULT TRUE,
    updated_by             BIGINT REFERENCES users(id),
    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_supplier_media_price_override_non_negative CHECK (sell_price_cents >= 0),
    CONSTRAINT uk_supplier_media_price_overrides_resource_type UNIQUE (resource_id, price_type)
);

CREATE INDEX IF NOT EXISTS idx_supplier_media_price_overrides_resource
    ON supplier_media_price_overrides (resource_id, enabled);

CREATE TABLE IF NOT EXISTS media_supply_user_wallets (
    tenant_id              BIGINT NOT NULL REFERENCES tenants(id),
    user_id                BIGINT NOT NULL REFERENCES users(id),
    balance_cents          BIGINT NOT NULL DEFAULT 0,
    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (tenant_id, user_id),
    CONSTRAINT chk_media_supply_user_wallet_balance_non_negative CHECK (balance_cents >= 0)
);

CREATE TABLE IF NOT EXISTS media_supply_orders (
    id                     BIGSERIAL PRIMARY KEY,
    tenant_id              BIGINT NOT NULL REFERENCES tenants(id),
    workspace_id           BIGINT NOT NULL REFERENCES workspaces(id),
    brand_id               BIGINT NOT NULL REFERENCES brands(id),
    user_id                BIGINT NOT NULL REFERENCES users(id),
    article_id             BIGINT REFERENCES articles(id),
    supplier               VARCHAR(32) NOT NULL,
    model_id               INT NOT NULL,
    status                 VARCHAR(32) NOT NULL DEFAULT 'queued',
    title                  VARCHAR(500) NOT NULL,
    content_snapshot       TEXT NOT NULL,
    remark                 TEXT,
    order_brand            VARCHAR(255),
    external_order_id      VARCHAR(128),
    external_order_code    VARCHAR(128),
    supplier_status        VARCHAR(64),
    cost_total_cents       BIGINT NOT NULL DEFAULT 0,
    sell_total_cents       BIGINT NOT NULL DEFAULT 0,
    wallet_debit_cents     BIGINT NOT NULL DEFAULT 0,
    wallet_debited_at      TIMESTAMPTZ,
    wallet_refunded_at     TIMESTAMPTZ,
    request_payload_json   JSONB NOT NULL DEFAULT '{}'::jsonb,
    response_payload_json  JSONB,
    error_message          TEXT,
    attempt_count          INT NOT NULL DEFAULT 0,
    next_attempt_at        TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    queued_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    submitted_at           TIMESTAMPTZ,
    completed_at           TIMESTAMPTZ,
    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at             TIMESTAMPTZ,
    CONSTRAINT chk_media_supply_order_totals_non_negative CHECK (cost_total_cents >= 0 AND sell_total_cents >= 0),
    CONSTRAINT chk_media_supply_order_no_loss CHECK (sell_total_cents >= cost_total_cents),
    CONSTRAINT chk_media_supply_order_wallet_debit_non_negative CHECK (wallet_debit_cents >= 0)
);

CREATE INDEX IF NOT EXISTS idx_media_supply_orders_user_created
    ON media_supply_orders (tenant_id, user_id, created_at DESC)
    WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_media_supply_orders_status_next
    ON media_supply_orders (supplier, status, next_attempt_at, created_at)
    WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_media_supply_orders_article
    ON media_supply_orders (tenant_id, article_id, created_at DESC)
    WHERE article_id IS NOT NULL AND deleted_at IS NULL;

CREATE TABLE IF NOT EXISTS media_supply_order_items (
    id                       BIGSERIAL PRIMARY KEY,
    order_id                 BIGINT NOT NULL REFERENCES media_supply_orders(id) ON DELETE CASCADE,
    resource_id              BIGINT NOT NULL REFERENCES supplier_media_resources(id),
    supplier_resource_id     VARCHAR(64) NOT NULL,
    price_type               VARCHAR(64) NOT NULL DEFAULT 'price',
    resource_name_snapshot   VARCHAR(500) NOT NULL,
    locked_cost_price_cents  BIGINT NOT NULL,
    locked_sell_price_cents  BIGINT NOT NULL,
    status                   VARCHAR(32) NOT NULL DEFAULT 'queued',
    external_article_url     TEXT,
    raw_json                 JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at               TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at               TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_media_supply_order_item_prices_non_negative CHECK (locked_cost_price_cents >= 0 AND locked_sell_price_cents >= 0),
    CONSTRAINT chk_media_supply_order_item_no_loss CHECK (locked_sell_price_cents >= locked_cost_price_cents)
);

CREATE INDEX IF NOT EXISTS idx_media_supply_order_items_order
    ON media_supply_order_items (order_id, id);

CREATE TABLE IF NOT EXISTS media_supply_wallet_ledgers (
    id                     BIGSERIAL PRIMARY KEY,
    tenant_id              BIGINT NOT NULL REFERENCES tenants(id),
    user_id                BIGINT NOT NULL REFERENCES users(id),
    order_id               BIGINT REFERENCES media_supply_orders(id) ON DELETE SET NULL,
    delta_cents            BIGINT NOT NULL,
    balance_after_cents    BIGINT NOT NULL,
    reason                 VARCHAR(128) NOT NULL,
    note                   TEXT,
    created_by             BIGINT REFERENCES users(id),
    created_at             TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT chk_media_supply_wallet_ledger_balance_non_negative CHECK (balance_after_cents >= 0)
);

CREATE INDEX IF NOT EXISTS idx_media_supply_wallet_ledgers_user_created
    ON media_supply_wallet_ledgers (tenant_id, user_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_media_supply_wallet_ledgers_user_recent
    ON media_supply_wallet_ledgers (tenant_id, user_id, created_at DESC, id DESC);

CREATE INDEX IF NOT EXISTS idx_media_supply_wallet_ledgers_order
    ON media_supply_wallet_ledgers (order_id)
    WHERE order_id IS NOT NULL;

CREATE TABLE IF NOT EXISTS media_supply_sync_jobs (
    id                    BIGSERIAL PRIMARY KEY,
    supplier              VARCHAR(32) NOT NULL,
    model_id              INT,
    status                VARCHAR(32) NOT NULL DEFAULT 'queued',
    requested_by          BIGINT REFERENCES users(id),
    started_at            TIMESTAMPTZ,
    finished_at           TIMESTAMPTZ,
    error_message         TEXT,
    attempt_count         INT NOT NULL DEFAULT 0,
    stats_json            JSONB NOT NULL DEFAULT '{}'::jsonb,
    created_at            TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at            TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_media_supply_sync_jobs_status_created
    ON media_supply_sync_jobs (supplier, status, created_at);
