package com.example.boidelov3;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;

import androidx.core.content.ContextCompat;

/**
 * Classe utilitaire pour les animations et effets visuels
 */
public class BoideloAnimationUtils {

    private static final Interpolator OVERSHOOT = new OvershootInterpolator();

    /**
     * Anime le changement de couleur de fond d'une vue
     *
     * @param view        La vue à animer
     * @param targetColor La couleur cible
     * @param duration    La durée de l'animation en ms
     */
    public static void animateBackgroundColor(View view, int targetColor, int duration) {
        if (view == null) return;

        int currentColor = getBackgroundColor(view);
        if (currentColor == targetColor) return;

        ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), currentColor, targetColor);
        anim.setDuration(duration);
        anim.addUpdateListener(animation -> {
            int color = (int) animation.getAnimatedValue();
            view.setBackgroundColor(color);
        });
        anim.start();
    }

    /**
     * Anime le changement de couleur de fond avec la durée par défaut (500ms)
     */
    public static void animateBackgroundColor(View view, int targetColor) {
        animateBackgroundColor(view, targetColor, 500);
    }

    /**
     * Obtient la couleur de fond actuelle d'une vue
     */
    private static int getBackgroundColor(View view) {
        if (view.getBackground() instanceof ColorDrawable) {
            return ((ColorDrawable) view.getBackground()).getColor();
        }
        return 0xFFFFFFFF; // Blanc par défaut
    }

    /**
     * Déclenche une vibration haptique
     *
     * @param context Le contexte
     * @param duration Durée de la vibration en ms
     */
    public static void triggerHapticFeedback(Context context, int duration) {
        if (context == null) return;

        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        if (vibrator != null && vibrator.hasVibrator()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                VibrationEffect effect = VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
                vibrator.vibrate(effect);
            } else {
                vibrator.vibrate(duration);
            }
        }
    }

    /**
     * Déclenche une vibration haptique courte (100ms)
     */
    public static void triggerHapticFeedback(Context context) {
        triggerHapticFeedback(context, 100);
    }

    /**
     * Déclenche une vibration haptique de succès
     */
    public static void triggerSuccessHaptic(Context context) {
        if (context == null) return;

        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        if (vibrator != null && vibrator.hasVibrator() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            long[] pattern = {0, 50, 50, 50};
            VibrationEffect effect = VibrationEffect.createWaveform(pattern, -1);
            vibrator.vibrate(effect);
        }
    }

    /**
     * Déclenche une vibration haptique d'erreur
     */
    public static void triggerErrorHaptic(Context context) {
        if (context == null) return;

        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        if (vibrator != null && vibrator.hasVibrator() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            long[] pattern = {0, 100, 50, 100};
            VibrationEffect effect = VibrationEffect.createWaveform(pattern, -1);
            vibrator.vibrate(effect);
        }
    }

    /**
     * Anime l'apparition d'une vue avec un effet de fade-in
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void fadeIn(View view, int duration) {
        if (view == null) return;

        view.setAlpha(0f);
        view.setVisibility(View.VISIBLE);
        view.animate()
                .alpha(1f)
                .setDuration(duration)
                .start();
    }

    /**
     * Anime la disparition d'une vue avec un effet de fade-out
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void fadeOut(View view, int duration) {
        if (view == null) return;

        view.animate()
                .alpha(0f)
                .setDuration(duration)
                .withEndAction(() -> view.setVisibility(View.GONE))
                .start();
    }

    /**
     * Anime une vue avec un effet de scale
     *
     * @param view     La vue à animer
     * @param scale    Échelle cible (1.0 = normal, 0.5 = moitié)
     * @param duration Durée de l'animation
     */
    public static void scale(View view, float scale, int duration) {
        if (view == null) return;

        view.animate()
                .scaleX(scale)
                .scaleY(scale)
                .setDuration(duration)
                .setInterpolator(OVERSHOOT)
                .start();
    }

    /**
     * Anime une vue avec un effet de slide depuis le bas
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void slideUp(View view, int duration) {
        if (view == null) return;

        view.setTranslationY(view.getHeight());
        view.setVisibility(View.VISIBLE);
        view.animate()
                .translationY(0f)
                .setDuration(duration)
                .setInterpolator(new android.view.animation.DecelerateInterpolator())
                .start();
    }

    /**
     * Applique une animation de pression à un bouton
     *
     * @param view La vue (bouton) à animer
     */
    public static void applyButtonPressAnimation(View view) {
        if (view == null) return;

        view.setOnTouchListener((v, event) -> {
            switch (event.getAction()) {
                case android.view.MotionEvent.ACTION_DOWN:
                    v.animate()
                            .scaleX(0.95f)
                            .scaleY(0.95f)
                            .setDuration(100)
                            .start();
                    return true;
                case android.view.MotionEvent.ACTION_UP:
                case android.view.MotionEvent.ACTION_CANCEL:
                    v.animate()
                            .scaleX(1f)
                            .scaleY(1f)
                            .setDuration(100)
                            .start();
                    v.performClick();
                    return true;
            }
            return false;
        });
    }

    /**
     * Anime une vue avec un effet de pulsation
     *
     * @param view     La vue à animer
     * @param duration Durée d'un cycle de pulsation
     */
    public static void pulse(View view, int duration) {
        if (view == null) return;

        view.animate()
                .scaleX(1.05f)
                .scaleY(1.05f)
                .setDuration(duration / 2)
                .withEndAction(() -> {
                    view.animate()
                            .scaleX(1f)
                            .scaleY(1f)
                            .setDuration(duration / 2)
                            .start();
                })
                .start();
    }

    /**
     * Anime une vue avec un effet de shake (tremblement)
     *
     * @param view La vue à animer
     */
    public static void shake(View view) {
        if (view == null) return;

        Animation shake = AnimationUtils.loadAnimation(view.getContext(), R.anim.button_press);
        view.startAnimation(shake);
    }

    /**
     * Obtient la couleur depuis une ressource de couleur
     */
    public static int getColorFromResource(Context context, int colorResId) {
        return ContextCompat.getColor(context, colorResId);
    }

    /**
     * Anime une vue avec un effet de bounce (rebond)
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void bounce(View view, int duration) {
        if (view == null) return;

        view.animate()
                .scaleY(0.8f)
                .scaleX(0.8f)
                .setDuration(duration / 2)
                .setInterpolator(new android.view.animation.DecelerateInterpolator())
                .withEndAction(() -> {
                    view.animate()
                            .scaleY(1f)
                            .scaleX(1f)
                            .setDuration(duration / 2)
                            .setInterpolator(OVERSHOOT)
                            .start();
                })
                .start();
    }

    /**
     * Anime une vue pour la supprimer (slide out + fade out)
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     * @param endAction Action à exécuter après l'animation
     */
    public static void slideOutToRemove(View view, int duration, Runnable endAction) {
        if (view == null) return;

        view.animate()
                .translationX(-view.getWidth())
                .alpha(0f)
                .setDuration(duration)
                .setInterpolator(new android.view.animation.AccelerateInterpolator())
                .withEndAction(endAction)
                .start();
    }

    /**
     * Anime l'apparition d'une vue (slide in + fade in)
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void slideIn(View view, int duration) {
        if (view == null) return;

        view.setTranslationX(view.getWidth());
        view.setAlpha(0f);
        view.setVisibility(View.VISIBLE);
        view.animate()
                .translationX(0f)
                .alpha(1f)
                .setDuration(duration)
                .setInterpolator(new android.view.animation.DecelerateInterpolator())
                .start();
    }

    /**
     * Anime une vue avec un effet de rotation
     *
     * @param view     La vue à animer
     * @param degrees  Angle de rotation en degrés
     * @param duration Durée de l'animation
     */
    public static void rotate(View view, float degrees, int duration) {
        if (view == null) return;

        view.animate()
                .rotation(degrees)
                .setDuration(duration)
                .setInterpolator(new android.view.animation.DecelerateInterpolator())
                .start();
    }

    /**
     * Anime une vue avec un effet de wiggle (gauche-droite)
     *
     * @param view La vue à animer
     */
    public static void wiggle(View view) {
        if (view == null) return;

        view.animate()
                .rotation(5f)
                .setDuration(50)
                .withEndAction(() -> {
                    view.animate()
                            .rotation(-5f)
                            .setDuration(50)
                            .withEndAction(() -> {
                                view.animate()
                                        .rotation(3f)
                                        .setDuration(50)
                                        .withEndAction(() -> {
                                            view.animate()
                                                    .rotation(0f)
                                                    .setDuration(50)
                                                    .start();
                                        })
                                        .start();
                            })
                            .start();
                })
                .start();
    }

    /**
     * Anime une vue avec un effet de pop-in (apparition avec scale)
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     */
    public static void popIn(View view, int duration) {
        if (view == null) return;

        view.setScaleX(0f);
        view.setScaleY(0f);
        view.setAlpha(0f);
        view.setVisibility(View.VISIBLE);
        view.animate()
                .scaleX(1f)
                .scaleY(1f)
                .alpha(1f)
                .setDuration(duration)
                .setInterpolator(OVERSHOOT)
                .start();
    }

    /**
     * Anime une vue avec un effet de pop-out (disparition avec scale)
     *
     * @param view     La vue à animer
     * @param duration Durée de l'animation
     * @param endAction Action à exécuter après l'animation
     */
    public static void popOut(View view, int duration, Runnable endAction) {
        if (view == null) return;

        view.animate()
                .scaleX(0f)
                .scaleY(0f)
                .alpha(0f)
                .setDuration(duration)
                .setInterpolator(new android.view.animation.AccelerateInterpolator())
                .withEndAction(endAction)
                .start();
    }
}
