-- Supply domain schema (PostgreSQL 15)
-- Single executable DDL source for supply_* tables.
-- Updated: 2026-03-25

BEGIN;

CREATE TABLE IF NOT EXISTS supply_accounts (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    user_id BIGINT NOT NULL,
    platform VARCHAR(50) NOT NULL,
    account_type VARCHAR(20) NOT NULL CHECK (account_type IN ('api_key', 'oauth')),
    account_name VARCHAR(100),
    encrypted_credentials TEXT NOT NULL,
    key_id VARCHAR(100),
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'active', 'suspended', 'disabled')),
    risk_level VARCHAR(20) NOT NULL DEFAULT 'normal'
        CHECK (risk_level IN ('low', 'normal', 'high')),
    total_quota NUMERIC(20, 6),
    available_quota NUMERIC(20, 6),
    frozen_quota NUMERIC(20, 6) DEFAULT 0,
    is_verified BOOLEAN DEFAULT FALSE,
    verified_at TIMESTAMPTZ,
    last_check_at TIMESTAMPTZ,
    tos_compliant BOOLEAN DEFAULT TRUE,
    tos_check_result TEXT,
    total_requests BIGINT DEFAULT 0,
    total_tokens BIGINT DEFAULT 0,
    total_cost NUMERIC(20, 6) DEFAULT 0,
    success_rate NUMERIC(5, 2) DEFAULT 0,
    risk_score INT DEFAULT 0,
    risk_reason TEXT,
    is_frozen BOOLEAN DEFAULT FALSE,
    frozen_reason TEXT,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by BIGINT,
    updated_by BIGINT
);

CREATE INDEX IF NOT EXISTS idx_supply_accounts_user_id ON supply_accounts (user_id);
CREATE INDEX IF NOT EXISTS idx_supply_accounts_platform ON supply_accounts (platform);
CREATE INDEX IF NOT EXISTS idx_supply_accounts_status ON supply_accounts (status);
CREATE INDEX IF NOT EXISTS idx_supply_accounts_risk_level ON supply_accounts (risk_level);

CREATE TABLE IF NOT EXISTS supply_packages (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    supply_account_id BIGINT NOT NULL REFERENCES supply_accounts(id),
    user_id BIGINT NOT NULL,
    platform VARCHAR(50) NOT NULL,
    model VARCHAR(100) NOT NULL,
    total_quota NUMERIC(20, 6) NOT NULL,
    available_quota NUMERIC(20, 6) NOT NULL,
    sold_quota NUMERIC(20, 6) DEFAULT 0,
    reserved_quota NUMERIC(20, 6) DEFAULT 0,
    price_per_1m_input NUMERIC(20, 6),
    price_per_1m_output NUMERIC(20, 6),
    min_purchase NUMERIC(20, 6),
    start_at TIMESTAMPTZ,
    end_at TIMESTAMPTZ,
    valid_days INT,
    status VARCHAR(20) NOT NULL DEFAULT 'draft'
        CHECK (status IN ('draft', 'active', 'paused', 'sold_out', 'expired')),
    max_concurrent INT DEFAULT 10,
    rate_limit_rpm INT DEFAULT 60,
    total_orders INT DEFAULT 0,
    total_revenue NUMERIC(20, 6) DEFAULT 0,
    rating NUMERIC(3, 2) DEFAULT 0,
    rating_count INT DEFAULT 0,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_supply_packages_supply_account_id ON supply_packages (supply_account_id);
CREATE INDEX IF NOT EXISTS idx_supply_packages_user_id ON supply_packages (user_id);
CREATE INDEX IF NOT EXISTS idx_supply_packages_platform_model ON supply_packages (platform, model);
CREATE INDEX IF NOT EXISTS idx_supply_packages_status ON supply_packages (status);

CREATE TABLE IF NOT EXISTS supply_orders (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    order_no VARCHAR(64) NOT NULL UNIQUE,
    buyer_user_id BIGINT NOT NULL,
    buyer_team_id BIGINT,
    supply_account_id BIGINT NOT NULL REFERENCES supply_accounts(id),
    supplier_user_id BIGINT NOT NULL,
    supply_package_id BIGINT NOT NULL REFERENCES supply_packages(id),
    platform VARCHAR(50) NOT NULL,
    model VARCHAR(100) NOT NULL,
    quota_amount NUMERIC(20, 6) NOT NULL,
    quota_tokens BIGINT,
    unit_price NUMERIC(20, 6) NOT NULL,
    total_amount NUMERIC(20, 6) NOT NULL,
    platform_fee NUMERIC(20, 6) NOT NULL,
    supplier_earnings NUMERIC(20, 6) NOT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'paid', 'using', 'expired', 'refunded')),
    used_quota NUMERIC(20, 6) DEFAULT 0,
    remaining_quota NUMERIC(20, 6),
    expired_at TIMESTAMPTZ,
    payment_method VARCHAR(20),
    paid_at TIMESTAMPTZ,
    payment_transaction_id VARCHAR(100),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_supply_orders_buyer_user_id ON supply_orders (buyer_user_id);
