-- ============================================================================
-- SCHEMA: trading
-- TABLE: bots
-- DESCRIPTION: Agentes de trading automatizado (Atlas, Orion, Nova)
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 3 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Enum para estado del bot
DO $$ BEGIN
    CREATE TYPE trading.bot_status AS ENUM (
        'inactive',         -- Inactivo
        'starting',         -- Iniciando
        'running',          -- Ejecutando
        'paused',           -- Pausado temporalmente
        'stopping',         -- Deteniendo
        'error',            -- Error
        'maintenance'       -- En mantenimiento
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para nivel de riesgo del bot
DO $$ BEGIN
    CREATE TYPE trading.bot_risk_level AS ENUM (
        'conservative',     -- Conservador (bajo riesgo)
        'moderate',         -- Moderado
        'aggressive',       -- Agresivo
        'ultra_aggressive'  -- Ultra agresivo
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Bots de Trading
CREATE TABLE IF NOT EXISTS trading.bots (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    strategy_id UUID REFERENCES trading.strategies(id),

    -- Identificacion
    code VARCHAR(20) NOT NULL,                      -- 'ATLAS', 'ORION', 'NOVA'
    name VARCHAR(100) NOT NULL,
    description TEXT,
    avatar_url TEXT,

    -- Tipo y version
    version VARCHAR(20) NOT NULL DEFAULT '1.0.0',
    risk_level trading.bot_risk_level NOT NULL DEFAULT 'moderate',

    -- Estado
    status trading.bot_status NOT NULL DEFAULT 'inactive',
    status_message TEXT,
    last_status_change TIMESTAMPTZ DEFAULT NOW(),

    -- Conexion MT4/MT5
    mt_account_id VARCHAR(50),
    mt_server VARCHAR(100),
    mt_connected BOOLEAN NOT NULL DEFAULT FALSE,
    mt_last_heartbeat TIMESTAMPTZ,

    -- Configuracion de trading
    trading_config JSONB NOT NULL DEFAULT '{
        "enabled": false,
        "symbols": ["EURUSD", "GBPUSD", "XAUUSD"],
        "timeframes": ["H1", "H4"],
        "max_trades_per_day": 5,
        "max_concurrent_positions": 3,
        "trading_hours": {
            "enabled": false,
            "start": "08:00",
            "end": "20:00",
            "timezone": "America/New_York"
        }
    }'::JSONB,

    -- Configuracion de riesgo
    risk_config JSONB NOT NULL DEFAULT '{
        "capital_allocation": 10000,
        "risk_per_trade_percent": 1,
        "max_daily_loss_percent": 3,
        "max_drawdown_percent": 10,
        "lot_size_mode": "fixed",
        "fixed_lot_size": 0.1,
        "use_compounding": false
    }'::JSONB,

    -- Configuracion de senales
    signal_config JSONB NOT NULL DEFAULT '{
        "min_confidence": 70,
        "require_confirmation": true,
        "confirmation_timeframe": "M15",
        "filter_by_trend": true,
        "filter_by_volatility": true
    }'::JSONB,

    -- Capital y rendimiento
    initial_capital DECIMAL(15, 2) NOT NULL DEFAULT 0,
    current_capital DECIMAL(15, 2) NOT NULL DEFAULT 0,
    allocated_capital DECIMAL(15, 2) NOT NULL DEFAULT 0,
    available_margin DECIMAL(15, 2) NOT NULL DEFAULT 0,

    -- Estadisticas de rendimiento
    total_trades INTEGER NOT NULL DEFAULT 0,
    winning_trades INTEGER NOT NULL DEFAULT 0,
    losing_trades INTEGER NOT NULL DEFAULT 0,
    win_rate DECIMAL(5, 2) DEFAULT 0,
    profit_factor DECIMAL(10, 4) DEFAULT 0,
    sharpe_ratio DECIMAL(10, 4) DEFAULT 0,
    max_drawdown DECIMAL(15, 4) DEFAULT 0,
    max_drawdown_percent DECIMAL(5, 2) DEFAULT 0,

    -- P&L
    total_profit DECIMAL(15, 4) NOT NULL DEFAULT 0,
    total_loss DECIMAL(15, 4) NOT NULL DEFAULT 0,
    net_profit DECIMAL(15, 4) NOT NULL DEFAULT 0,
    daily_pnl DECIMAL(15, 4) NOT NULL DEFAULT 0,
    weekly_pnl DECIMAL(15, 4) NOT NULL DEFAULT 0,
    monthly_pnl DECIMAL(15, 4) NOT NULL DEFAULT 0,

    -- Rendimiento porcentual
    total_return_percent DECIMAL(10, 4) DEFAULT 0,
    daily_return_percent DECIMAL(10, 4) DEFAULT 0,
    weekly_return_percent DECIMAL(10, 4) DEFAULT 0,
    monthly_return_percent DECIMAL(10, 4) DEFAULT 0,

    -- Posiciones actuales
    open_positions_count INTEGER NOT NULL DEFAULT 0,
    open_positions_value DECIMAL(15, 4) NOT NULL DEFAULT 0,
    unrealized_pnl DECIMAL(15, 4) NOT NULL DEFAULT 0,

    -- Ultima actividad
    last_trade_at TIMESTAMPTZ,
    last_signal_at TIMESTAMPTZ,
    last_error_at TIMESTAMPTZ,
    last_error_message TEXT,

    -- Subscribers (usuarios que invierten en este bot)
    subscriber_count INTEGER NOT NULL DEFAULT 0,
    total_aum DECIMAL(15, 2) NOT NULL DEFAULT 0,    -- Assets Under Management

    -- Disponibilidad
    is_public BOOLEAN NOT NULL DEFAULT FALSE,
    is_premium BOOLEAN NOT NULL DEFAULT FALSE,
    min_investment DECIMAL(15, 2) DEFAULT 100,
    max_investment DECIMAL(15, 2),

    -- Comisiones
    performance_fee_percent DECIMAL(5, 2) DEFAULT 20,  -- Fee sobre ganancias
    management_fee_percent DECIMAL(5, 2) DEFAULT 0,    -- Fee anual sobre AUM

    -- Metadata
    tags VARCHAR(50)[],
    metadata JSONB DEFAULT '{}'::JSONB,

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

    -- Constraints
    CONSTRAINT bots_unique_code UNIQUE (tenant_id, code),
    CONSTRAINT bots_capital_check CHECK (current_capital >= 0),
    CONSTRAINT bots_win_rate_check CHECK (win_rate BETWEEN 0 AND 100)
);

