using System;
using System.IO;
using System.Threading.Tasks;

namespace Abuksigun.Piper
{
    public sealed unsafe class PiperVoice : IDisposable
    {
        Piper piper;
        PiperLib.Voice* voice;

        public Piper Piper => piper;
        internal PiperLib.Voice* Voice => voice;

        PiperVoice(Piper piper, PiperLib.Voice* voice)
        {
            this.piper = piper;
            this.voice = voice;
        }

        ~PiperVoice()
        {
            Dispose();
        }

        public void Dispose()
        {
            if (voice != null)
            {
                PiperLib.destroy_Voice(voice);
                voice = null;
            }
        }

        public static Task<PiperVoice> LoadPiperVoice(Piper piper, string fullModelPath)
        {
            if (!File.Exists(fullModelPath))
                throw new FileNotFoundException("Model file not found", fullModelPath);
            if (!File.Exists(fullModelPath + ".json"))
                throw new FileNotFoundException("Model descriptor not found (Make sure it has the same name as model + .json)", fullModelPath);

            return Task.Run(() =>
            {
                var newVoice = PiperLib.create_Voice();
                try
                {
                    PiperLib.loadVoice(piper.Config, fullModelPath, fullModelPath + ".json", newVoice, null);
                    return Task.FromResult(new PiperVoice(piper, newVoice));
                }
                catch
                {
                    PiperLib.destroy_Voice(newVoice);
                    throw;
                }
            });
        }

        public float[] TextToPCMAudio(string text)
        {
            float[] audioData = new float[0];
            TextToAudioStream(text, (short* data, int length) =>
            {
                int writeIndex = audioData.Length;
                Array.Resize(ref audioData, audioData.Length + length);
                for (int i = writeIndex; i < audioData.Length; i++)
                    audioData[i] = data[i] / 32768f;
            });

            return audioData;
        }

        public void TextToAudioStream(string text, PiperLib.AudioCallbackDelegate audioCallback)
        {
            PiperLib.SynthesisResult result = new PiperLib.SynthesisResult();
            PiperLib.textToAudio(piper.Config, voice, text, &result, audioCallback);
        }
    }
}