import os
import glob
import torch
import shutil
import random
import numpy as np
import gymnasium as gym
from gymnasium.spaces import Discrete, Box
from moviepy.editor import VideoFileClip, concatenate_videoclips


def moving_average(a, n):
    """
    Return an array of the moving average of a with window size n
    """
    if len(a) <= n:
        return a
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return ret[n - 1:] / n

def get_epsilon(step, eps_min, eps_max, eps_steps):
    """
    Return the linearly descending epsilon of the current step for the epsilon-greedy policy. After eps_steps, epsilon will keep at eps_min
    """
    ############################
    # YOUR IMPLEMENTATION HERE #
    return max(eps_min, eps_max - (step / eps_steps) * (eps_max - eps_min))
    ############################

def merge_videos(video_dir):
    """
    Merge videos in the video_dir into a single video    
    """
    videos = glob.glob(os.path.join(video_dir, "*.mp4"))
    videos = sorted(videos, key=lambda x: int(x.split("-")[-1].split(".")[0]))
    clip = concatenate_videoclips([VideoFileClip(video) for video in videos])
    clip.write_videofile(f"{video_dir}.mp4")
    shutil.rmtree(video_dir)


def set_seed_everywhere(env: gym.Env, seed=0):
    """
    Set seed for all randomness sources
    """
    env.action_space.seed(seed)
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    os.environ["PYTHONHASHSEED"] = str(seed)


def get_space_shape(space):
    """
    Return the shape of the gym.Space object
    """
    if isinstance(space, Discrete):
        return space.n
    elif isinstance(space, Box):
        if len(space.shape) == 1:
            return space.shape[0]
        else:
            return space.shape
    else:
        raise ValueError(f"Space not supported: {space}")
