package app.fedilab.android.fragments;
/* Copyright 2019 Thomas Schneider
 *
 * This file is a part of Fedilab
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Fedilab 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 General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with Fedilab; if not,
 * see <http://www.gnu.org/licenses>. */

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.cleveroad.audiovisualization.DbmHandler;
import com.cleveroad.audiovisualization.GLAudioVisualizationView;
import com.github.chrisbanes.photoview.PhotoView;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import com.r0adkll.slidr.Slidr;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.model.SlidrInterface;
import com.r0adkll.slidr.model.SlidrListener;
import com.r0adkll.slidr.model.SlidrPosition;

import org.jetbrains.annotations.NotNull;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Timer;
import java.util.TimerTask;

import javax.net.ssl.HttpsURLConnection;

import app.fedilab.android.R;
import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.client.Entities.Attachment;
import app.fedilab.android.client.TLSSocketFactory;
import app.fedilab.android.helper.CacheDataSourceFactory;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.webview.CustomWebview;
import app.fedilab.android.webview.MastalabWebChromeClient;
import app.fedilab.android.webview.MastalabWebViewClient;

import static android.content.Context.MODE_PRIVATE;
import static app.fedilab.android.helper.Helper.changeDrawableColor;
import static cafe.adriel.androidaudiorecorder.Util.formatSeconds;
import static cafe.adriel.androidaudiorecorder.Util.getDarkerColor;


/**
 * Created by Thomas on 09/10/2019.
 * Fragment to display media from SlideMediaActivity
 */
public class MediaSliderFragment extends Fragment implements MediaPlayer.OnCompletionListener {


    private static final Handler HANDLER = new Handler();
    private Context context;
    private SimpleExoPlayer player;
    private MediaPlayer playeraudio;
    private Timer timer;
    private int playerSecondsElapsed;
    private String url;
    private RelativeLayout loader;
    private PhotoView imageView;
    private TextView message_ready;
    private boolean canSwipe;
    private Attachment attachment;
    private TextView statusView;
    private TextView timerView;
    private ImageButton playView;
    private GLAudioVisualizationView visualizerView;
    private View rootView;
    private SlidrInterface slidrInterface;
    private boolean swipeEnabled;
    private int bgColor;
    private RelativeLayout media_fragment_container;
    private RelativeLayout content_audio;
    private PlayerView videoView;
    private CustomWebview webview_video;
    private FrameLayout webview_container;
    private RelativeLayout videoLayout;

    public MediaSliderFragment() {
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_slide_media, container, false);

        context = getContext();
        Bundle bundle = this.getArguments();

        if (bundle != null) {
            attachment = bundle.getParcelable("attachment");
            bgColor = bundle.getInt("bgcolor", R.color.black);

        }
        swipeEnabled = true;
        message_ready = rootView.findViewById(R.id.message_ready);

        content_audio = rootView.findViewById(R.id.content_audio);

        SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
        int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);

        loader = rootView.findViewById(R.id.loader);
        ImageView prev = rootView.findViewById(R.id.media_prev);
        ImageView next = rootView.findViewById(R.id.media_next);

        imageView = rootView.findViewById(R.id.media_picture);
        videoView = rootView.findViewById(R.id.media_video);
        if (theme == Helper.THEME_BLACK) {
            changeDrawableColor(context, prev, R.color.dark_icon);
            changeDrawableColor(context, next, R.color.dark_icon);
        } else if (theme == Helper.THEME_LIGHT) {
            changeDrawableColor(context, prev, R.color.mastodonC4);
            changeDrawableColor(context, next, R.color.mastodonC4);
        } else {
            changeDrawableColor(context, prev, R.color.white);
            changeDrawableColor(context, next, R.color.white);
        }

        url = attachment.getUrl();
        imageView.setOnMatrixChangeListener(rect -> {
            canSwipe = (imageView.getScale() == 1);

            if (!canSwipe) {
                if (!((SlideMediaActivity) context).getFullScreen()) {
                    ((SlideMediaActivity) context).setFullscreen(true);
                }
                enableSliding(false);
            } else {
                enableSliding(true);
            }
        });
        ProgressBar pbar_inf = rootView.findViewById(R.id.pbar_inf);
        String type = attachment.getType();
        String preview_url = attachment.getPreview_url();
        if (type.equals("unknown")) {
            preview_url = attachment.getRemote_url();
            if (preview_url.endsWith(".png") || preview_url.endsWith(".jpg") || preview_url.endsWith(".jpeg") || preview_url.endsWith(".gif")) {
                type = "image";
            } else if (preview_url.endsWith(".mp4") || preview_url.endsWith(".mp3")) {
                type = "video";
            }
            url = attachment.getRemote_url();
            attachment.setType(type);
        }
        media_fragment_container = rootView.findViewById(R.id.media_fragment_container);
        imageView.setVisibility(View.VISIBLE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            imageView.setTransitionName(attachment.getUrl());
        }
        if (Helper.isValidContextForGlide(context)) {
            Glide.with(context)
                    .asBitmap()
                    .dontTransform()
                    .load(preview_url).into(
                    new CustomTarget<Bitmap>() {
                        @Override
                        public void onResourceReady(@NonNull final Bitmap resource, Transition<? super Bitmap> transition) {
                            //Bitmap imageCompressed = Helper.compressImageIfNeeded(resource);
                            imageView.setImageBitmap(resource);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                scheduleStartPostponedTransition(imageView);
                            }
                            if (bgColor != -1) {
                                media_fragment_container.setBackgroundColor(bgColor);
                            }
                            if (attachment.getType().toLowerCase().compareTo("image") == 0 && !attachment.getUrl().endsWith(".gif")) {
                                final Handler handler = new Handler();
                                handler.postDelayed(() -> {
                                    pbar_inf.setScaleY(1f);
                                    imageView.setVisibility(View.VISIBLE);
                                    pbar_inf.setIndeterminate(true);
                                    loader.setVisibility(View.VISIBLE);
                                    if (Helper.isValidContextForGlide(context)) {
                                        Glide.with(context)
                                                .asBitmap()
                                                .dontTransform()
                                                .load(url).into(
                                                new CustomTarget<Bitmap>() {
                                                    @Override
                                                    public void onResourceReady(@NonNull final Bitmap resource, Transition<? super Bitmap> transition) {
                                                        loader.setVisibility(View.GONE);
                                                        Bitmap imageCompressed = Helper.compressImageIfNeeded(resource);
                                                        if (imageView.getScale() < 1.1) {
                                                            imageView.setImageBitmap(imageCompressed);
                                                        } else {
                                                            message_ready.setVisibility(View.VISIBLE);
                                                        }
                                                        message_ready.setOnClickListener(view -> {
                                                            imageView.setImageBitmap(imageCompressed);
                                                            message_ready.setVisibility(View.GONE);
                                                        });
                                                    }

                                                    @Override
                                                    public void onLoadCleared(@Nullable Drawable placeholder) {

                                                    }
                                                }
                                        );
                                    }
                                }, 1000);


                            } else if (attachment.getType().toLowerCase().compareTo("image") == 0 && attachment.getUrl().endsWith(".gif")) {
                                loader.setVisibility(View.GONE);
                                if (Helper.isValidContextForGlide(context)) {
                                    Glide.with(context)
                                            .load(url).into(imageView);
                                }
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                    scheduleStartPostponedTransition(imageView);
                                }
                            }
                        }

                        @Override
                        public void onLoadFailed(@Nullable Drawable errorDrawable) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                scheduleStartPostponedTransition(imageView);
                            }
                        }

                        @Override
                        public void onLoadCleared(@Nullable Drawable placeholder) {

                        }
                    }
            );
        }
        switch (type.toLowerCase()) {
            case "video":
            case "gifv":
                if (bgColor != -1) {
                    media_fragment_container.setBackgroundColor(bgColor);
                }
                pbar_inf.setIndeterminate(false);
                pbar_inf.setScaleY(3f);
                try {
                    HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory(Helper.getLiveInstance(context)));
                } catch (KeyManagementException | NoSuchAlgorithmException e) {
                    e.printStackTrace();
                }
                videoView.setVisibility(View.VISIBLE);
                Uri uri = Uri.parse(url);

                String userAgent = sharedpreferences.getString(Helper.SET_CUSTOM_USER_AGENT, Helper.USER_AGENT);
                int video_cache = sharedpreferences.getInt(Helper.SET_VIDEO_CACHE, Helper.DEFAULT_VIDEO_CACHE_MB);
                ProgressiveMediaSource videoSource;
                if (video_cache == 0) {
                    DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
                            Util.getUserAgent(context, userAgent), null);
                    videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
                            .createMediaSource(uri);
                } else {
                    CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(context);
                    videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
                            .createMediaSource(uri);
                }
                player = ExoPlayerFactory.newSimpleInstance(context);
                if (type.toLowerCase().equals("gifv"))
                    player.setRepeatMode(Player.REPEAT_MODE_ONE);
                videoView.setPlayer(player);
                loader.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
                player.prepare(videoSource);
                player.setPlayWhenReady(true);
                break;
            case "web":
                if (bgColor != -1) {
                    media_fragment_container.setBackgroundColor(bgColor);
                }
                loader.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
                webview_video = Helper.initializeWebview((Activity) context, R.id.webview_video, rootView);
                webview_video.setVisibility(View.VISIBLE);
                webview_container = rootView.findViewById(R.id.main_media_frame);
                videoLayout = rootView.findViewById(R.id.videoLayout);

                MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient((Activity) context, webview_video, webview_container, videoLayout);
                mastalabWebChromeClient.setOnToggledFullscreen(fullscreen -> {
                    if (fullscreen) {
                        videoLayout.setVisibility(View.VISIBLE);
                        WindowManager.LayoutParams attrs = ((Activity) context).getWindow().getAttributes();
                        attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
                        attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                        ((Activity) context).getWindow().setAttributes(attrs);
                        ((Activity) context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
                    } else {
                        WindowManager.LayoutParams attrs = ((Activity) context).getWindow().getAttributes();
                        attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
                        attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
                        ((Activity) context).getWindow().setAttributes(attrs);
                        ((Activity) context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                        videoLayout.setVisibility(View.GONE);
                    }
                });
                webview_video.getSettings().setAllowFileAccess(true);
                webview_video.setWebChromeClient(mastalabWebChromeClient);
                webview_video.getSettings().setDomStorageEnabled(true);
                webview_video.getSettings().setAppCacheEnabled(true);
                String user_agent = sharedpreferences.getString(Helper.SET_CUSTOM_USER_AGENT, Helper.USER_AGENT);
                webview_video.getSettings().setUserAgentString(user_agent);
                webview_video.getSettings().setMediaPlaybackRequiresUserGesture(false);
                webview_video.setWebViewClient(new MastalabWebViewClient((Activity) context));
                webview_video.loadUrl(attachment.getUrl());
                break;
            case "audio":
                if (bgColor != -1) {
                    media_fragment_container.setBackgroundColor(bgColor);
                }
                loader.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
                content_audio.setVisibility(View.VISIBLE);
                int color = getResources().getColor(R.color.mastodonC1);
                visualizerView = new GLAudioVisualizationView.Builder(context)
                        .setLayersCount(1)
                        .setWavesCount(6)
                        .setWavesHeight(R.dimen.aar_wave_height)
                        .setWavesFooterHeight(R.dimen.aar_footer_height)
                        .setBubblesPerLayer(20)
                        .setBubblesSize(R.dimen.aar_bubble_size)
                        .setBubblesRandomizeSize(true)
                        .setBackgroundColor(getDarkerColor(color))
                        .setLayerColors(new int[]{color})
                        .build();

                statusView = rootView.findViewById(R.id.status);
                timerView = rootView.findViewById(R.id.timer);
                playView = rootView.findViewById(R.id.play);
                content_audio.setBackgroundColor(getDarkerColor(color));
                content_audio.addView(visualizerView, 0);
                playView.setVisibility(View.INVISIBLE);
                this.url = attachment.getUrl();

                startPlaying();
                break;
        }
        return rootView;
    }


    private void startPlaying() {
        try {

            playeraudio = new MediaPlayer();
            playeraudio.setDataSource(url);
            playeraudio.prepare();
            playeraudio.start();

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) ==
                        PackageManager.PERMISSION_GRANTED) {
                    visualizerView.linkTo(DbmHandler.Factory.newVisualizerHandler(context, playeraudio));
                }

            }
            visualizerView.post(() -> playeraudio.setOnCompletionListener(MediaSliderFragment.this));

            timerView.setText("00:00:00");
            playView.setVisibility(View.VISIBLE);
            statusView.setText(R.string.aar_playing);
            statusView.setVisibility(View.VISIBLE);
            playView.setImageResource(R.drawable.aar_ic_stop);

            playerSecondsElapsed = 0;
            startTimer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void stopPlaying() {
        statusView.setText("");
        statusView.setVisibility(View.INVISIBLE);
        playView.setImageResource(R.drawable.aar_ic_play);

        visualizerView.release();

        if (playeraudio != null) {
            try {
                playeraudio.pause();
            } catch (Exception ignored) {
            }
        }
        stopTimer();
    }

    private void startTimer() {
        stopTimer();
        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                updateTimer();
            }
        }, 0, 1000);
    }

    private void updateTimer() {
        ((Activity) context).runOnUiThread(() -> {
            playerSecondsElapsed++;
            timerView.setText(formatSeconds(playerSecondsElapsed));
        });
    }

    private void stopTimer() {
        if (timer != null) {
            timer.cancel();
            timer.purge();
            timer = null;
        }
    }

    private boolean isPlaying() {
        try {
            return playeraudio != null && playeraudio.isPlaying();
        } catch (Exception e) {
            return false;
        }
    }

    public void togglePlaying() {

        HANDLER.postDelayed(() -> {
            if (isPlaying()) {
                stopPlaying();
            } else {
                startPlaying();
            }
        }, 100);
    }


    @Override
    public void onCreate(Bundle saveInstance) {
        super.onCreate(saveInstance);
    }


    @Override
    public void onAttach(@NotNull Context context) {
        super.onAttach(context);
        this.context = context;
    }


    @Override
    public void onPause() {
        super.onPause();
        if (player != null) {
            player.setPlayWhenReady(false);
        }
        if (playeraudio != null) {
            playeraudio.pause();
        }
        if (webview_video != null) {
            webview_video.onPause();
        }
        try {
            visualizerView.onPause();
        } catch (Exception ignored) {
        }
    }

    @Override
    public void onDestroy() {
        try {
            if (visualizerView != null) {
                visualizerView.release();
            }
            if (player != null) {
                player.release();
            }
            if (playeraudio != null) {
                playeraudio.release();
            }
        } catch (Exception ignored) {
        }
        if (webview_video != null) {
            webview_video.destroy();
        }
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        rootView = null;
    }

    @Override
    public void onResume() {
        super.onResume();
        if (player != null) {
            player.setPlayWhenReady(true);
        }
        if (playeraudio != null) {
            playeraudio.start();
        }
        try {
            visualizerView.onResume();
        } catch (Exception ignored) {
        }
        if (webview_video != null) {
            webview_video.onResume();
        }
        if (slidrInterface == null && rootView != null) {
            slidrInterface = Slidr.replace(rootView.findViewById(R.id.media_fragment_container), new SlidrConfig.Builder().sensitivity(1f)
                    .scrimColor(Color.BLACK)
                    .scrimStartAlpha(0.8f)
                    .scrimEndAlpha(0f)
                    .position(SlidrPosition.VERTICAL)
                    .velocityThreshold(2400)
                    .distanceThreshold(0.25f)
                    .edgeSize(0.18f)
                    .listener(new SlidrListener() {
                        @Override
                        public void onSlideStateChanged(int state) {

                        }

                        @Override
                        public void onSlideChange(float percent) {
                            if (percent < 0.80 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

                                if (imageView != null) {
                                    imageView.setVisibility(View.VISIBLE);
                                }
                                if (content_audio != null) {
                                    content_audio.setVisibility(View.GONE);
                                }
                                if (videoView != null) {
                                    videoView.setVisibility(View.GONE);
                                }
                                if (webview_video != null) {
                                    webview_video.setVisibility(View.GONE);
                                    webview_video.destroy();
                                }
                                if (webview_container != null) {
                                    webview_container.setVisibility(View.GONE);
                                }
                                if (videoLayout != null) {
                                    videoLayout.setVisibility(View.GONE);
                                }
                                ActivityCompat.finishAfterTransition((AppCompatActivity) context);
                            }

                        }

                        @Override
                        public void onSlideOpened() {

                        }

                        @Override
                        public boolean onSlideClosed() {
                            return false;
                        }
                    })
                    .build());
        }
    }

    private void scheduleStartPostponedTransition(final ImageView imageView) {
        imageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                imageView.getViewTreeObserver().removeOnPreDrawListener(this);
                ActivityCompat.startPostponedEnterTransition((Activity) context);
                return true;
            }
        });
    }

    private void enableSliding(boolean enable) {
        if (enable && !swipeEnabled) {
            slidrInterface.unlock();
            swipeEnabled = true;
        } else if (!enable && swipeEnabled) {
            slidrInterface.lock();
            swipeEnabled = false;
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        stopPlaying();
    }
}
