/*
 * Copyright (C) 2020 Stefan Schüller <sschueller@techdroid.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package net.schueller.peertube.activity;


import android.annotation.SuppressLint;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;

import android.preference.PreferenceManager;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.text.TextUtils;
import android.util.Log;
import android.util.Rational;
import android.util.TypedValue;

import android.view.WindowManager;
import android.widget.FrameLayout;

import android.widget.RelativeLayout;

import net.schueller.peertube.R;
import net.schueller.peertube.fragment.VideoMetaDataFragment;
import net.schueller.peertube.fragment.VideoPlayerFragment;
import net.schueller.peertube.service.VideoPlayerService;


import java.util.ArrayList;

import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;


import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PAUSE;
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_PLAY;
import static com.google.android.exoplayer2.ui.PlayerNotificationManager.ACTION_STOP;
import static net.schueller.peertube.helper.VideoHelper.canEnterPipMode;

public class VideoPlayActivity extends AppCompatActivity {

    private static final String TAG = "VideoPlayActivity";

    static boolean floatMode = false;

    private static final int REQUEST_CODE = 101;
    private BroadcastReceiver receiver;

    //This can only be called when in entering pip mode which can't happen if the device doesn't support pip mode.
    @SuppressLint("NewApi")
    public void makePipControls() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);

        ArrayList<RemoteAction> actions = new ArrayList<>();

        Intent actionIntent = new Intent(getString(R.string.app_background_audio));
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
        @SuppressLint({"NewApi", "LocalSuppress"}) Icon icon = Icon.createWithResource(getApplicationContext(), android.R.drawable.stat_sys_speakerphone);
        @SuppressLint({"NewApi", "LocalSuppress"}) RemoteAction remoteAction = new RemoteAction(icon, "close pip", "from pip window custom command", pendingIntent);
        actions.add(remoteAction);

        actionIntent = new Intent(ACTION_STOP);
        pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
        icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_stop);
        remoteAction = new RemoteAction(icon, "play", "stop the media", pendingIntent);
        actions.add(remoteAction);

        assert videoPlayerFragment != null;
        if (videoPlayerFragment.isPaused()) {
            Log.e(TAG, "setting actions with play button");
            actionIntent = new Intent(ACTION_PLAY);
            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
            icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_play);
            remoteAction = new RemoteAction(icon, "play", "play the media", pendingIntent);
        } else {
            Log.e(TAG, "setting actions with pause button");
            actionIntent = new Intent(ACTION_PAUSE);
            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, actionIntent, 0);
            icon = Icon.createWithResource(getApplicationContext(), com.google.android.exoplayer2.ui.R.drawable.exo_notification_pause);
            remoteAction = new RemoteAction(icon, "pause", "pause the media", pendingIntent);
        }
        actions.add(remoteAction);


        //add custom actions to pip window
        PictureInPictureParams params =
                new PictureInPictureParams.Builder()
                        .setActions(actions)
                        .build();
        setPictureInPictureParams(params);
    }

    public void changedToPipMode() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;
        videoPlayerFragment.showControls(false);
        //create custom actions
        makePipControls();

        //setup receiver to handle customer actions
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_STOP);
        filter.addAction(ACTION_PAUSE);
        filter.addAction(ACTION_PLAY);
        filter.addAction((getString(R.string.app_background_audio)));
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                assert action != null;
                if (action.equals(ACTION_PAUSE)) {
                    videoPlayerFragment.pauseVideo();
                    makePipControls();
                }
                if (action.equals(ACTION_PLAY)) {
                    videoPlayerFragment.unPauseVideo();
                    makePipControls();
                }

                if (action.equals(getString(R.string.app_background_audio))) {
                    unregisterReceiver(receiver);
                    finish();
                }
                if (action.equals(ACTION_STOP)) {
                    unregisterReceiver(receiver);
                    finishAndRemoveTask();
                }
            }
        };
        registerReceiver(receiver, filter);

        Log.v(TAG, "switched to pip ");
        floatMode = true;
        videoPlayerFragment.showControls(false);
    }

    public void changedToNormalMode() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;
        videoPlayerFragment.showControls(true);
        if (receiver != null) {
            unregisterReceiver(receiver);
        }
        Log.v(TAG, "switched to normal");
        floatMode = false;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set theme
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        setTheme(getResources().getIdentifier(
                sharedPref.getString(
                        getString(R.string.pref_theme_key),
                        getString(R.string.app_default_theme)
                ),
                "style",
                getPackageName())
        );

        setContentView(R.layout.activity_video_play);

        // get video ID
        Intent intent = getIntent();
        String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
                getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;
        String playingVideo = videoPlayerFragment.getVideoUuid();
        Log.v(TAG, "oncreate click: " + videoUuid + " is trying to replace: " + playingVideo);

        if (TextUtils.isEmpty(playingVideo)) {
            Log.v(TAG, "oncreate no video currently playing");
            videoPlayerFragment.start(videoUuid);
        } else if (!playingVideo.equals(videoUuid)) {
            Log.v(TAG, "oncreate different video playing currently");
            videoPlayerFragment.stopVideo();
            videoPlayerFragment.start(videoUuid);
        } else {
            Log.v(TAG, "oncreate same video playing currently");
        }

        // if we are in landscape set the video to fullscreen
        int orientation = this.getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            setOrientation(true);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
                getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);
        assert videoPlayerFragment != null;
        String videoUuid = intent.getStringExtra(VideoListActivity.EXTRA_VIDEOID);
        Log.v(TAG, "new intent click: " + videoUuid + " is trying to replace: " + videoPlayerFragment.getVideoUuid());
        String playingVideo = videoPlayerFragment.getVideoUuid();

        if (TextUtils.isEmpty(playingVideo)) {
            Log.v(TAG, "new intent no video currently playing");
            videoPlayerFragment.start(videoUuid);
        } else if (!playingVideo.equals(videoUuid)) {
            Log.v(TAG, "new intent different video playing currently");
            videoPlayerFragment.stopVideo();
            videoPlayerFragment.start(videoUuid);
        } else {
            Log.v(TAG, "new intent same video playing currently");
        }

        // if we are in landscape set the video to fullscreen
        int orientation = this.getResources().getConfiguration().orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            setOrientation(true);
        }
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        Log.v(TAG, "onConfigurationChanged()...");

        super.onConfigurationChanged(newConfig);

        // Checking the orientation changes of the screen
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            setOrientation(true);
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
            setOrientation(false);
        }
    }

    private void setOrientation(Boolean isLandscape) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
        VideoMetaDataFragment videoMetaFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);

        assert videoPlayerFragment != null;
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) videoPlayerFragment.requireView().getLayoutParams();
        params.width = FrameLayout.LayoutParams.MATCH_PARENT;
        params.height = isLandscape ? FrameLayout.LayoutParams.MATCH_PARENT : (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 250, getResources().getDisplayMetrics());

        videoPlayerFragment.requireView().setLayoutParams(params);

        if (videoMetaFragment != null) {
            FragmentTransaction transaction = fragmentManager.beginTransaction()
                    .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);

            if (isLandscape) {
                transaction.hide(videoMetaFragment);
            } else {
                transaction.show(videoMetaFragment);
            }

            transaction.commit();
        }

        videoPlayerFragment.setIsFullscreen(isLandscape);

        if ( isLandscape ) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
    }

    @Override
    protected void onDestroy() {
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
                getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;
        videoPlayerFragment.destroyVideo();

        super.onDestroy();
        Log.v(TAG, "onDestroy...");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.v(TAG, "onPause()...");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.v(TAG, "onResume()...");
    }

    @Override
    protected void onStop() {
        super.onStop();

        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
                getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;
        videoPlayerFragment.stopVideo();

        Log.v(TAG, "onStop()...");
    }

    @Override
    protected void onStart() {
        super.onStart();

        Log.v(TAG, "onStart()...");
    }

    @SuppressLint("NewApi")
    @Override
    public void onUserLeaveHint() {

        Log.v(TAG, "onUserLeaveHint()...");

        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);
        VideoMetaDataFragment videoMetaDataFragment = (VideoMetaDataFragment) fragmentManager.findFragmentById(R.id.video_meta_data_fragment);

        String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));

        assert videoPlayerFragment != null;
        assert backgroundBehavior != null;
        if ( videoMetaDataFragment.isLeaveAppExpected() )
        {
            super.onUserLeaveHint();
            return;
        }

        if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
            Log.v(TAG, "stop the video");

            videoPlayerFragment.pauseVideo();
            stopService(new Intent(this, VideoPlayerService.class));
            super.onBackPressed();

        } else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
            Log.v(TAG, "play the Audio");
            super.onBackPressed();

        } else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
            Log.v(TAG, "play in floating video");
            //canEnterPIPMode makes sure API level is high enough
            if (canEnterPipMode(this)) {
                Log.v(TAG, "enabling pip");
                enterPipMode();
            } else {
                Log.v(TAG, "unable to use pip");
            }

        } else {
            // Deal with bad entries from older version
            Log.v(TAG, "No setting, fallback");
            super.onBackPressed();

        }


    }

    // @RequiresApi(api = Build.VERSION_CODES.O)
    @SuppressLint("NewApi")
    public void onBackPressed() {

        Log.v(TAG, "onBackPressed()...");

        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment)
                getSupportFragmentManager().findFragmentById(R.id.video_player_fragment);

        assert videoPlayerFragment != null;

        // copying Youtube behavior to have back button exit full screen.
        if (videoPlayerFragment.getIsFullscreen()) {
            Log.v(TAG, "exiting full screen");
            videoPlayerFragment.fullScreenToggle();
            return;
        }
        // pause video if pref is enabled
        if (sharedPref.getBoolean(getString(R.string.pref_back_pause_key), true)) {
            videoPlayerFragment.pauseVideo();
        }

        String backgroundBehavior = sharedPref.getString(getString(R.string.pref_background_behavior_key), getString(R.string.pref_background_stop_key));

        assert backgroundBehavior != null;

        if (backgroundBehavior.equals(getString(R.string.pref_background_stop_key))) {
            Log.v(TAG, "stop the video");
            videoPlayerFragment.pauseVideo();
            stopService(new Intent(this, VideoPlayerService.class));
            super.onBackPressed();

        } else if (backgroundBehavior.equals(getString(R.string.pref_background_audio_key))) {
            Log.v(TAG, "play the Audio");
            super.onBackPressed();

        } else if (backgroundBehavior.equals(getString(R.string.pref_background_float_key))) {
            Log.v(TAG, "play in floating video");
            //canEnterPIPMode makes sure API level is high enough
            if (canEnterPipMode(this)) {
                Log.v(TAG, "enabling pip");
                enterPipMode();
                //fixes problem where back press doesn't bring up video list after returning from PIP mode
                Intent intentSettings = new Intent(this, VideoListActivity.class);
                this.startActivity(intentSettings);
            } else {
                Log.v(TAG, "Unable to enter PIP mode");
                super.onBackPressed();
            }

        } else {
            // Deal with bad entries from older version
            Log.v(TAG, "No setting, fallback");
            super.onBackPressed();

        }


    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void enterPipMode() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        final VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById( R.id.video_player_fragment );

        if ( videoPlayerFragment.getVideoAspectRatio() == 0 ) {
            Log.i( TAG, "impossible to switch to pip" );
        } else {
            Rational rational = new Rational( (int) ( videoPlayerFragment.getVideoAspectRatio() * 100 ), 100 );
            PictureInPictureParams mParams =
                    new PictureInPictureParams.Builder()
                            .setAspectRatio( rational )
//                          .setSourceRectHint(new Rect(0,500,400,600))
                            .build();

            enterPictureInPictureMode( mParams );
        }
    }

    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        VideoPlayerFragment videoPlayerFragment = (VideoPlayerFragment) fragmentManager.findFragmentById(R.id.video_player_fragment);

        if (videoPlayerFragment != null) {

            if (isInPictureInPictureMode) {
                changedToPipMode();
                Log.v(TAG, "switched to pip ");
                videoPlayerFragment.useController(false);
            } else {
                changedToNormalMode();
                Log.v(TAG, "switched to normal");
                videoPlayerFragment.useController(true);
            }

        } else {
            Log.e(TAG, "videoPlayerFragment is NULL");
        }
    }

}
