import os
import json, json5
from pathlib import Path

import utils
from APIs import VP


def save_voice_presets_metadata(voice_presets_path, metadata):
    with open(voice_presets_path / 'metadata.json', 'w') as f:
        json.dump(metadata, f, indent=4)

def load_voice_presets_metadata(voice_presets_path, safe_if_metadata_not_exist=False):
    metadata_full_path = voice_presets_path / 'metadata.json'

    if safe_if_metadata_not_exist:
        if not os.path.exists(metadata_full_path):
            return {}

    with open(metadata_full_path, 'r') as f:
        presets = json5.load(f)

    return presets

# return system voice presets and session voice presets individually, each in a list
def get_voice_presets(session_id):
    system_presets, session_presets = [], []

    # Load system presets
    system_presets = load_voice_presets_metadata(utils.get_system_voice_preset_path())

    # Load session presets
    session_presets = load_voice_presets_metadata(
        utils.get_session_voice_preset_path(session_id),
        safe_if_metadata_not_exist=True
    )

    return system_presets, session_presets

# return merged voice presets in a {voice_preset_name: voice_preset} dict
def get_merged_voice_presets(session_id):
    system_presets, session_presets = get_voice_presets(session_id)
    res = {}
    for preset in list(system_presets.values()) + list(session_presets.values()):
        res[preset['id']] = preset  # session presets with the same id will cover that of system presets
    return res

def add_voice_preset(voice_presets_path, presets, id, desc, wav_file_path):
    if id in presets:
        raise KeyError(f'{id} already in voice preset, path={voice_presets_path}!')

    # Convert wav to npz
    npz_path = voice_presets_path / 'npz'
    VP(wav_file_path, npz_path)
    npz_file_path = npz_path / f'{Path(wav_file_path).stem}.npz'

    presets[id]  = {
        'id': id,
        'desc': desc,
        'npz_path': str(npz_file_path)
    }
    save_voice_presets_metadata(voice_presets_path, presets)
    return presets[id]

def add_session_voice_preset(id, desc, wav_file_path, session_id):
    voice_presets_path = utils.get_session_voice_preset_path(session_id)
    os.makedirs(voice_presets_path / 'npz', exist_ok=True)
    presets = load_voice_presets_metadata(voice_presets_path, safe_if_metadata_not_exist=True)
    if len(presets) >= 3:
        raise ValueError(f'session voice presets size exceed 3')
    if id in presets:
        raise KeyError(f'{id} already in voice preset, path={voice_presets_path}!')

    return add_voice_preset(voice_presets_path, presets, id, desc, wav_file_path)

def add_system_voice_preset(id, desc, wav_file_path):
    voice_presets_path = utils.get_system_voice_preset_path()
    presets = load_voice_presets_metadata(voice_presets_path)
    return add_voice_preset(voice_presets_path, presets, id, desc, wav_file_path)

# if session_id set to '', we are removing system voice presets
def remove_session_voice_preset(id, session_id):
    voice_presets_path = utils.get_session_voice_preset_path(session_id)
    presets = load_voice_presets_metadata(
        voice_presets_path,
        safe_if_metadata_not_exist=True
    )
    preset = presets.pop(id)
    npz_path = preset['npz_path']

    try:
        os.remove(npz_path)
    except FileNotFoundError:
        print(f"INFO: trying to delete {npz_path} which does not exist, path={voice_presets_path}.")

    save_voice_presets_metadata(voice_presets_path, presets)