-- ============================================================================
-- SCHEMA: trading
-- TABLE: watchlists, watchlist_items
-- DESCRIPTION: Listas de seguimiento de simbolos
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 3 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Tabla de Watchlists
CREATE TABLE IF NOT EXISTS trading.watchlists (
    -- 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,

    -- Informacion
    name VARCHAR(100) NOT NULL,
    description TEXT,
    color VARCHAR(7),                               -- Color hex para identificacion
    icon VARCHAR(50),

    -- Configuracion
    is_default BOOLEAN NOT NULL DEFAULT FALSE,      -- Watchlist por defecto
    is_public BOOLEAN NOT NULL DEFAULT FALSE,       -- Compartida publicamente
    is_pinned BOOLEAN NOT NULL DEFAULT FALSE,       -- Fijada en UI

    -- Ordenamiento
    display_order INTEGER NOT NULL DEFAULT 0,
    sort_by VARCHAR(50) DEFAULT 'symbol',           -- 'symbol', 'change', 'volume', 'custom'
    sort_direction VARCHAR(4) DEFAULT 'asc',

    -- Columnas visibles
    visible_columns JSONB DEFAULT '["symbol", "price", "change", "change_percent"]'::JSONB,

    -- Estadisticas
    item_count INTEGER NOT NULL DEFAULT 0,

    -- Compartir
    share_code VARCHAR(20),                         -- Codigo para compartir
    shared_at TIMESTAMPTZ,
    view_count INTEGER NOT NULL DEFAULT 0,
    copy_count INTEGER NOT NULL DEFAULT 0,

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

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

    -- Constraints
    CONSTRAINT watchlists_unique_name UNIQUE (user_id, name)
);

COMMENT ON TABLE trading.watchlists IS
'Listas de seguimiento de simbolos creadas por usuarios';

-- Tabla de Items de Watchlist
CREATE TABLE IF NOT EXISTS trading.watchlist_items (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    watchlist_id UUID NOT NULL REFERENCES trading.watchlists(id) ON DELETE CASCADE,
    symbol_id UUID REFERENCES trading.symbols(id),
    ticker_id UUID REFERENCES market_data.tickers(id),

    -- Simbolo
    symbol VARCHAR(20) NOT NULL,

    -- Orden personalizado
    display_order INTEGER NOT NULL DEFAULT 0,

    -- Notas del usuario
    notes TEXT,
    tags VARCHAR(50)[],

    -- Alertas rapidas
    alert_price_above DECIMAL(15, 8),
    alert_price_below DECIMAL(15, 8),
    alert_enabled BOOLEAN NOT NULL DEFAULT FALSE,

    -- Precios de referencia del usuario
    entry_price DECIMAL(15, 8),                     -- Precio de entrada planeado
    target_price DECIMAL(15, 8),                    -- Precio objetivo
    stop_price DECIMAL(15, 8),                      -- Stop loss planeado

    -- Precio actual (cache)
    current_price DECIMAL(15, 8),
    price_change DECIMAL(15, 8),
    price_change_percent DECIMAL(10, 4),
    price_updated_at TIMESTAMPTZ,

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

    -- Timestamps
    added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT watchlist_items_unique UNIQUE (watchlist_id, symbol)
);

COMMENT ON TABLE trading.watchlist_items IS
'Simbolos individuales dentro de una watchlist';

-- Indices para watchlists
CREATE INDEX IF NOT EXISTS idx_watchlists_tenant
    ON trading.watchlists(tenant_id);

CREATE INDEX IF NOT EXISTS idx_watchlists_user
    ON trading.watchlists(user_id);

CREATE INDEX IF NOT EXISTS idx_watchlists_default
    ON trading.watchlists(user_id, is_default)
    WHERE is_default = TRUE;

CREATE INDEX IF NOT EXISTS idx_watchlists_public
    ON trading.watchlists(is_public, view_count DESC)
    WHERE is_public = TRUE;

CREATE INDEX IF NOT EXISTS idx_watchlists_share_code
    ON trading.watchlists(share_code)
    WHERE share_code IS NOT NULL;

-- Indices para watchlist_items
CREATE INDEX IF NOT EXISTS idx_watchlist_items_watchlist
    ON trading.watchlist_items(watchlist_id, display_order);

CREATE INDEX IF NOT EXISTS idx_watchlist_items_symbol
    ON trading.watchlist_items(symbol);

CREATE INDEX IF NOT EXISTS idx_watchlist_items_alerts
    ON trading.watchlist_items(alert_enabled, symbol)
    WHERE alert_enabled = TRUE;

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

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

-- Trigger para actualizar item_count en watchlist
CREATE OR REPLACE FUNCTION trading.update_watchlist_count()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'INSERT' THEN
        UPDATE trading.watchlists
        SET item_count = item_count + 1
        WHERE id = NEW.watchlist_id;
    ELSIF TG_OP = 'DELETE' THEN
        UPDATE trading.watchlists
        SET item_count = item_count - 1
        WHERE id = OLD.watchlist_id;
    END IF;

    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS watchlist_item_count ON trading.watchlist_items;
CREATE TRIGGER watchlist_item_count
    AFTER INSERT OR DELETE ON trading.watchlist_items
    FOR EACH ROW
    EXECUTE FUNCTION trading.update_watchlist_count();

