-- Migration: Token Aggregation Schema
-- Description: Creates tables for token market data, liquidity pools, OHLCV, and external API cache
-- Supports ChainID 138 and 651940

-- Token Market Data - Aggregated market metrics per token
CREATE TABLE IF NOT EXISTS token_market_data (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    token_address VARCHAR(42) NOT NULL,
    price_usd NUMERIC(30, 8),
    price_change_24h NUMERIC(10, 4),
    volume_24h NUMERIC(30, 8) DEFAULT 0,
    volume_7d NUMERIC(30, 8) DEFAULT 0,
    volume_30d NUMERIC(30, 8) DEFAULT 0,
    market_cap_usd NUMERIC(30, 8),
    liquidity_usd NUMERIC(30, 8) DEFAULT 0,
    holders_count INTEGER DEFAULT 0,
    transfers_24h INTEGER DEFAULT 0,
    last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, token_address)
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS token_market_data_chain_138 PARTITION OF token_market_data FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS token_market_data_chain_651940 PARTITION OF token_market_data FOR VALUES IN (651940);

CREATE INDEX idx_token_market_data_chain_token ON token_market_data(chain_id, token_address);
CREATE INDEX idx_token_market_data_price ON token_market_data(price_usd) WHERE price_usd IS NOT NULL;
CREATE INDEX idx_token_market_data_volume ON token_market_data(volume_24h) WHERE volume_24h > 0;
CREATE INDEX idx_token_market_data_last_updated ON token_market_data(last_updated);

-- Liquidity Pools - DEX pool information
CREATE TABLE IF NOT EXISTS liquidity_pools (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    pool_address VARCHAR(42) NOT NULL,
    token0_address VARCHAR(42) NOT NULL,
    token1_address VARCHAR(42) NOT NULL,
    dex_type VARCHAR(20) NOT NULL CHECK (dex_type IN ('uniswap_v2', 'uniswap_v3', 'dodo', 'custom')),
    factory_address VARCHAR(42),
    router_address VARCHAR(42),
    reserve0 NUMERIC(78, 0) DEFAULT 0,
    reserve1 NUMERIC(78, 0) DEFAULT 0,
    reserve0_usd NUMERIC(30, 8) DEFAULT 0,
    reserve1_usd NUMERIC(30, 8) DEFAULT 0,
    total_liquidity_usd NUMERIC(30, 8) DEFAULT 0,
    volume_24h NUMERIC(30, 8) DEFAULT 0,
    fee_tier INTEGER, -- For UniswapV3 (500, 3000, 10000)
    created_at_block BIGINT,
    created_at_timestamp TIMESTAMP WITH TIME ZONE,
    last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, pool_address)
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS liquidity_pools_chain_138 PARTITION OF liquidity_pools FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS liquidity_pools_chain_651940 PARTITION OF liquidity_pools FOR VALUES IN (651940);

CREATE INDEX idx_liquidity_pools_chain_pool ON liquidity_pools(chain_id, pool_address);
CREATE INDEX idx_liquidity_pools_token0 ON liquidity_pools(chain_id, token0_address);
CREATE INDEX idx_liquidity_pools_token1 ON liquidity_pools(chain_id, token1_address);
CREATE INDEX idx_liquidity_pools_dex_type ON liquidity_pools(chain_id, dex_type);
CREATE INDEX idx_liquidity_pools_tvl ON liquidity_pools(total_liquidity_usd) WHERE total_liquidity_usd > 0;

