-- Migration: Track 2-4 Schema
-- Description: Creates tables for indexed explorer (Track 2), analytics (Track 3), and operator tools (Track 4)

-- Track 2: Indexed Address Data
CREATE TABLE IF NOT EXISTS addresses (
    id SERIAL PRIMARY KEY,
    address VARCHAR(42) NOT NULL UNIQUE,
    chain_id INTEGER NOT NULL,
    first_seen_block BIGINT,
    first_seen_timestamp TIMESTAMP WITH TIME ZONE,
    last_seen_block BIGINT,
    last_seen_timestamp TIMESTAMP WITH TIME ZONE,
    tx_count_sent INTEGER DEFAULT 0,
    tx_count_received INTEGER DEFAULT 0,
    total_sent_wei NUMERIC(78, 0) DEFAULT 0,
    total_received_wei NUMERIC(78, 0) DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_addresses_address ON addresses(address);
CREATE INDEX idx_addresses_chain_id ON addresses(chain_id);
CREATE INDEX idx_addresses_first_seen ON addresses(first_seen_timestamp);
CREATE INDEX idx_addresses_last_seen ON addresses(last_seen_timestamp);

-- Track 2: Token Transfers (ERC-20)
CREATE TABLE IF NOT EXISTS token_transfers (
    id SERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    transaction_hash VARCHAR(66) NOT NULL,
    log_index INTEGER NOT NULL,
    block_number BIGINT NOT NULL,
    block_hash VARCHAR(66) NOT NULL,
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    token_contract VARCHAR(42) NOT NULL,
    from_address VARCHAR(42) NOT NULL,
    to_address VARCHAR(42) NOT NULL,
    value NUMERIC(78, 0) NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, transaction_hash, log_index)
);

CREATE INDEX idx_token_transfers_token ON token_transfers(token_contract);
CREATE INDEX idx_token_transfers_from ON token_transfers(from_address);
CREATE INDEX idx_token_transfers_to ON token_transfers(to_address);
CREATE INDEX idx_token_transfers_block ON token_transfers(block_number);
CREATE INDEX idx_token_transfers_timestamp ON token_transfers(timestamp);
CREATE INDEX idx_token_transfers_tx_hash ON token_transfers(transaction_hash);

-- Track 2: Token Balances (Snapshots)
CREATE TABLE IF NOT EXISTS token_balances (
    id SERIAL PRIMARY KEY,
    address VARCHAR(42) NOT NULL,
    token_contract VARCHAR(42) NOT NULL,
    chain_id INTEGER NOT NULL,
    balance NUMERIC(78, 0) NOT NULL DEFAULT 0,
    balance_formatted NUMERIC(78, 18),
    last_updated_block BIGINT,
    last_updated_timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(address, token_contract, chain_id)
);

CREATE INDEX idx_token_balances_address ON token_balances(address);
CREATE INDEX idx_token_balances_token ON token_balances(token_contract);
CREATE INDEX idx_token_balances_chain ON token_balances(chain_id);