-- Trigger para asegurar solo una watchlist default por usuario
CREATE OR REPLACE FUNCTION trading.ensure_single_default_watchlist()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.is_default = TRUE THEN
        UPDATE trading.watchlists
        SET is_default = FALSE
        WHERE user_id = NEW.user_id
          AND id != NEW.id
          AND is_default = TRUE;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS watchlist_single_default ON trading.watchlists;
CREATE TRIGGER watchlist_single_default
    BEFORE INSERT OR UPDATE OF is_default ON trading.watchlists
    FOR EACH ROW
    WHEN (NEW.is_default = TRUE)
    EXECUTE FUNCTION trading.ensure_single_default_watchlist();

-- Funcion para copiar watchlist
CREATE OR REPLACE FUNCTION trading.copy_watchlist(
    p_watchlist_id UUID,
    p_new_user_id UUID,
    p_new_name VARCHAR(100) DEFAULT NULL
)
RETURNS UUID AS $$
DECLARE
    v_source RECORD;
    v_new_id UUID;
    v_tenant_id UUID;
BEGIN
    -- Obtener watchlist origen
    SELECT * INTO v_source FROM trading.watchlists WHERE id = p_watchlist_id;

    IF v_source IS NULL THEN
        RAISE EXCEPTION 'Watchlist not found';
    END IF;

    -- Obtener tenant del nuevo usuario
    SELECT tenant_id INTO v_tenant_id FROM users.users WHERE id = p_new_user_id;

    -- Crear nueva watchlist
    INSERT INTO trading.watchlists (
        tenant_id, user_id, name, description, color, icon,
        sort_by, sort_direction, visible_columns
    ) VALUES (
        v_tenant_id,
        p_new_user_id,
        COALESCE(p_new_name, v_source.name || ' (Copy)'),
        v_source.description,
        v_source.color,
        v_source.icon,
        v_source.sort_by,
        v_source.sort_direction,
        v_source.visible_columns
    )
    RETURNING id INTO v_new_id;

    -- Copiar items
    INSERT INTO trading.watchlist_items (
        watchlist_id, symbol_id, ticker_id, symbol,
        display_order, notes, tags,
        entry_price, target_price, stop_price
    )
    SELECT
        v_new_id, symbol_id, ticker_id, symbol,
        display_order, notes, tags,
        entry_price, target_price, stop_price
    FROM trading.watchlist_items
    WHERE watchlist_id = p_watchlist_id;

    -- Incrementar contador de copias
    UPDATE trading.watchlists
    SET copy_count = copy_count + 1
    WHERE id = p_watchlist_id;

    RETURN v_new_id;
END;
$$ LANGUAGE plpgsql;

-- Vista de watchlists con items
CREATE OR REPLACE VIEW trading.v_watchlists_with_items AS
SELECT
    w.id,
    w.user_id,
    w.name,
    w.description,
    w.color,
    w.is_default,
    w.is_pinned,
    w.item_count,
    w.display_order,
    (
        SELECT jsonb_agg(jsonb_build_object(
            'symbol', wi.symbol,
            'current_price', wi.current_price,
            'price_change_percent', wi.price_change_percent,
            'notes', wi.notes
        ) ORDER BY wi.display_order)
        FROM trading.watchlist_items wi
        WHERE wi.watchlist_id = w.id
    ) AS items
FROM trading.watchlists w
ORDER BY w.is_pinned DESC, w.display_order, w.name;

-- Vista de items con precios actualizados
CREATE OR REPLACE VIEW trading.v_watchlist_items_live AS
SELECT
    wi.id,
    wi.watchlist_id,
    wi.symbol,
    t.name AS symbol_name,
    t.type AS symbol_type,
    t.current_bid,
    t.current_ask,
    wi.current_price,
    wi.price_change_percent,
    wi.entry_price,
    wi.target_price,
    wi.stop_price,
    wi.notes,
    wi.display_order
FROM trading.watchlist_items wi
LEFT JOIN market_data.tickers t ON wi.symbol = t.symbol
ORDER BY wi.watchlist_id, wi.display_order;

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

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

CREATE POLICY watchlists_user_isolation ON trading.watchlists
    FOR ALL
    USING (user_id = current_setting('app.current_user_id', true)::UUID);

-- RLS para watchlist_items (hereda de watchlist via JOIN)
ALTER TABLE trading.watchlist_items ENABLE ROW LEVEL SECURITY;

CREATE POLICY watchlist_items_via_watchlist ON trading.watchlist_items
    FOR ALL
    USING (
        watchlist_id IN (
            SELECT id FROM trading.watchlists
            WHERE user_id = current_setting('app.current_user_id', true)::UUID
        )
    );

-- Grants
GRANT SELECT, INSERT, UPDATE, DELETE ON trading.watchlists TO trading_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON trading.watchlist_items TO trading_app;
GRANT SELECT ON trading.watchlists TO trading_readonly;
GRANT SELECT ON trading.watchlist_items TO trading_readonly;
GRANT SELECT ON trading.v_watchlists_with_items TO trading_app;
GRANT SELECT ON trading.v_watchlist_items_live TO trading_app;
GRANT EXECUTE ON FUNCTION trading.copy_watchlist TO trading_app;