-- Pool Reserves History - Time-series snapshots of pool reserves
CREATE TABLE IF NOT EXISTS pool_reserves_history (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    pool_address VARCHAR(42) NOT NULL,
    reserve0 NUMERIC(78, 0) NOT NULL,
    reserve1 NUMERIC(78, 0) NOT NULL,
    reserve0_usd NUMERIC(30, 8),
    reserve1_usd NUMERIC(30, 8),
    total_liquidity_usd NUMERIC(30, 8),
    block_number BIGINT NOT NULL,
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS pool_reserves_history_chain_138 PARTITION OF pool_reserves_history FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS pool_reserves_history_chain_651940 PARTITION OF pool_reserves_history FOR VALUES IN (651940);

-- Convert to hypertable for TimescaleDB time-series optimization
SELECT create_hypertable('pool_reserves_history', 'timestamp', 
    chunk_time_interval => INTERVAL '1 day',
    if_not_exists => TRUE
);

CREATE INDEX idx_pool_reserves_history_pool_time ON pool_reserves_history(chain_id, pool_address, timestamp DESC);
CREATE INDEX idx_pool_reserves_history_timestamp ON pool_reserves_history(timestamp DESC);

-- Token OHLCV - Open, High, Low, Close, Volume data by interval
CREATE TABLE IF NOT EXISTS token_ohlcv (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    token_address VARCHAR(42) NOT NULL,
    pool_address VARCHAR(42), -- Optional: specific pool, NULL = aggregated across all pools
    interval_type VARCHAR(10) NOT NULL CHECK (interval_type IN ('5m', '15m', '1h', '4h', '24h')),
    open_price NUMERIC(30, 8) NOT NULL,
    high_price NUMERIC(30, 8) NOT NULL,
    low_price NUMERIC(30, 8) NOT NULL,
    close_price NUMERIC(30, 8) NOT NULL,
    volume NUMERIC(30, 8) DEFAULT 0,
    volume_usd NUMERIC(30, 8) DEFAULT 0,
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, token_address, pool_address, interval_type, timestamp)
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS token_ohlcv_chain_138 PARTITION OF token_ohlcv FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS token_ohlcv_chain_651940 PARTITION OF token_ohlcv FOR VALUES IN (651940);

-- Convert to hypertable for TimescaleDB time-series optimization
SELECT create_hypertable('token_ohlcv', 'timestamp',
    chunk_time_interval => INTERVAL '7 days',
    if_not_exists => TRUE
);

CREATE INDEX idx_token_ohlcv_token_time ON token_ohlcv(chain_id, token_address, interval_type, timestamp DESC);
CREATE INDEX idx_token_ohlcv_pool_time ON token_ohlcv(chain_id, pool_address, interval_type, timestamp DESC) WHERE pool_address IS NOT NULL;
CREATE INDEX idx_token_ohlcv_timestamp ON token_ohlcv(timestamp DESC);

-- External API Cache - Cached responses from external APIs
CREATE TABLE IF NOT EXISTS external_api_cache (
    id BIGSERIAL PRIMARY KEY,
    api_provider VARCHAR(50) NOT NULL CHECK (api_provider IN ('coingecko', 'coinmarketcap', 'dexscreener')),
    cache_key VARCHAR(255) NOT NULL,
    chain_id INTEGER,
    token_address VARCHAR(42),
    response_data JSONB NOT NULL,
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(api_provider, cache_key)
);

CREATE INDEX idx_external_api_cache_provider_key ON external_api_cache(api_provider, cache_key);
CREATE INDEX idx_external_api_cache_chain_token ON external_api_cache(chain_id, token_address) WHERE chain_id IS NOT NULL AND token_address IS NOT NULL;
CREATE INDEX idx_external_api_cache_expires ON external_api_cache(expires_at);

-- Token Signals - Trending and growth metrics
CREATE TABLE IF NOT EXISTS token_signals (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    token_address VARCHAR(42) NOT NULL,
    tx_count_growth_24h NUMERIC(10, 4) DEFAULT 0, -- Percentage change
    unique_wallets_24h INTEGER DEFAULT 0,
    unique_wallets_growth_24h NUMERIC(10, 4) DEFAULT 0,
    swap_count_24h INTEGER DEFAULT 0,
    swap_count_growth_24h NUMERIC(10, 4) DEFAULT 0,
    new_lp_creations_24h INTEGER DEFAULT 0,
    attention_score NUMERIC(10, 4) DEFAULT 0, -- Composite score 0-100
    trending_rank INTEGER, -- Rank among trending tokens
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, token_address, timestamp)
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS token_signals_chain_138 PARTITION OF token_signals FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS token_signals_chain_651940 PARTITION OF token_signals FOR VALUES IN (651940);

-- Convert to hypertable for TimescaleDB time-series optimization
SELECT create_hypertable('token_signals', 'timestamp',
    chunk_time_interval => INTERVAL '1 day',
    if_not_exists => TRUE
);

CREATE INDEX idx_token_signals_token_time ON token_signals(chain_id, token_address, timestamp DESC);
CREATE INDEX idx_token_signals_attention ON token_signals(chain_id, attention_score DESC, timestamp DESC);
CREATE INDEX idx_token_signals_trending ON token_signals(chain_id, trending_rank, timestamp DESC) WHERE trending_rank IS NOT NULL;

-- Swap Events - Track individual swap events for volume calculation
CREATE TABLE IF NOT EXISTS swap_events (
    id BIGSERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    pool_address VARCHAR(42) NOT NULL,
    transaction_hash VARCHAR(66) NOT NULL,
    block_number BIGINT NOT NULL,
    log_index INTEGER NOT NULL,
    token0_address VARCHAR(42) NOT NULL,
    token1_address VARCHAR(42) NOT NULL,
    amount0_in NUMERIC(78, 0) DEFAULT 0,
    amount1_in NUMERIC(78, 0) DEFAULT 0,
    amount0_out NUMERIC(78, 0) DEFAULT 0,
    amount1_out NUMERIC(78, 0) DEFAULT 0,
    amount_usd NUMERIC(30, 8), -- Calculated USD value
    sender VARCHAR(42),
    to_address VARCHAR(42),
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, transaction_hash, log_index)
) PARTITION BY LIST (chain_id);

