-- ============================================================================
-- SCHEMA: llm
-- TABLE: conversations
-- DESCRIPTION: Conversaciones con el agente LLM
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 5 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Crear schema si no existe
CREATE SCHEMA IF NOT EXISTS llm;

COMMENT ON SCHEMA llm IS
'Sistema de agente LLM con conversaciones, herramientas y limites de uso';

-- Enum para tipo de conversacion
DO $$ BEGIN
    CREATE TYPE llm.conversation_type AS ENUM (
        'chat',                 -- Chat general
        'trading_assistant',    -- Asistente de trading
        'market_analysis',      -- Analisis de mercado
        'education',            -- Educacion/tutoria
        'support',              -- Soporte tecnico
        'portfolio_review',     -- Revision de portafolio
        'strategy_builder',     -- Constructor de estrategias
        'code_assistant'        -- Asistente de codigo
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para estado de conversacion
DO $$ BEGIN
    CREATE TYPE llm.conversation_status AS ENUM (
        'active',               -- Activa
        'archived',             -- Archivada
        'deleted',              -- Eliminada (soft delete)
        'expired'               -- Expirada por inactividad
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para modelo LLM
DO $$ BEGIN
    CREATE TYPE llm.llm_model AS ENUM (
        'gpt-4o',
        'gpt-4o-mini',
        'gpt-4-turbo',
        'claude-3-5-sonnet',
        'claude-3-opus',
        'claude-3-5-haiku',
        'gemini-pro',
        'gemini-ultra',
        'llama-3-70b',
        'mixtral-8x7b',
        'custom'
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Conversaciones
CREATE TABLE IF NOT EXISTS llm.conversations (
    -- 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,

    -- Tipo y estado
    type llm.conversation_type NOT NULL DEFAULT 'chat',
    status llm.conversation_status NOT NULL DEFAULT 'active',

    -- Titulo y descripcion
    title VARCHAR(255),
    description TEXT,
    auto_title BOOLEAN NOT NULL DEFAULT TRUE,           -- Generar titulo automaticamente

    -- Modelo
    model llm.llm_model NOT NULL DEFAULT 'gpt-4o-mini',
    model_config JSONB DEFAULT '{}'::JSONB,             -- Temperatura, max_tokens, etc.

    -- System prompt
    system_prompt TEXT,
    custom_instructions TEXT,

    -- Contexto
    context_type VARCHAR(50),                           -- 'symbol', 'portfolio', 'position'
    context_id UUID,                                    -- ID del contexto
    context_data JSONB DEFAULT '{}'::JSONB,             -- Datos de contexto

    -- Estadisticas
    message_count INTEGER NOT NULL DEFAULT 0,
    token_count_input INTEGER NOT NULL DEFAULT 0,
    token_count_output INTEGER NOT NULL DEFAULT 0,
    total_tokens INTEGER NOT NULL DEFAULT 0,

    -- Costo estimado
    estimated_cost_usd DECIMAL(10, 6) NOT NULL DEFAULT 0,

    -- Herramientas habilitadas
    tools_enabled VARCHAR(100)[],                       -- Herramientas disponibles
    tools_auto_execute BOOLEAN NOT NULL DEFAULT FALSE,  -- Ejecutar herramientas automaticamente

    -- Feedback
    rating INTEGER CHECK (rating BETWEEN 1 AND 5),
    feedback TEXT,
    rated_at TIMESTAMPTZ,

    -- Compartir
    is_shared BOOLEAN NOT NULL DEFAULT FALSE,
    share_code VARCHAR(20),
    shared_at TIMESTAMPTZ,

    -- Ultima actividad
    last_message_at TIMESTAMPTZ,
    last_user_message_at TIMESTAMPTZ,

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

    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    archived_at TIMESTAMPTZ,
    expires_at TIMESTAMPTZ,                             -- Para limpiar conversaciones antiguas

    -- Constraints
    CONSTRAINT conversations_share_code_unique UNIQUE (share_code)
);

COMMENT ON TABLE llm.conversations IS
'Conversaciones con el agente LLM por usuario';

COMMENT ON COLUMN llm.conversations.tools_enabled IS
'Herramientas habilitadas: market_data, portfolio, trading, charts, etc.';

-- Indices
CREATE INDEX IF NOT EXISTS idx_conversations_tenant
    ON llm.conversations(tenant_id);

CREATE INDEX IF NOT EXISTS idx_conversations_user
    ON llm.conversations(user_id);

CREATE INDEX IF NOT EXISTS idx_conversations_status
    ON llm.conversations(status);

CREATE INDEX IF NOT EXISTS idx_conversations_active
    ON llm.conversations(user_id, status, updated_at DESC)
    WHERE status = 'active';

CREATE INDEX IF NOT EXISTS idx_conversations_type
    ON llm.conversations(type);

CREATE INDEX IF NOT EXISTS idx_conversations_last_message
    ON llm.conversations(last_message_at DESC)
    WHERE status = 'active';

CREATE INDEX IF NOT EXISTS idx_conversations_share
    ON llm.conversations(share_code)
    WHERE share_code IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_conversations_context
    ON llm.conversations(context_type, context_id)
    WHERE context_id IS NOT NULL;

-- Funcion de timestamp
CREATE OR REPLACE FUNCTION llm.update_llm_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at := NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Trigger para updated_at
DROP TRIGGER IF EXISTS conversation_updated_at ON llm.conversations;
CREATE TRIGGER conversation_updated_at
    BEFORE UPDATE ON llm.conversations
    FOR EACH ROW
    EXECUTE FUNCTION llm.update_llm_timestamp();

-- Funcion para generar share code
CREATE OR REPLACE FUNCTION llm.generate_share_code()
RETURNS VARCHAR AS $$
DECLARE
    v_code VARCHAR;
    v_exists BOOLEAN;
BEGIN
    LOOP
        v_code := UPPER(SUBSTRING(MD5(RANDOM()::TEXT || NOW()::TEXT) FROM 1 FOR 8));
        SELECT EXISTS (SELECT 1 FROM llm.conversations WHERE share_code = v_code) INTO v_exists;
        EXIT WHEN NOT v_exists;
    END LOOP;
    RETURN v_code;
END;
$$ LANGUAGE plpgsql;

-- Funcion para compartir conversacion
CREATE OR REPLACE FUNCTION llm.share_conversation(p_conversation_id UUID)
RETURNS VARCHAR AS $$
DECLARE
    v_code VARCHAR;
BEGIN
    v_code := llm.generate_share_code();

    UPDATE llm.conversations
    SET is_shared = TRUE,
        share_code = v_code,
        shared_at = NOW()
    WHERE id = p_conversation_id;

    RETURN v_code;
END;
$$ LANGUAGE plpgsql;

-- Vista de conversaciones recientes
CREATE OR REPLACE VIEW llm.v_recent_conversations AS
SELECT
    id,
    user_id,
    type,
    title,
    model,
    message_count,
    total_tokens,
    estimated_cost_usd,
    last_message_at,
    created_at
FROM llm.conversations
WHERE status = 'active'
ORDER BY last_message_at DESC NULLS LAST;

-- RLS Policies
ALTER TABLE llm.conversations ENABLE ROW LEVEL SECURITY;

CREATE POLICY conversations_tenant_isolation ON llm.conversations
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

CREATE POLICY conversations_user_isolation ON llm.conversations
    FOR ALL
    USING (user_id = current_setting('app.current_user_id', true)::UUID);

-- Grants
GRANT USAGE ON SCHEMA llm TO trading_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON llm.conversations TO trading_app;
GRANT SELECT ON llm.conversations TO trading_readonly;
GRANT SELECT ON llm.v_recent_conversations TO trading_app;
GRANT EXECUTE ON FUNCTION llm.share_conversation TO trading_app;
