package com.example.fitbot.ui.activities;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.Dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.view.View;
import android.widget.Button;
import android.widget.VideoView;

import com.aldebaran.qi.sdk.QiContext;
import com.aldebaran.qi.sdk.QiSDK;
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
import com.aldebaran.qi.sdk.design.activity.conversationstatus.SpeechBarDisplayStrategy;
import com.example.fitbot.R;
import com.example.fitbot.exercise.Exercise;
import com.example.fitbot.exercise.ExerciseManager;
import com.example.fitbot.pepper.Pepper;
import com.example.fitbot.util.NavigationManager;
import com.example.fitbot.util.processing.InputProcessor;

public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {

    // Private fields for the FitnessActivity class.
    private InputProcessor motionProcessor;
    private Exercise currentExercise;

    // Progress circle for the exercises
    private ProgressBar progressCircle;
    private TextView progressText;
    private int progress = 0;
    private final int maxProgress = 10;

    // Exercise status element data
    private TextView exerciseMuscleGroupTextView;
    private TextView exerciseNameTextView;
    private TextView exerciseShortDescriptionTextView;
    //private TextView exerciseDescriptionTextView;
    private static String exerciseVideoUrl;

    private final Object lock = new Object();

    // Some nice little messages for the user
    private static final String[] EXERCISE_NOT_FOUND_MESSAGES = new String[]{
            "Ik heb momenteel helaas wat moeite met het ophalen van oefeningen, sorry.",
            "Het lijkt erop dat de oefeningen op een misterieus avontuur zijn. Even wachten tot ze terug zijn.",
            ", de oefeningen slapen nog, probeer het later nog eens."
    };

    private static final String EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE =
            "Indien dit probleem zich voortzet, neem contact op met de ontwikkelaar.";

    private static final float SENSOR_SAMPLE_RATE = 10.0f;
    private static final int EXERCISE_COUNT = 5;
    private static int EXERCISE_REP = 1;
    private static final float EXERCISE_SPEED_MULTIPLIER = 1.0f;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        QiSDK.register(this, this);
        setContentView(R.layout.activity_fitness);

        // Fill empty objects with exercise data
        this.exerciseNameTextView = findViewById(R.id.textViewFitnessTitle);
        this.exerciseShortDescriptionTextView = findViewById(R.id.textViewFitnessShortDescription);
        //this.exerciseDescriptionTextView = findViewById(R.id.textViewDialogDescription);

        // Set the repetition count for the exercise
        EXERCISE_REP = 1;

        progressCircle = findViewById(R.id.progressCircle);
        progressText = findViewById(R.id.progressText);

        progressCircle.setMax(maxProgress);
        updateProgress();

        // Set color of loading circle
        ProgressBar loadingCircle = findViewById(R.id.loadingCircle);
        loadingCircle.setIndeterminateTintList(ColorStateList.valueOf(Color.RED));

        // Navigation Buttons
        NavigationManager.setupButtonNavigation(this, R.id.homeButtonFitness, MainActivity.class);
        NavigationManager.setupButtonNavigation(this, R.id.skipButtonFitness, MainActivity.class); //Needs to skip exercises once those are implemented

        // Hide system UI
        NavigationManager.hideSystemUI(this);
        setSpeechBarDisplayStrategy(SpeechBarDisplayStrategy.IMMERSIVE);

        // Initiate info button
        Button infoButtonFitness = findViewById(R.id.infoButtonFitness);
        infoButtonFitness.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showInfoDialog();
            }
        });
    }

    @Override
    public void onRobotFocusGained(QiContext qiContext) {

        // Provide the context so that all queued actions can be performed.
        Pepper.provideContext(qiContext, this.getClass());

        // Initialize the element whenever it has been added to the screen.
        // This will provide the element with the appropriate dimensions for drawing
        // the canvas properly.
        this.fetchExerciseAsync((exercise) -> {
            // Acquire paths from the exercise and provide them to the motion processor
            motionProcessor = new InputProcessor(SENSOR_SAMPLE_RATE, this);
            motionProcessor.useExercise(exercise);
            /* TODO: Remove if not needed */
            motionProcessor.setRecording(true, 10);
            motionProcessor.startListening();

        }, (n) -> {
            int randomMessageIndex = (int) Math.floor(Math.random() * EXERCISE_NOT_FOUND_MESSAGES.length);
            Pepper.say(EXERCISE_NOT_FOUND_MESSAGES[randomMessageIndex]);
            Pepper.say(EXERCISE_NOT_FOUND_SEEK_HELP_MESSAGE);
            NavigationManager.navigateToActivity(this, EndScreenActivity.class);
        });
    }

    /**
     * Acquire an exercise from the ExerciseManager.
     * Whenever the retrieval failed, it will have the robot say something to the user
     * to inform them about the issue.
     */
    public void fetchExerciseAsync(Exercise.ExerciseFetchHandler onSuccessfulFetch, Exercise.ExerciseFetchHandler onFailedFetch) {
        // For some stupid reason we cannot perform network operations on the main thread.
        // therefore we'll have to do it like this...
        new Thread(() -> {
            Exercise exercise = ExerciseManager.fetchExerciseFromDatabase();
            if (exercise == null) {
                onFailedFetch.handle(null);
            } else {
                onSuccessfulFetch.handle(exercise);
                this.runOnUiThread(() -> {
                    exerciseNameTextView.setText(exercise.name);
                    exerciseShortDescriptionTextView.setText(exercise.shortDescription);
                    // exerciseDescriptionTextView.setText(exercise.description);
                    exerciseVideoUrl = exercise.videoUrl;

                    // Play the video
                    VideoView videoView = findViewById(R.id.videoView);
                    playVideo(videoView, this);

                    // When the video has started playing remove the loading circle
                    videoView.setOnInfoListener((mp, what, extra) -> {
                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                            ProgressBar loadingCircle = findViewById(R.id.loadingCircle);
                            loadingCircle.setVisibility(View.GONE);
                            return true;
                        }
                        return false;
                    });

                    videoView.setOnCompletionListener(mp -> {
                        if (EXERCISE_REP < EXERCISE_COUNT) {
                            videoView.start(); // start the video again
                            EXERCISE_REP++;
                        }
                    });
                });
            }
        }).start();
    }

    /**
     * Function for playing a video in a VideoView
     *
     * @param videoView The VideoView to play the video in
     * @param context   The context to use
     */
    public void playVideo(VideoView videoView, Context context) {
        // Set up the video player
        if (videoView != null) {
            videoView.setVideoPath(exerciseVideoUrl);
            videoView.start();
        } else {
            Log.e("FitnessActivity", "VideoView is null. Check your layout XML.");
        }
    }

    @Override
    public void onRobotFocusLost() {
        QiSDK.unregister(this, this);
        Pepper.provideContext(null, this.getClass()); // Remove the context (unavailable)

        // Go to the main screen
//        NavigationManager.navigateToActivity(this, MainActivity.class);
    }

    @Override
    public void onRobotFocusRefused(String reason) {
    }

    @Override
    protected void onDestroy() {
        if (this.motionProcessor != null) {
            this.motionProcessor.stopListening();
            this.motionProcessor = null;
        }
        QiSDK.unregister(this, this);
        Pepper.provideContext(null, this.getClass());

        super.onDestroy();
    }

    private void showInfoDialog() {
        final Dialog dialog = new Dialog(this);
        dialog.setContentView(R.layout.dialog_info);

        // Hide the system UI
        NavigationManager.hideSystemUI(this);

        // Set the dialog options
        dialog.getWindow().setDimAmount(0.5f);
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
        dialog.setCancelable(true);

        // Close button for dialog
        Button closeButton = dialog.findViewById(R.id.closeButtonDialog);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        dialog.show();
    }

    public void incrementProgress(View view) {
        if (progress < maxProgress) {
            progress++;
            triggerColorBurst(false);
            updateProgress();
        }
    }

    private void updateProgress() {
        progressCircle.setProgress(progress);
        progressText.setText(progress + "/" + maxProgress);
    }

    private void triggerColorBurst(boolean isGoodRep) {

        if (isGoodRep) {
            progressCircle.setProgressDrawable(ContextCompat.getDrawable(this, R.drawable.progress_circle_good));
        } else {
            progressCircle.setProgressDrawable(ContextCompat.getDrawable(this, R.drawable.progress_circle_bad));
        }

        ObjectAnimator animator = ObjectAnimator.ofFloat(progressCircle, "alpha", 1f, 0f, 1f);
        animator.setDuration(500); // Burst duration
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                progressCircle.setProgressDrawable(ContextCompat.getDrawable(FitnessActivity.this, R.drawable.progress_circle));
            }
        });
        animator.start();
    }

}