package com.reactlibrary;

import android.app.Application;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.reactlibrary.interfaces.IDBMediaConstants;
import com.reactlibrary.interfaces.IDBMediaListener;
import com.un4seen.bass.BASS;
import com.un4seen.bass.BASS_FX;
import com.un4seen.bass.BASSenc;
import com.un4seen.bass.BASSmix;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Locale;

public class DBMediaPlayer implements IDBMediaConstants {
    private static final String TAG = DBMediaPlayer.class.getSimpleName();

    private String mMediaPath;

    private IDBMediaListener mDBMediaListener;

    private int currrentPostion = 0;
    private int duration = 0;

    private int mChanPlay;
    private int mChanTemp;

    private boolean isPlaying = false;
    private boolean isPausing = false;
    private ArrayList<Integer> listChannelAds;

    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            currrentPostion = getChannelPosition();
            duration = getChannelLength();

            if (currrentPostion <= 0) {
                removeMessages(0);
                if (mDBMediaListener != null) {
                    mDBMediaListener.onMediaCompletion();
                }
            } else {
                sendEmptyMessageDelayed(0, 50);
            }
        }
    };

    public DBMediaPlayer(String mBeatPath) {
        this.mMediaPath = mBeatPath;
    }

    public boolean prepareAudio() {
        if (mMediaPath != null && !mMediaPath.isEmpty()) {
            if (mMediaPath.toLowerCase(Locale.getDefault()).endsWith(TYPE_MP3)
                    || mMediaPath.toLowerCase(Locale.getDefault()).endsWith(TYPE_WAV)
                    || mMediaPath.toLowerCase(Locale.getDefault()).endsWith(TYPE_OGG)
                    || mMediaPath.toLowerCase(Locale.getDefault()).endsWith(TYPE_FLAC)) {
                this.initMedia();
                return true;
            } else {
                new Exception("DBMidiPlayer:can not support file format").printStackTrace();
            }
        }
        return false;
    }

    public void startAudio() {
        this.isPlaying = true;
        if (mChanPlay != 0) {
            BASS.BASS_ChannelPlay(mChanPlay, false);
        }
        this.mHandler.sendEmptyMessage(0);
    }

    public void pauseAudio() {
        if (!isPlaying) {
            new Exception(TAG + " pauseAudio:HanetMediaPlayer not init").printStackTrace();
            return;
        }
        this.isPausing = true;
        if (mChanPlay != 0) {
            BASS.BASS_ChannelPause(mChanPlay);
        }

    }

    public void releaseAudio() {
        mHandler.removeMessages(0);

        isPlaying = false;
        isPausing = false;

        BASS.BASS_StreamFree(mChanPlay);
        BASS.BASS_StreamFree(mChanTemp);
        if (listChannelAds != null && listChannelAds.size() > 0) {
            for (Integer mInteger : listChannelAds) {
                BASS.BASS_StreamFree(mInteger);
            }
            listChannelAds.clear();
            listChannelAds = null;
        }
        mChanTemp = 0;
        mChanPlay = 0;
        Log.d(TAG, "=======>release ALL");
    }

    public void setAudioPitch(int semitone) {
        if (mChanPlay != 0) {
            BASS.BASS_ChannelSetAttribute(mChanPlay, BASS_FX.BASS_ATTRIB_TEMPO_PITCH, semitone);
        }
    }

    public void setAudioRate(float value) {
        if (mChanPlay != 0) {
            BASS.BASS_ChannelSetAttribute(mChanPlay, BASS_FX.BASS_ATTRIB_TEMPO, value);
        }
    }

    public void setOnDBMediaListener(IDBMediaListener mDBMediaListener) {
        this.mDBMediaListener = mDBMediaListener;
    }

    public int getDuration() {
        if (mChanPlay != 0) {
            duration = getChannelLength();
        }
        return duration;
    }

    public int getCurrrentPostion() {
        return currrentPostion;
    }

    public boolean isPlaying() {
        return isPlaying;
    }

    public void seekTo(int position) {
        if (!isPlaying) {
            new Exception(TAG + " seekTo:HanetMediaPlayer is not playing").printStackTrace();
            return;
        }
        currrentPostion = position;
        this.seekChannelTo(position);
    }

    private void initMedia() {
        releaseAudio();
        if (mMediaPath != null && !mMediaPath.isEmpty()) {
            mChanPlay = BASS.BASS_StreamCreateFile(mMediaPath, 0, 0, BASS.BASS_STREAM_DECODE);
        }
        Log.d(TAG, "========>mChanPlay=" + mChanPlay);

        if (mChanPlay != 0) {
            //mChanPlay = BASS_FX.BASS_FX_ReverseCreate(mChanPlay, 2, BASS.BASS_STREAM_DECODE | BASS_FX.BASS_FX_FREESOURCE);
            if (mChanPlay != 0) {
                BASS.BASS_CHANNELINFO infoPlay = new BASS.BASS_CHANNELINFO();
                BASS.BASS_ChannelGetInfo(mChanPlay, infoPlay);
                mChanPlay = BASS_FX.BASS_FX_TempoCreate(mChanPlay, BASS_FX.BASS_FX_FREESOURCE);
                if (mChanPlay == 0) {
                    Log.d(TAG, "========>BASS_Error=" + BASS.BASS_ErrorGetCode());
                    new Exception(TAG + " Couldnt create a resampled stream!").printStackTrace();
                    BASS.BASS_StreamFree(mChanPlay);
                    return;
                }
            } else {
                Log.d(TAG, "========>BASS_Error=" + BASS.BASS_ErrorGetCode());
                new Exception(TAG + " Couldnt create a resampled stream!").printStackTrace();
                BASS.BASS_StreamFree(mChanPlay);
            }
        } else {
            Log.d(TAG, "========>BASS_Error=" + BASS.BASS_ErrorGetCode());
            new Exception(TAG + " Couldnt create a resampled stream!").printStackTrace();
            BASS.BASS_StreamFree(mChanPlay);
        }
    }


    public boolean initMediaToSave() {
        BASS.BASS_StreamFree(mChanPlay);
        
        mChanPlay = BASS.BASS_StreamCreateFile(mMediaPath, 0, 0, BASS.BASS_STREAM_DECODE);
        if (mChanPlay != 0) {
            Log.d(TAG, "========>mChanPlay=" + mChanPlay);
            if (mChanPlay != 0) {
                mChanPlay = BASS_FX.BASS_FX_TempoCreate(mChanPlay, BASS.BASS_STREAM_DECODE);
                if (mChanPlay == 0) {
                    new Exception(TAG + " Couldn't create a resampled stream!").printStackTrace();
                    BASS.BASS_StreamFree(mChanPlay);
                    return false;
                }
                return true;
            } else {
                new Exception(TAG + " Couldn't create a resampled stream!").printStackTrace();
                BASS.BASS_StreamFree(mChanPlay);
            }
        }
        return false;
    }

    public void seekChannelTo(int position) {
        if (mChanPlay != 0) {
            BASS.BASS_ChannelSetPosition(mChanPlay, BASS.BASS_ChannelSeconds2Bytes(mChanPlay, position), BASS.BASS_POS_BYTE);
        }
    }

    private int getChannelPosition() {
        if (mChanTemp != 0) {
            int p = (int) BASS.BASS_ChannelBytes2Seconds(mChanTemp, BASS.BASS_ChannelGetPosition(mChanTemp, BASS.BASS_POS_BYTE));
            return p;
        }
        if (mChanPlay != 0) {
            int p = (int) BASS.BASS_ChannelBytes2Seconds(mChanPlay, BASS.BASS_ChannelGetPosition(mChanPlay, BASS.BASS_POS_BYTE));
            return p;
        }
        return -1;
    }

    private int getChannelLength() {
        if (mChanTemp != 0) {
            int p = (int) BASS.BASS_ChannelBytes2Seconds(mChanTemp, BASS.BASS_ChannelGetLength(mChanTemp, BASS.BASS_POS_BYTE));
            return p;
        }
        if (mChanPlay != 0) {
            int p = (int) BASS.BASS_ChannelBytes2Seconds(mChanPlay, BASS.BASS_ChannelGetLength(mChanPlay, BASS.BASS_POS_BYTE));
            return p;
        }
        return 0;
    }

    public void saveToFile(String filePath) {
        if (filePath != null && filePath != "" && mChanPlay != 0) {
            int encoder = BASSenc.BASS_Encode_Start(mChanPlay, filePath,
                    BASSenc.BASS_ENCODE_PCM | BASSenc.BASS_ENCODE_AUTOFREE, null, 0);

            if (encoder != 0) {
                try {
                    ByteBuffer buf = ByteBuffer.allocateDirect(16384); // allocate buffer for decoding
                    while (true) {
                        int r = BASS.BASS_ChannelGetData(mChanPlay, buf, buf.capacity()); // decode some data (and send it to WAV writer)

                        if (r == -1 || r == 0) {
                            break;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
