-- =====================================================
-- FUNCTION: education.update_gamification_profile()
-- =====================================================
-- Proyecto: OrbiQuant IA (Trading Platform)
-- Módulo: OQI-002 - Education
-- Especificación: Función adicional para gamificación
-- Descripción: Actualiza el perfil de gamificación del usuario
-- =====================================================

-- Función para actualizar XP y nivel
CREATE OR REPLACE FUNCTION education.update_user_xp(
  p_user_id UUID,
  p_xp_to_add INTEGER
)
RETURNS VOID AS $$
DECLARE
  v_profile RECORD;
  v_new_total_xp INTEGER;
  v_new_level INTEGER;
  v_xp_to_next INTEGER;
BEGIN
  -- Obtener o crear perfil
  INSERT INTO education.user_gamification_profile (user_id)
  VALUES (p_user_id)
  ON CONFLICT (user_id) DO NOTHING;

  -- Obtener perfil actual
  SELECT * INTO v_profile
  FROM education.user_gamification_profile
  WHERE user_id = p_user_id;

  -- Calcular nuevo XP total
  v_new_total_xp := v_profile.total_xp + p_xp_to_add;

  -- Calcular nuevo nivel (cada nivel requiere 100 XP más que el anterior)
  -- Nivel 1: 0-99 XP, Nivel 2: 100-299 XP, Nivel 3: 300-599 XP, etc.
  v_new_level := FLOOR((-100 + SQRT(10000 + 800 * v_new_total_xp)) / 200) + 1;

  -- XP necesario para siguiente nivel
  v_xp_to_next := (v_new_level * 100 + (v_new_level * (v_new_level - 1) * 100)) - v_new_total_xp;

  -- Actualizar perfil
  UPDATE education.user_gamification_profile
  SET
    total_xp = v_new_total_xp,
    current_level = v_new_level,
    xp_to_next_level = v_xp_to_next,
    weekly_xp = weekly_xp + p_xp_to_add,
    monthly_xp = monthly_xp + p_xp_to_add,
    last_activity_date = CURRENT_DATE,
    updated_at = NOW()
  WHERE user_id = p_user_id;

  -- Si subió de nivel, crear achievement
  IF v_new_level > v_profile.current_level THEN
    INSERT INTO education.user_achievements (
      user_id,
      achievement_type,
      title,
      description,
      xp_bonus
    ) VALUES (
      p_user_id,
      'level_up',
      'Level Up! - Nivel ' || v_new_level,
      'Has alcanzado el nivel ' || v_new_level,
      50
    );
  END IF;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION education.update_user_xp(UUID, INTEGER) IS 'Actualiza XP del usuario y recalcula nivel';

-- Función para actualizar streak
CREATE OR REPLACE FUNCTION education.update_user_streak(p_user_id UUID)
RETURNS VOID AS $$
DECLARE
  v_last_activity DATE;
  v_current_streak INTEGER;
  v_longest_streak INTEGER;
BEGIN
  -- Obtener o crear perfil
  INSERT INTO education.user_gamification_profile (user_id)
  VALUES (p_user_id)
  ON CONFLICT (user_id) DO NOTHING;

  -- Obtener datos actuales
  SELECT last_activity_date, current_streak_days, longest_streak_days
  INTO v_last_activity, v_current_streak, v_longest_streak
  FROM education.user_gamification_profile
  WHERE user_id = p_user_id;

  -- Actualizar streak
  IF v_last_activity IS NULL THEN
    -- Primera actividad
    v_current_streak := 1;
  ELSIF v_last_activity = CURRENT_DATE THEN
    -- Ya tuvo actividad hoy, no hacer nada
    RETURN;
  ELSIF v_last_activity = CURRENT_DATE - INTERVAL '1 day' THEN
    -- Actividad día consecutivo
    v_current_streak := v_current_streak + 1;
  ELSE
    -- Se rompió el streak
    v_current_streak := 1;
  END IF;

  -- Actualizar longest streak si corresponde
  IF v_current_streak > v_longest_streak THEN
    v_longest_streak := v_current_streak;

    -- Crear achievement por streak milestones
    IF v_current_streak IN (7, 30, 100) THEN
      INSERT INTO education.user_achievements (
        user_id,
        achievement_type,
        title,
        description,
        xp_bonus,
        metadata
      ) VALUES (
        p_user_id,
        'streak_milestone',
        'Streak de ' || v_current_streak || ' días',
        'Has mantenido una racha de ' || v_current_streak || ' días consecutivos',
        v_current_streak * 5,
        jsonb_build_object('streak_days', v_current_streak)
      );
    END IF;
  END IF;

  -- Actualizar perfil
  UPDATE education.user_gamification_profile
  SET
    current_streak_days = v_current_streak,
    longest_streak_days = v_longest_streak,
    last_activity_date = CURRENT_DATE,
    updated_at = NOW()
  WHERE user_id = p_user_id;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION education.update_user_streak(UUID) IS 'Actualiza streak del usuario basado en actividad diaria';

-- Trigger para actualizar streak en actividades
CREATE OR REPLACE FUNCTION education.trigger_update_streak()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM education.update_user_streak(NEW.user_id);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_streak_on_activity
  AFTER INSERT ON education.user_activity_log
  FOR EACH ROW
  EXECUTE FUNCTION education.trigger_update_streak();
