/*
 The MIT License (MIT)

 Copyright (c) 2017 Nedim Cholich

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
package co.frontyard.cordova.plugin.exoplayer;

import android.util.Log;
import android.app.*;
import android.content.*;
// import android.content.res.Resources;
import android.graphics.Color;
import android.media.*;
import android.net.*;
import android.os.*;
import android.util.*;
import android.view.*;
import android.widget.*;
import com.google.android.exoplayer2.*;
import com.google.android.exoplayer2.extractor.*;
import com.google.android.exoplayer2.source.*;
import com.google.android.exoplayer2.source.dash.*;
import com.google.android.exoplayer2.source.hls.*;
import com.google.android.exoplayer2.source.smoothstreaming.*;
import com.google.android.exoplayer2.trackselection.*;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.ui.*;
import com.google.android.exoplayer2.upstream.*;
import com.google.android.exoplayer2.util.*;
import com.squareup.picasso.*;
import java.lang.*;
import java.lang.Math;
import java.lang.Override;
import java.util.*;
import org.apache.cordova.*;
import org.json.*;
// import android.widget.TextView;
// import android.widget.Toast;

public class Player {
    public static final String TAG = "ExoPlayerPlugin";
    private final Activity activity;
    private final CallbackContext callbackContext;
    private final Configuration config;
    private Dialog dialog;
    // private ExoPlayer exoPlayer;
    private ExoPlayer exoPlayer;
    private PlayerView exoView;
    private CordovaWebView webView;
    private int controllerVisibility;
    private boolean paused = false;
    private AudioManager audioManager;
    private LinearLayout backgroundLinearLayout;

    private DefaultTrackSelector trackSelector;
    private DefaultTrackSelector.Parameters trackSelectorParameters;
    DefaultTrackSelector.ParametersBuilder trackSelectorParamsBuilder;
    DefaultTrackSelector.SelectionOverride override;

    public Player(Configuration config, Activity activity, CallbackContext callbackContext, CordovaWebView webView) {
        this.config = config;
        this.activity = activity;
        this.callbackContext = callbackContext;
        this.webView = webView;
        this.audioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
    }

    private class PlayerEventListener implements ExoPlayer.Listener {
        @Override
        public void onLoadingChanged(boolean isLoading) {
            JSONObject payload = Payload.loadingEvent(Player.this.exoPlayer, isLoading);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
        }

        @Override
        public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
            Log.i(TAG, "Playback parameters changed");
        }

        // @Override
        public void onPlayerError(ExoPlaybackException error) {
            JSONObject payload = Payload.playerErrorEvent(Player.this.exoPlayer, error, null);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.ERROR, payload, true);
        }
        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            // if (config.getShowBuffering()) {
            //     LayoutProvider.setBufferingVisibility(exoView, activity, playbackState == ExoPlayer.STATE_BUFFERING);
            // }
            JSONObject payload = Payload.stateEvent(Player.this.exoPlayer, playbackState, Player.this.controllerVisibility == View.VISIBLE);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
        }

        @Override
        public void onPositionDiscontinuity(int reason) {
            JSONObject payload = Payload.positionDiscontinuityEvent(Player.this.exoPlayer, reason);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
        }
    
        @Override
        public void onSeekProcessed() {
        }

        // @Override
        public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
            // Need to see if we want to send this to Cordova.
            JSONObject payload = Payload.tracksChanged(Player.this.exoPlayer, trackGroups, trackSelections);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
        }

        // public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
        //     // Get layout params of view
        //     // Use MyView.this to refer to the current MyView instance 
        //     // inside a callback
        // }

        // @Override
        // public void onTracksInfoChanged(TracksInfo tracksInfo) {
        //     // Need to see if we want to send this to Cordova.
        // }
    };

    private DialogInterface.OnDismissListener dismissListener = new DialogInterface.OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialog) {
            if (exoPlayer != null) {
                exoPlayer.release();
            }
            exoPlayer = null;
            JSONObject payload = Payload.stopEvent(exoPlayer);
            new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
        }
    };

    private DialogInterface.OnKeyListener onKeyListener = new DialogInterface.OnKeyListener() {
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            int action = event.getAction();
            String key = KeyEvent.keyCodeToString(event.getKeyCode());
            // We need android to handle these key events
            if (key.equals("KEYCODE_VOLUME_UP") ||
                    key.equals("KEYCODE_VOLUME_DOWN") ||
                    key.equals("KEYCODE_VOLUME_MUTE")) {
                return false;
            }
            else {
                JSONObject payload = Payload.keyEvent(event);
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
                return true;
            }
        }
    };

    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
        int previousAction = -1;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            int eventAction = event.getAction();
            if (previousAction != eventAction) {
                previousAction = eventAction;
                JSONObject payload = Payload.touchEvent(event);
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
            }
            return true;
        }
    };

    private PlayerControlView.VisibilityListener playbackControlVisibilityListener = new PlayerControlView.VisibilityListener() {
        @Override
        public void onVisibilityChange(int visibility) {
            Player.this.controllerVisibility = visibility;
        }
    };

    private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
        public void onAudioFocusChange(int focusChange) {
            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                JSONObject payload = Payload.audioFocusEvent(Player.this.exoPlayer, "AUDIOFOCUS_LOSS_TRANSIENT");
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
            }
            else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
                JSONObject payload = Payload.audioFocusEvent(Player.this.exoPlayer, "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
            }
            else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                JSONObject payload = Payload.audioFocusEvent(Player.this.exoPlayer, "AUDIOFOCUS_GAIN");
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
            }
            else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                JSONObject payload = Payload.audioFocusEvent(Player.this.exoPlayer, "AUDIOFOCUS_LOSS");
                new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
            }
        }
    };

    public void createPlayerTransparent() {
        createTransparentPlayer();
        preparePlayer(config.getUri());
    }

    public void createTransparentPlayer() {
        webView.getView().setBackgroundColor(Color.TRANSPARENT);

        FrameLayout mainLayout = LayoutProvider.getMainLayout(this.activity);
        exoView = LayoutProvider.getExoPlayerView(this.activity, config);
        exoView.setControllerVisibilityListener(playbackControlVisibilityListener);
        mainLayout.addView(exoView);

        backgroundLinearLayout = LayoutProvider.getBackgroundLinearLayout(this.activity);
        backgroundLinearLayout.addView(mainLayout);

        FrameLayout wrapperFrameLayout = (FrameLayout) this.webView.getView().getParent();
        wrapperFrameLayout.addView(backgroundLinearLayout, 0);

        exoView.requestFocus();
        exoView.setOnTouchListener(onTouchListener);
    }

    private void preparePlayer(Uri uri) {
        // DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        // TrackSelector trackSelector = new DefaultTrackSelector();
        // LoadControl loadControl = new DefaultLoadControl();

        exoPlayer = new ExoPlayer.Builder(this.activity).build();
        exoPlayer.addListener(new PlayerEventListener());
        if (null != exoView) {
            exoView.setPlayer(exoPlayer);
        }

        MediaItem mediaItem = MediaItem.fromUri(uri);
        exoPlayer.addMediaItem(mediaItem);
        long offset = config.getSeekTo();
        boolean autoPlay = config.autoPlay();
        if (offset > -1) {
            exoPlayer.seekTo(offset);
        }

        exoPlayer.prepare();

        exoPlayer.setPlayWhenReady(autoPlay);
        paused = !autoPlay;

        JSONObject payload = Payload.startEvent(exoPlayer); // , audioFocusString
        new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.OK, payload, true);
    }

    public void close() {
        FrameLayout wrapperFrameLayout = (FrameLayout) this.webView.getView().getParent();
        audioManager.abandonAudioFocus(audioFocusChangeListener);
        if (exoPlayer != null) {
            exoPlayer.removeListener(new PlayerEventListener());
            exoPlayer.stop();
            exoPlayer.release();
            exoPlayer = null;
        }

        if (backgroundLinearLayout != null) {
            backgroundLinearLayout.removeAllViews();
            wrapperFrameLayout.removeView(backgroundLinearLayout);
        }

        if (this.dialog != null) {
            dialog.dismiss();
        }
    }

    public void playPause() {
        if (this.paused) {
            play();
        }
        else {
            pause();
        }
    }

    public void pause() {
        if (null != exoPlayer) {
            paused = true;
            exoPlayer.setPlayWhenReady(false);
        }
    }

    public void play() {
        paused = false;
        exoPlayer.setPlayWhenReady(true);
    }

    public void stop() {
        paused = false;
        exoPlayer.stop();
    }

    private long normalizeOffset(long newTime) {
        long duration = exoPlayer.getDuration();
        return duration == 0 ? 0 : Math.min(Math.max(0, newTime), duration);
    }

    public JSONObject seekTo(long timeMillis) {
        long newTime = normalizeOffset(timeMillis);
        exoPlayer.seekTo(newTime);
        JSONObject payload = Payload.seekEvent(Player.this.exoPlayer, newTime);
        return payload;
    }

    public JSONObject seekBy(long timeMillis) {
        long newTime = normalizeOffset(exoPlayer.getCurrentPosition() + timeMillis);
        exoPlayer.seekTo(newTime);
        JSONObject payload = Payload.seekEvent(Player.this.exoPlayer, newTime);
        return payload;
    }

    public JSONObject getPlayerState() {
        return Payload.stateEvent(exoPlayer,
                null != exoPlayer ? exoPlayer.getPlaybackState() : com.google.android.exoplayer2.Player.STATE_ENDED,
                Player.this.controllerVisibility == View.VISIBLE);
    }

    public void showController() {
        if (null != exoView) {
            exoView.showController();
        }
    }

    public void hideController() {
        if (null != exoView) {
            exoView.hideController();
        }
    }

    // public void setController(JSONObject controller) {
    //     // if (null != exoView) {
    //     //     LayoutProvider.setupController(exoView, activity, controller);
    //     // }
    // }

    private void sendError(String msg) {
        Log.e(TAG, msg);
        JSONObject payload = Payload.playerErrorEvent(Player.this.exoPlayer, null, msg);
        new CallbackResponse(Player.this.callbackContext).send(PluginResult.Status.ERROR, payload, true);
    }

    /* My Own Functions */
    
    public void subTitleOff() {
        trackSelector.setParameters(new DefaultTrackSelector.ParametersBuilder()
                .setRendererDisabled(C.TRACK_TYPE_VIDEO, true)
                .build()
        );
    }
    public void subTitleOn() {
 
            // trackSelector.setParameters(new DefaultTrackSelector.ParametersBuilder()
            //         .setRendererDisabled(C.TRACK_TYPE_VIDEO, false)
            //         .build()
            // );
            // showToast("subTitle ON");
    }

    public int getDuration() {
        int duration = Payload.getDuration(exoPlayer);
        return duration;
    }

    public int getCurrentPosition() {
        return (int) exoPlayer.getCurrentPosition();
    }

    public void getTotalTrackInfo() {

    }

    // public int getAudios() {
    //     return exoPlayer.getCurrentTrackGroups().length;
    // }

    public void setAudioTrack(int index) {

        // TrackGroupArray trackGroups = trackSelector.getCurrentMappedTrackInfo().getTrackGroups(1);
        // DefaultTrackSelector.ParametersBuilder parametersBuilder = trackSelector.buildUponParameters();
        // DefaultTrackSelector.SelectionOverride override = new DefaultTrackSelector.SelectionOverride(index, 0);
        // boolean isDisabled = trackSelector.getParameters().getRendererDisabled(1);
        // parametersBuilder.setRendererDisabled(1, isDisabled);
        // if (override != null) {
        //     sendError("override null");
        //     parametersBuilder.setSelectionOverride(1, trackGroups, override);
        // }
        // else {
        //     sendError("nk dolu");
        //     // Log.d(TAG,"nk dolu");
        //     parametersBuilder.clearSelectionOverrides(1);
        // }
        // trackSelector.setParameters(parametersBuilder);
    }

    public void setSubtitleTrack(int index) {

        // MappedTrackInfo mappedTrackInfo = Assertions.checkNotNull(trackSelector.getCurrentMappedTrackInfo());
        // DefaultTrackSelector.Parameters parameters = trackSelector.getParameters();
        // DefaultTrackSelector.ParametersBuilder builder = parameters.buildUpon();

    }

    // public void showToast(String message) {
    //     Toast.makeText(activity , message, Toast.LENGTH_LONG).show();
    // }
}