COMMENT ON TABLE trading.bots IS
'Agentes de trading automatizado con configuracion y estadisticas';

COMMENT ON COLUMN trading.bots.code IS
'Codigo unico del bot: ATLAS (conservador), ORION (moderado), NOVA (agresivo)';

-- Indices
CREATE INDEX IF NOT EXISTS idx_bots_tenant
    ON trading.bots(tenant_id);

CREATE INDEX IF NOT EXISTS idx_bots_code
    ON trading.bots(tenant_id, code);

CREATE INDEX IF NOT EXISTS idx_bots_status
    ON trading.bots(status);

CREATE INDEX IF NOT EXISTS idx_bots_running
    ON trading.bots(tenant_id, status)
    WHERE status = 'running';

CREATE INDEX IF NOT EXISTS idx_bots_public
    ON trading.bots(is_public, net_profit DESC)
    WHERE is_public = TRUE;

CREATE INDEX IF NOT EXISTS idx_bots_performance
    ON trading.bots(tenant_id, total_return_percent DESC);

-- Trigger para updated_at
DROP TRIGGER IF EXISTS bot_updated_at ON trading.bots;
CREATE TRIGGER bot_updated_at
    BEFORE UPDATE ON trading.bots
    FOR EACH ROW
    EXECUTE FUNCTION trading.update_trading_timestamp();

