-- Test Database Schema for Integration Testing
-- Creates tables needed for database integration tests

-- Test trades table for testing trade persistence
CREATE TABLE IF NOT EXISTS test_trades (
    id SERIAL PRIMARY KEY,
    trade_id VARCHAR(100) UNIQUE NOT NULL,
    symbol VARCHAR(20) NOT NULL,
    side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')),
    quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0),
    price DECIMAL(20,8) NOT NULL CHECK (price > 0),
    commission DECIMAL(20,8) DEFAULT 0,
    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    execution_venue VARCHAR(50) DEFAULT 'TEST_EXCHANGE',
    order_id VARCHAR(100),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Test positions table for testing position management
CREATE TABLE IF NOT EXISTS test_positions (
    id SERIAL PRIMARY KEY,
    account_id VARCHAR(50) NOT NULL,
    symbol VARCHAR(20) NOT NULL,
    quantity DECIMAL(20,8) NOT NULL,
    average_price DECIMAL(20,8) NOT NULL,
    market_value DECIMAL(20,8) NOT NULL,
    unrealized_pnl DECIMAL(20,8) DEFAULT 0,
    realized_pnl DECIMAL(20,8) DEFAULT 0,
    last_updated TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(account_id, symbol)
);

-- Test orders table for testing order lifecycle
CREATE TABLE IF NOT EXISTS test_orders (
    id SERIAL PRIMARY KEY,
    order_id VARCHAR(100) UNIQUE NOT NULL,
    client_order_id VARCHAR(100),
    account_id VARCHAR(50) NOT NULL,
    symbol VARCHAR(20) NOT NULL,
    side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')),
    order_type VARCHAR(20) NOT NULL CHECK (order_type IN ('MARKET', 'LIMIT', 'STOP', 'STOP_LIMIT')),
    quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0),
    price DECIMAL(20,8),
    stop_price DECIMAL(20,8),
    filled_quantity DECIMAL(20,8) DEFAULT 0,
    remaining_quantity DECIMAL(20,8),
    status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'ACTIVE', 'FILLED', 'CANCELLED', 'REJECTED')),
    time_in_force VARCHAR(10) DEFAULT 'DAY' CHECK (time_in_force IN ('DAY', 'GTC', 'IOC', 'FOK')),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    expires_at TIMESTAMPTZ
);

-- Test executions table for testing execution tracking
CREATE TABLE IF NOT EXISTS test_executions (
    id SERIAL PRIMARY KEY,
    execution_id VARCHAR(100) UNIQUE NOT NULL,
    order_id VARCHAR(100) NOT NULL,
    trade_id VARCHAR(100),
    symbol VARCHAR(20) NOT NULL,
    side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')),
    quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0),
    price DECIMAL(20,8) NOT NULL CHECK (price > 0),
    commission DECIMAL(20,8) DEFAULT 0,
    execution_venue VARCHAR(50) DEFAULT 'TEST_EXCHANGE',
    executed_at TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Performance-optimized indexes for testing
CREATE INDEX IF NOT EXISTS idx_test_trades_symbol_timestamp ON test_trades(symbol, timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_test_trades_trade_id_hash ON test_trades USING HASH(trade_id);
CREATE INDEX IF NOT EXISTS idx_test_trades_timestamp ON test_trades(timestamp DESC);

CREATE INDEX IF NOT EXISTS idx_test_positions_account_symbol ON test_positions(account_id, symbol);
CREATE INDEX IF NOT EXISTS idx_test_positions_symbol ON test_positions(symbol);
CREATE INDEX IF NOT EXISTS idx_test_positions_updated ON test_positions(last_updated DESC);

CREATE INDEX IF NOT EXISTS idx_test_orders_status ON test_orders(status) WHERE status IN ('PENDING', 'ACTIVE');
CREATE INDEX IF NOT EXISTS idx_test_orders_symbol_status ON test_orders(symbol, status);
CREATE INDEX IF NOT EXISTS idx_test_orders_account ON test_orders(account_id);
CREATE INDEX IF NOT EXISTS idx_test_orders_created ON test_orders(created_at DESC);

CREATE INDEX IF NOT EXISTS idx_test_executions_order_id ON test_executions(order_id);
CREATE INDEX IF NOT EXISTS idx_test_executions_symbol_executed ON test_executions(symbol, executed_at DESC);
CREATE INDEX IF NOT EXISTS idx_test_executions_executed_at ON test_executions(executed_at DESC);

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

CREATE TRIGGER update_test_trades_updated_at BEFORE UPDATE ON test_trades
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_test_positions_updated_at BEFORE UPDATE ON test_positions
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_test_orders_updated_at BEFORE UPDATE ON test_orders
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- Function to calculate remaining quantity for orders
CREATE OR REPLACE FUNCTION update_order_remaining_quantity()
RETURNS TRIGGER AS $$
BEGIN
    NEW.remaining_quantity = NEW.quantity - NEW.filled_quantity;
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_test_orders_remaining BEFORE INSERT OR UPDATE ON test_orders
    FOR EACH ROW EXECUTE FUNCTION update_order_remaining_quantity();

-- Comments for documentation
COMMENT ON TABLE test_trades IS 'Test table for validating trade persistence and querying performance';
COMMENT ON TABLE test_positions IS 'Test table for validating position management and portfolio tracking';
COMMENT ON TABLE test_orders IS 'Test table for validating order lifecycle management';
COMMENT ON TABLE test_executions IS 'Test table for validating execution tracking and reporting';

COMMENT ON COLUMN test_trades.trade_id IS 'Unique identifier for the trade execution';
COMMENT ON COLUMN test_trades.symbol IS 'Trading symbol (e.g., AAPL, GOOGL)';
COMMENT ON COLUMN test_trades.side IS 'Buy or sell side of the trade';
COMMENT ON COLUMN test_trades.quantity IS 'Number of shares/units traded';
COMMENT ON COLUMN test_trades.price IS 'Execution price per share/unit';

COMMENT ON COLUMN test_positions.account_id IS 'Account identifier owning the position';
COMMENT ON COLUMN test_positions.symbol IS 'Trading symbol for the position';
COMMENT ON COLUMN test_positions.quantity IS 'Current position size (positive=long, negative=short)';
COMMENT ON COLUMN test_positions.average_price IS 'Average cost basis for the position';
COMMENT ON COLUMN test_positions.market_value IS 'Current market value of the position';
COMMENT ON COLUMN test_positions.unrealized_pnl IS 'Unrealized profit/loss on the position';