CREATE INDEX IF NOT EXISTS idx_supply_orders_supplier_user_id ON supply_orders (supplier_user_id);
CREATE INDEX IF NOT EXISTS idx_supply_orders_supply_package_id ON supply_orders (supply_package_id);
CREATE INDEX IF NOT EXISTS idx_supply_orders_status ON supply_orders (status);

CREATE TABLE IF NOT EXISTS supply_usage_records (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    order_id BIGINT NOT NULL REFERENCES supply_orders(id),
    buyer_user_id BIGINT NOT NULL,
    supply_account_id BIGINT NOT NULL REFERENCES supply_accounts(id),
    supplier_user_id BIGINT NOT NULL,
    request_id VARCHAR(64) NOT NULL,
    upstream_request_id VARCHAR(128),
    api_key_id BIGINT,
    platform VARCHAR(50) NOT NULL,
    model VARCHAR(100) NOT NULL,
    endpoint VARCHAR(100) NOT NULL,
    request_tokens BIGINT,
    response_tokens BIGINT,
    total_tokens BIGINT GENERATED ALWAYS AS (COALESCE(request_tokens, 0) + COALESCE(response_tokens, 0)) STORED,
    input_cost NUMERIC(20, 6),
    output_cost NUMERIC(20, 6),
    total_cost NUMERIC(20, 6) NOT NULL,
    unit_price NUMERIC(20, 6) NOT NULL,
    response_status INT,
    latency_ms INT,
    error_message TEXT,
    success BOOLEAN DEFAULT TRUE,
    started_at TIMESTAMPTZ NOT NULL,
    completed_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_supply_usage_records_request_id ON supply_usage_records (request_id);
CREATE INDEX IF NOT EXISTS idx_supply_usage_records_order_id ON supply_usage_records (order_id);
CREATE INDEX IF NOT EXISTS idx_supply_usage_records_supply_account_id ON supply_usage_records (supply_account_id);
CREATE INDEX IF NOT EXISTS idx_supply_usage_records_platform_model ON supply_usage_records (platform, model);
CREATE INDEX IF NOT EXISTS idx_supply_usage_records_started_at ON supply_usage_records (started_at);

CREATE TABLE IF NOT EXISTS supply_earnings (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    user_id BIGINT NOT NULL,
    supply_account_id BIGINT REFERENCES supply_accounts(id),
    order_id BIGINT REFERENCES supply_orders(id),
    usage_record_id BIGINT REFERENCES supply_usage_records(id),
    earnings_type VARCHAR(20) NOT NULL CHECK (earnings_type IN ('usage', 'bonus', 'refund')),
    amount NUMERIC(20, 6) NOT NULL,
    currency VARCHAR(10) DEFAULT 'CNY',
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'available', 'withdrawn', 'frozen')),
    available_amount NUMERIC(20, 6) DEFAULT 0,
    frozen_amount NUMERIC(20, 6) DEFAULT 0,
    withdrawn_amount NUMERIC(20, 6) DEFAULT 0,
    description TEXT,
    earned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    available_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_supply_earnings_user_id ON supply_earnings (user_id);
CREATE INDEX IF NOT EXISTS idx_supply_earnings_status ON supply_earnings (status);
CREATE INDEX IF NOT EXISTS idx_supply_earnings_earned_at ON supply_earnings (earned_at);

CREATE TABLE IF NOT EXISTS supply_settlements (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    settlement_no VARCHAR(64) NOT NULL UNIQUE,
    user_id BIGINT NOT NULL,
    total_amount NUMERIC(20, 6) NOT NULL,
    fee_amount NUMERIC(20, 6) DEFAULT 0,
    net_amount NUMERIC(20, 6) NOT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'processing', 'completed', 'failed')),
    payment_method VARCHAR(20),
    payment_account VARCHAR(100),
    payment_transaction_id VARCHAR(100),
    paid_at TIMESTAMPTZ,
    period_start DATE NOT NULL,
    period_end DATE NOT NULL,
    total_orders INT DEFAULT 0,
    total_usage_records INT DEFAULT 0,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_supply_settlements_user_id ON supply_settlements (user_id);
CREATE INDEX IF NOT EXISTS idx_supply_settlements_status ON supply_settlements (status);
CREATE INDEX IF NOT EXISTS idx_supply_settlements_period ON supply_settlements (period_start, period_end);

COMMIT;