-- Trigger para registrar cambios de estado
CREATE OR REPLACE FUNCTION trading.log_bot_status_change()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.status IS DISTINCT FROM OLD.status THEN
        NEW.last_status_change := NOW();

        IF NEW.status = 'running' AND OLD.status != 'running' THEN
            NEW.started_at := NOW();
        ELSIF NEW.status IN ('inactive', 'stopped') AND OLD.status = 'running' THEN
            NEW.stopped_at := NOW();
        ELSIF NEW.status = 'error' THEN
            NEW.last_error_at := NOW();
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS bot_status_change ON trading.bots;
CREATE TRIGGER bot_status_change
    BEFORE UPDATE OF status ON trading.bots
    FOR EACH ROW
    EXECUTE FUNCTION trading.log_bot_status_change();

-- Funcion para actualizar estadisticas del bot
CREATE OR REPLACE FUNCTION trading.recalculate_bot_stats(p_bot_id UUID)
RETURNS VOID AS $$
DECLARE
    v_stats RECORD;
BEGIN
    SELECT
        COUNT(*) AS total,
        COUNT(*) FILTER (WHERE profit_loss > 0) AS wins,
        COUNT(*) FILTER (WHERE profit_loss < 0) AS losses,
        COALESCE(SUM(profit_loss) FILTER (WHERE profit_loss > 0), 0) AS total_profit,
        COALESCE(SUM(ABS(profit_loss)) FILTER (WHERE profit_loss < 0), 0) AS total_loss,
        COALESCE(SUM(profit_loss), 0) AS net_pnl
    INTO v_stats
    FROM trading.positions
    WHERE bot_id = p_bot_id
      AND status IN ('closed', 'stopped', 'target_hit');

    UPDATE trading.bots
    SET total_trades = v_stats.total,
        winning_trades = v_stats.wins,
        losing_trades = v_stats.losses,
        win_rate = CASE WHEN v_stats.total > 0
                        THEN (v_stats.wins::DECIMAL / v_stats.total * 100)
                        ELSE 0 END,
        profit_factor = CASE WHEN v_stats.total_loss > 0
                             THEN v_stats.total_profit / v_stats.total_loss
                             ELSE 0 END,
        total_profit = v_stats.total_profit,
        total_loss = v_stats.total_loss,
        net_profit = v_stats.net_pnl,
        total_return_percent = CASE WHEN initial_capital > 0
                                    THEN (v_stats.net_pnl / initial_capital * 100)
                                    ELSE 0 END
    WHERE id = p_bot_id;
END;
$$ LANGUAGE plpgsql;

-- Vista de bots activos
CREATE OR REPLACE VIEW trading.v_active_bots AS
SELECT
    id,
    tenant_id,
    code,
    name,
    description,
    avatar_url,
    risk_level,
    status,
    win_rate,
    profit_factor,
    total_return_percent,
    max_drawdown_percent,
    subscriber_count,
    total_aum,
    is_premium,
    min_investment
FROM trading.bots
WHERE is_public = TRUE
  AND status IN ('running', 'paused')
ORDER BY total_return_percent DESC;

-- Vista de rendimiento de bots
CREATE OR REPLACE VIEW trading.v_bot_performance AS
SELECT
    b.id,
    b.code,
    b.name,
    b.status,
    b.total_trades,
    b.win_rate,
    b.profit_factor,
    b.sharpe_ratio,
    b.net_profit,
    b.total_return_percent,
    b.daily_return_percent,
    b.weekly_return_percent,
    b.monthly_return_percent,
    b.max_drawdown_percent,
    b.open_positions_count,
    b.unrealized_pnl,
    b.last_trade_at
FROM trading.bots b
ORDER BY b.tenant_id, b.total_return_percent DESC;

-- RLS Policy para multi-tenancy
ALTER TABLE trading.bots ENABLE ROW LEVEL SECURITY;

CREATE POLICY bots_tenant_isolation ON trading.bots
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Grants
GRANT SELECT, INSERT, UPDATE, DELETE ON trading.bots TO trading_app;
GRANT SELECT ON trading.bots TO trading_readonly;
GRANT SELECT ON trading.v_active_bots TO trading_app;
GRANT SELECT ON trading.v_bot_performance TO trading_app;
GRANT EXECUTE ON FUNCTION trading.recalculate_bot_stats TO trading_app;
