"""Example: run DiscoRL agent inference on a Gym env (PoC).

This script demonstrates how to:
 - discretize a continuous Gym action space (quick PoC),
 - adapt the Gym env to DiscoRL's Environment interface using
   `disco_gym_adapter.GymToDiscoEnv`, and
 - run a few actor steps with the DiscoRL Agent (inference only).

Important constraints and notes:
 - The provided DiscoRL code expects a scalar discrete action space by
   design (see Agent.__init__). To avoid large code changes we discretize
   your continuous action space into a small action set.
 - This example performs inference only using the freshly initialised
   agent parameters (no meta-training). If you want to run meta-training or
   reproduce the paper, keep using the JAX harness and the original
   training notebooks / scripts.
"""

import os
import sys

# ============================================================================
# JAX/CUDA Configuration: Prevent GPU conflicts between JAX and LBM simulator.
# If you encounter segmentation faults, try setting JAX_PLATFORM_NAME=cpu
# in your shell environment before running this script.
# ============================================================================
# Uncomment below to force JAX to CPU-only mode (safest for PoC):
os.environ['JAX_PLATFORMS'] = 'cpu'

import time
import numpy as np
import jax

# Make sure DiscoRL package is importable. If you installed it with
# `pip install -e ./disco_rl` then the plain import below will work. If not,
# try adding the repo-local path to sys.path.
current_dir = os.path.dirname(os.path.abspath(__file__))
repo_root = os.path.abspath(os.path.join(current_dir, os.pardir))
sys.path.append(os.path.join(repo_root, "disco_rl"))

from disco_gym_adapter import GymToDiscoEnv
from gym_env_250326_erase import CustomEnv

from disco_rl import agent as disco_agent


def main():
  # Choose a small discrete action set (example: grid over each continuous dim).
  # Here the original env has action shape (3,) with each element in [-1,1].
  # We build a simple 5-action set: no-op + ±1 on each axis (sparse).
  discrete_actions = np.array([
      [0.0, 0.0, 0.0],
      [1.0, 0.0, 0.0],
      [-1.0, 0.0, 0.0],
      [0.0, 1.0, 0.0],
      [0.0, -1.0, 0.0],
  ], dtype=np.float32)

  # Build the Disco adapter with discrete actions (batch_size=1).
  base_kwargs = dict(device_id=2)
  disco_env = GymToDiscoEnv(
      gym_env_cls=lambda **kw: CustomEnv(**base_kwargs),
      batch_size=1,
      env_settings=None,
      discrete_actions=discrete_actions,
  )

  # Create agent and settings.
  settings = disco_agent.get_settings_disco()

  # Get action/observation specs from the adapted env.
  single_obs_spec = disco_env.single_observation_spec()
  single_act_spec = disco_env.single_action_spec()
  
  print('Action spec:', single_act_spec)
  print('Observation spec:', single_obs_spec)

  # Create the DiscoRL agent.
  agent = disco_agent.Agent(
      single_observation_spec=single_obs_spec,
      single_action_spec=single_act_spec,
      agent_settings=settings,
      batch_axis_name=None,
  )

  rng = jax.random.PRNGKey(0)
  learner_state = agent.initial_learner_state(rng)
  actor_state = agent.initial_actor_state(rng)

  # Reset environment and run a small rollout.
  _, env_t = disco_env.reset()
  print('\nInitial observation shape:', env_t.observation['observation'].shape)
  print('Initial observation:', env_t.observation)

  print('\nRunning 10 inference steps...')
  for step in range(10):
    rng, subkey = jax.random.split(rng)
    actor_timestep, actor_state = agent.actor_step(
        learner_state.params, subkey, env_t, actor_state
    )
    # actor_timestep.actions is a JAX array (discrete indices). Convert to numpy.
    action = np.asarray(actor_timestep.actions)[0]
    # Step the Gym env via the adapter: pass the discrete action index.
    _, env_t = disco_env.step(None, np.array([action]))
    reward = np.asarray(env_t.reward)
    print(f'  step {step:2d}  action={int(action)}  reward={reward[0] if hasattr(reward, "__len__") else reward:.4f}')
  
  print('\nPoC completed successfully!')

if __name__ == '__main__':
  try:
    main()
  except Exception as e:
    print(f'Error during execution: {e}')
    import traceback
    traceback.print_exc()