-- Create partitions for supported chains
CREATE TABLE IF NOT EXISTS swap_events_chain_138 PARTITION OF swap_events FOR VALUES IN (138);
CREATE TABLE IF NOT EXISTS swap_events_chain_651940 PARTITION OF swap_events FOR VALUES IN (651940);

-- Convert to hypertable for TimescaleDB time-series optimization
SELECT create_hypertable('swap_events', 'timestamp',
    chunk_time_interval => INTERVAL '1 day',
    if_not_exists => TRUE
);

CREATE INDEX idx_swap_events_pool_time ON swap_events(chain_id, pool_address, timestamp DESC);
CREATE INDEX idx_swap_events_token0 ON swap_events(chain_id, token0_address, timestamp DESC);
CREATE INDEX idx_swap_events_token1 ON swap_events(chain_id, token1_address, timestamp DESC);
CREATE INDEX idx_swap_events_tx_hash ON swap_events(chain_id, transaction_hash);
CREATE INDEX idx_swap_events_block ON swap_events(chain_id, block_number);

-- Update triggers for last_updated
CREATE TRIGGER update_token_market_data_updated_at BEFORE UPDATE ON token_market_data
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_liquidity_pools_updated_at BEFORE UPDATE ON liquidity_pools
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- Comments for documentation
COMMENT ON TABLE token_market_data IS 'Aggregated market data per token including price, volume, market cap, and liquidity';
COMMENT ON TABLE liquidity_pools IS 'DEX liquidity pool information with reserves and TVL';
COMMENT ON TABLE pool_reserves_history IS 'Time-series history of pool reserve snapshots';
COMMENT ON TABLE token_ohlcv IS 'OHLCV (Open, High, Low, Close, Volume) data for token price charts';
COMMENT ON TABLE external_api_cache IS 'Cached responses from external APIs (CoinGecko, CMC, DexScreener)';
COMMENT ON TABLE token_signals IS 'Trending signals and growth metrics for tokens';
COMMENT ON TABLE swap_events IS 'Individual swap events from DEX pools for volume calculation';
