import os
import torch
import torchaudio
import numpy as np
from tqdm import tqdm

from suno_utils.utils.text import read_jsonl
from suno_utils.audio import Audio
from suno_utils.tasks.dac_2c_12cb import (
    encode as codec_encode,
    decode as codec_decode,
    EMBEDDING_RATE as CODEC_EMBEDDING_RATE,
)
from suno_utils.tasks.dac_2c_12cb import preload_models as preload_codec_models


N_TOKENS_MEMMAP = 6016
SEMANTIC_N_CODEBOOKS = 1
COARSE_N_CODEBOOKS = 12


def remove_pad_tokens(arr, value: int = 2048):
    # Find the last index where the value is not equal to the specified value
    non_value_index = np.where(arr != value)[0]

    if non_value_index.size == 0:
        # If there are no values that are not equal to the specified value, return an empty array
        return np.array([], dtype=arr.dtype)

    # Get the last index where the value is not equal to the specified value
    last_non_value_index = non_value_index[-1]

    # Slice the array to remove trailing values
    return arr[: last_non_value_index + 1]


if __name__ == "__main__":
    # configuration
    use_val = True
    tmp_dir = os.path.join(os.getcwd(), "tmp-validate")
    os.makedirs(tmp_dir, exist_ok=True)

    if use_val:
        s3_metas_filepath = "/app/suno/data/chirp_v4_ft/multi/metas_val.jsonl"
        memmap_filepath = "/app/suno/data/chirp_v4/multi/data_val.bin"
    else:
        s3_metas_filepath = "/app/suno/data/chirp_v4_ft/multi/metas_tr.jsonl"
        memmap_filepath = "/app/suno/data/chirp_v4/multi/data_tr.bin"

    # load DAC codec
    _ = preload_codec_models(
        checkpoint_filepath="s3://suno-data/georg/models/codec/dac_2c_25x12.pt",
    )

    # load memmap
    mm = np.memmap(os.path.join(memmap_filepath), dtype=np.uint16, mode="r")
    mm = mm.reshape(-1, N_TOKENS_MEMMAP, SEMANTIC_N_CODEBOOKS + COARSE_N_CODEBOOKS)

    # load the memmap aligned jsonl file
    print(f"Reading {s3_metas_filepath} from disk...")
    s3_metas = read_jsonl(s3_metas_filepath)

    print(mm.shape, len(s3_metas))
    assert mm.shape[0] == len(s3_metas)

    for idx, meta in enumerate(tqdm(s3_metas)):
        dataset = meta.get("dataset")
        s3_filepath = meta.get("s3_filepath")
        id_key = meta.get("id")

        # print(dataset, s3_filepath)
        if s3_filepath is not None:
            s3_audio = Audio.from_s3(s3_filepath, n_channels=2)
            s3_audio_sample_rate = s3_audio.sample_rate
            s3_audio = torch.from_numpy(s3_audio.array_float)
            s3_audio /= s3_audio.abs().max()

            codes = remove_pad_tokens(mm[idx, :, 1:])
            decoded_audio = codec_decode(codes)
            decoded_audio = torch.from_numpy(decoded_audio.array_float)
            decoded_audio /= decoded_audio.abs().max()

            print(s3_audio.shape, decoded_audio.shape)

            s3_audio_out = os.path.join(tmp_dir, f"{idx}-{id_key}-s3.wav")
            decoded_audio_out = os.path.join(tmp_dir, f"{idx}-{id_key}-memmap.wav")
            torchaudio.save(s3_audio_out, s3_audio, s3_audio_sample_rate)
            torchaudio.save(decoded_audio_out, decoded_audio, 48_000)

        if idx > 10:
            break