-- Track 2: Internal Transactions
CREATE TABLE IF NOT EXISTS internal_transactions (
    id SERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    transaction_hash VARCHAR(66) NOT NULL,
    block_number BIGINT NOT NULL,
    block_hash VARCHAR(66) NOT NULL,
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    trace_address INTEGER[],
    from_address VARCHAR(42) NOT NULL,
    to_address VARCHAR(42),
    value NUMERIC(78, 0) NOT NULL DEFAULT 0,
    gas_limit NUMERIC(78, 0),
    gas_used NUMERIC(78, 0),
    call_type VARCHAR(50),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_internal_txs_tx_hash ON internal_transactions(transaction_hash);
CREATE INDEX idx_internal_txs_from ON internal_transactions(from_address);
CREATE INDEX idx_internal_txs_to ON internal_transactions(to_address);
CREATE INDEX idx_internal_txs_block ON internal_transactions(block_number);
CREATE INDEX idx_internal_txs_timestamp ON internal_transactions(timestamp);

-- Track 3: Analytics Flows (Address → Address)
CREATE TABLE IF NOT EXISTS analytics_flows (
    id SERIAL PRIMARY KEY,
    chain_id INTEGER NOT NULL,
    from_address VARCHAR(42) NOT NULL,
    to_address VARCHAR(42) NOT NULL,
    token_contract VARCHAR(42),
    total_amount NUMERIC(78, 0) NOT NULL DEFAULT 0,
    transfer_count INTEGER NOT NULL DEFAULT 0,
    first_seen TIMESTAMP WITH TIME ZONE NOT NULL,
    last_seen TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(chain_id, from_address, to_address, token_contract)
);

CREATE INDEX idx_analytics_flows_from ON analytics_flows(from_address);
CREATE INDEX idx_analytics_flows_to ON analytics_flows(to_address);
CREATE INDEX idx_analytics_flows_token ON analytics_flows(token_contract);
CREATE INDEX idx_analytics_flows_last_seen ON analytics_flows(last_seen);

-- Track 3: Bridge Analytics History
CREATE TABLE IF NOT EXISTS analytics_bridge_history (
    id SERIAL PRIMARY KEY,
    chain_from INTEGER NOT NULL,
    chain_to INTEGER NOT NULL,
    token_contract VARCHAR(42),
    transfer_hash VARCHAR(66) NOT NULL,
    from_address VARCHAR(42) NOT NULL,
    to_address VARCHAR(42) NOT NULL,
    amount NUMERIC(78, 0) NOT NULL,
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    status VARCHAR(50) NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_bridge_history_chains ON analytics_bridge_history(chain_from, chain_to);
CREATE INDEX idx_bridge_history_token ON analytics_bridge_history(token_contract);
CREATE INDEX idx_bridge_history_timestamp ON analytics_bridge_history(timestamp);
CREATE INDEX idx_bridge_history_from ON analytics_bridge_history(from_address);

-- Track 3: Token Distribution (Materialized View)
CREATE MATERIALIZED VIEW IF NOT EXISTS token_distribution AS
SELECT 
    token_contract,
    chain_id,
    COUNT(DISTINCT address) as holder_count,
    SUM(balance) as total_balance,
    AVG(balance) as avg_balance,
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY balance) as median_balance,
    MAX(balance) as max_balance,
    MIN(balance) as min_balance,
    COUNT(*) FILTER (WHERE balance > 0) as active_holders,
    NOW() as last_updated
FROM token_balances
GROUP BY token_contract, chain_id;

CREATE UNIQUE INDEX idx_token_distribution_unique ON token_distribution(token_contract, chain_id);
CREATE INDEX idx_token_distribution_holders ON token_distribution(holder_count);

-- Track 4: Operator Events (Audit Log)
CREATE TABLE IF NOT EXISTS operator_events (
    id SERIAL PRIMARY KEY,
    event_type VARCHAR(100) NOT NULL,
    chain_id INTEGER,
    operator_address VARCHAR(42) NOT NULL,
    target_resource VARCHAR(200),
    action VARCHAR(100) NOT NULL,
    details JSONB,
    ip_address INET,
    user_agent TEXT,
    timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_operator_events_type ON operator_events(event_type);
CREATE INDEX idx_operator_events_operator ON operator_events(operator_address);
CREATE INDEX idx_operator_events_timestamp ON operator_events(timestamp);
CREATE INDEX idx_operator_events_chain ON operator_events(chain_id);

-- Track 4: Operator IP Whitelist
CREATE TABLE IF NOT EXISTS operator_ip_whitelist (
    id SERIAL PRIMARY KEY,
    operator_address VARCHAR(42) NOT NULL,
    ip_address INET NOT NULL,
    description TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(operator_address, ip_address)
);

CREATE INDEX idx_operator_whitelist_operator ON operator_ip_whitelist(operator_address);
CREATE INDEX idx_operator_whitelist_ip ON operator_ip_whitelist(ip_address);

-- Track 4: Operator Roles
CREATE TABLE IF NOT EXISTS operator_roles (
    id SERIAL PRIMARY KEY,
    address VARCHAR(42) NOT NULL UNIQUE,
    track_level INTEGER NOT NULL DEFAULT 4,
    roles TEXT[],
    approved BOOLEAN DEFAULT FALSE,
    approved_by VARCHAR(42),
    approved_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_operator_roles_address ON operator_roles(address);
CREATE INDEX idx_operator_roles_approved ON operator_roles(approved);

-- Wallet Authentication: Nonce storage
CREATE TABLE IF NOT EXISTS wallet_nonces (
    id SERIAL PRIMARY KEY,
    address VARCHAR(42) NOT NULL UNIQUE,
    nonce VARCHAR(64) NOT NULL,
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_wallet_nonces_address ON wallet_nonces(address);
CREATE INDEX idx_wallet_nonces_expires ON wallet_nonces(expires_at);

-- Update triggers for updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_addresses_updated_at BEFORE UPDATE ON addresses
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_token_balances_updated_at BEFORE UPDATE ON token_balances
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_analytics_flows_updated_at BEFORE UPDATE ON analytics_flows
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_operator_roles_updated_at BEFORE UPDATE ON operator_roles
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

