-- ============================================================================
-- SCHEMA: broker_integration
-- TABLE: trade_execution
-- DESCRIPTION: Ejecucion de ordenes en broker
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 6 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Enum para estado de ejecucion
DO $$ BEGIN
    CREATE TYPE broker_integration.execution_status AS ENUM (
        'pending',              -- Pendiente de enviar
        'submitted',            -- Enviada al broker
        'accepted',             -- Aceptada por broker
        'filled',               -- Ejecutada completamente
        'partial_fill',         -- Ejecutada parcialmente
        'rejected',             -- Rechazada
        'cancelled',            -- Cancelada
        'expired',              -- Expirada
        'error'                 -- Error de sistema
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para tipo de orden
DO $$ BEGIN
    CREATE TYPE broker_integration.order_type AS ENUM (
        'market',
        'limit',
        'stop',
        'stop_limit',
        'trailing_stop'
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para direccion
DO $$ BEGIN
    CREATE TYPE broker_integration.trade_direction AS ENUM (
        'buy',
        'sell'
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Ejecucion de Trades
CREATE TABLE IF NOT EXISTS broker_integration.trade_execution (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,

    -- Referencias
    broker_account_id UUID NOT NULL REFERENCES broker_integration.broker_accounts(id) ON DELETE CASCADE,
    signal_id UUID,                                     -- Senal que origino
    position_id UUID,                                   -- Posicion resultante

    -- Orden
    order_type broker_integration.order_type NOT NULL,
    direction broker_integration.trade_direction NOT NULL,
    symbol VARCHAR(20) NOT NULL,

    -- Tamaño
    lot_size DECIMAL(10, 4) NOT NULL,
    units INTEGER,

    -- Precios solicitados
    requested_price DECIMAL(15, 8),
    limit_price DECIMAL(15, 8),
    stop_price DECIMAL(15, 8),

    -- Stop Loss / Take Profit
    stop_loss DECIMAL(15, 8),
    take_profit DECIMAL(15, 8),

    -- Estado
    status broker_integration.execution_status NOT NULL DEFAULT 'pending',
    status_message TEXT,

    -- Ejecucion
    executed_price DECIMAL(15, 8),
    executed_lot_size DECIMAL(10, 4),
    slippage DECIMAL(10, 4),                            -- En pips
    slippage_cost DECIMAL(15, 4),                       -- En moneda de cuenta

    -- IDs del broker
    broker_order_id VARCHAR(100),
    broker_ticket VARCHAR(100),
    broker_deal_id VARCHAR(100),

    -- Timestamps de ejecucion
    submitted_at TIMESTAMPTZ,
    accepted_at TIMESTAMPTZ,
    executed_at TIMESTAMPTZ,
    cancelled_at TIMESTAMPTZ,

    -- Latencia
    submission_latency_ms INTEGER,                      -- Tiempo hasta submit
    execution_latency_ms INTEGER,                       -- Tiempo hasta fill
    total_latency_ms INTEGER,

    -- Costos
    commission DECIMAL(15, 4) DEFAULT 0,
    swap DECIMAL(15, 4) DEFAULT 0,
    spread_cost DECIMAL(15, 4) DEFAULT 0,

    -- Contexto
    execution_source VARCHAR(50),                       -- 'manual', 'signal', 'bot', 'copy_trade'
    execution_context JSONB DEFAULT '{}'::JSONB,

    -- Errores
    error_code VARCHAR(50),
    error_message TEXT,
    retry_count INTEGER NOT NULL DEFAULT 0,
    max_retries INTEGER DEFAULT 3,

    -- Validez
    valid_until TIMESTAMPTZ,
    time_in_force VARCHAR(20) DEFAULT 'GTC',            -- 'GTC', 'IOC', 'FOK', 'GTD'

    -- Metadata
    metadata JSONB DEFAULT '{}'::JSONB,
    notes TEXT,

    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

COMMENT ON TABLE broker_integration.trade_execution IS
'Registro de todas las ejecuciones de ordenes en brokers conectados';

COMMENT ON COLUMN broker_integration.trade_execution.slippage IS
'Diferencia entre precio solicitado y ejecutado en pips';

-- Indices
CREATE INDEX IF NOT EXISTS idx_trade_exec_tenant
    ON broker_integration.trade_execution(tenant_id);

CREATE INDEX IF NOT EXISTS idx_trade_exec_user
    ON broker_integration.trade_execution(user_id);

CREATE INDEX IF NOT EXISTS idx_trade_exec_account
    ON broker_integration.trade_execution(broker_account_id);

CREATE INDEX IF NOT EXISTS idx_trade_exec_status
    ON broker_integration.trade_execution(status);

CREATE INDEX IF NOT EXISTS idx_trade_exec_pending
    ON broker_integration.trade_execution(status, created_at)
    WHERE status IN ('pending', 'submitted');

CREATE INDEX IF NOT EXISTS idx_trade_exec_symbol
    ON broker_integration.trade_execution(symbol, executed_at DESC);

CREATE INDEX IF NOT EXISTS idx_trade_exec_broker_order
    ON broker_integration.trade_execution(broker_order_id)
    WHERE broker_order_id IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_trade_exec_signal
    ON broker_integration.trade_execution(signal_id)
    WHERE signal_id IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_trade_exec_created
    ON broker_integration.trade_execution(created_at DESC);

-- Trigger para updated_at
DROP TRIGGER IF EXISTS trade_exec_updated_at ON broker_integration.trade_execution;
CREATE TRIGGER trade_exec_updated_at
    BEFORE UPDATE ON broker_integration.trade_execution
    FOR EACH ROW
    EXECUTE FUNCTION broker_integration.update_broker_timestamp();

-- Trigger para calcular latencias
CREATE OR REPLACE FUNCTION broker_integration.calculate_execution_latency()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.submitted_at IS NOT NULL AND NEW.submission_latency_ms IS NULL THEN
        NEW.submission_latency_ms := EXTRACT(EPOCH FROM (NEW.submitted_at - NEW.created_at)) * 1000;
    END IF;

    IF NEW.executed_at IS NOT NULL AND NEW.submitted_at IS NOT NULL AND NEW.execution_latency_ms IS NULL THEN
        NEW.execution_latency_ms := EXTRACT(EPOCH FROM (NEW.executed_at - NEW.submitted_at)) * 1000;
    END IF;

    IF NEW.executed_at IS NOT NULL AND NEW.total_latency_ms IS NULL THEN
        NEW.total_latency_ms := EXTRACT(EPOCH FROM (NEW.executed_at - NEW.created_at)) * 1000;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trade_exec_latency ON broker_integration.trade_execution;
CREATE TRIGGER trade_exec_latency
    BEFORE UPDATE OF submitted_at, executed_at ON broker_integration.trade_execution
    FOR EACH ROW
    EXECUTE FUNCTION broker_integration.calculate_execution_latency();

-- Vista de ejecuciones recientes
CREATE OR REPLACE VIEW broker_integration.v_recent_executions AS
SELECT
    te.id,
    te.user_id,
    ba.broker_name,
    te.symbol,
    te.direction,
    te.order_type,
    te.lot_size,
    te.status,
    te.requested_price,
    te.executed_price,
    te.slippage,
    te.total_latency_ms,
    te.created_at,
    te.executed_at
FROM broker_integration.trade_execution te
JOIN broker_integration.broker_accounts ba ON te.broker_account_id = ba.id
ORDER BY te.created_at DESC;

-- Vista de estadisticas de ejecucion
CREATE OR REPLACE VIEW broker_integration.v_execution_stats AS
SELECT
    ba.broker_name,
    te.symbol,
    COUNT(*) AS total_executions,
    COUNT(*) FILTER (WHERE te.status = 'filled') AS filled,
    COUNT(*) FILTER (WHERE te.status = 'rejected') AS rejected,
    ROUND((COUNT(*) FILTER (WHERE te.status = 'filled')::DECIMAL
        / NULLIF(COUNT(*), 0) * 100), 2) AS fill_rate,
    ROUND(AVG(te.slippage) FILTER (WHERE te.slippage IS NOT NULL)::NUMERIC, 2) AS avg_slippage,
    ROUND(AVG(te.total_latency_ms) FILTER (WHERE te.total_latency_ms IS NOT NULL)::NUMERIC, 0) AS avg_latency_ms
FROM broker_integration.trade_execution te
JOIN broker_integration.broker_accounts ba ON te.broker_account_id = ba.id
WHERE te.created_at >= NOW() - INTERVAL '30 days'
GROUP BY ba.broker_name, te.symbol
ORDER BY total_executions DESC;

-- RLS
ALTER TABLE broker_integration.trade_execution ENABLE ROW LEVEL SECURITY;

CREATE POLICY trade_exec_tenant ON broker_integration.trade_execution
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

CREATE POLICY trade_exec_user ON broker_integration.trade_execution
    FOR ALL
    USING (user_id = current_setting('app.current_user_id', true)::UUID);

-- Grants
GRANT SELECT, INSERT, UPDATE ON broker_integration.trade_execution TO trading_app;
GRANT SELECT ON broker_integration.trade_execution TO trading_readonly;
GRANT SELECT ON broker_integration.v_recent_executions TO trading_app;
GRANT SELECT ON broker_integration.v_execution_stats TO trading_app;
