package linea;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

public class BouleBonus extends ObjetGraphique {
    
    private double rayon = 15;
    private double vitesse = 5.0;
    private boolean estVerte; // true = bonus (niveau +1), false = malus (niveau -1)
    private int frameCounter = 0;
    private double vitesseVerticale = 0.0;
    private double amplitudeOndulation = 0.2;
    private double vitesseHorizontaleLisse = 0.0;
    private double phaseOndulation = Math.random() * Math.PI * 2; // phase unique par boule

    private static double clamp(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }
    
    public BouleBonus(double x, double y, boolean estVerte) {
        this.x = x;
        this.y = y;
        this.estVerte = estVerte;
        
        if (estVerte) {
            this.couleur = new Color(0.0f, 0.8f, 0.0f); // Vert
            this.rayon = 15;
            this.amplitudeOndulation = 0.45; // onde visible plus ample
            this.vitesseHorizontaleLisse = 4.8;
        } else {
            this.couleur = new Color(0.8f, 0.0f, 0.0f); // Rouge
            this.rayon = 14;
            this.amplitudeOndulation = 0.14;
            this.vitesseHorizontaleLisse = 4.3;
        }
    }
    
    public double getRayon() {
        return rayon;
    }
    
    public boolean isVerte() {
        return estVerte;
    }
    
    @Override
    void Afficher(Graphics g) {
        Graphics2D g2D = (Graphics2D) g;
        
        // Effet de pulsation (le rayon augmente/diminue)
        double rayonAffiche = rayon + Math.sin(frameCounter * 0.12) * 1.5;
        
        // Dessiner le cercle rempli (centré sur x,y)
        g2D.setColor(couleur);
        g2D.fillOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
                 (int)(2 * rayonAffiche), (int)(2 * rayonAffiche));
        
        // Contour
        g2D.setStroke(new BasicStroke(2.0f));
        g2D.setColor(estVerte ? new Color(0.0f, 1.0f, 0.0f) : new Color(1.0f, 0.0f, 0.0f));
        g2D.drawOval((int)(x - rayonAffiche), (int)(y - rayonAffiche),
                 (int)(2 * rayonAffiche), (int)(2 * rayonAffiche));
    }
    
    @Override
    void Animer() {
        // Déplacement vers la gauche (même vitesse que la ligne)
        x -= vitesse;
    }

    public void animerAvecCible(double vitesseLigne, double cibleY) {
        animerAvecCible(vitesseLigne, cibleY, 0.0);
    }

    public void animerAvecCible(double vitesseLigne, double cibleY, double cibleVitesseY) {
        // Vertes: trajectoire fluide à intercepter. Rouges: poursuite plus nette avec fenêtre d'esquive.
        double facteurHorizontal = estVerte ? 0.88 : 0.64;
        double vitesseMax = estVerte ? 9.2 : 5.8;
        double vitessePoursuite = estVerte ? 0.075 : 0.050; // meilleure réactivité
        double limiteVerticale = estVerte ? 1.85 : 1.05;    // accélération verticale
        double amortissement = estVerte ? 0.87 : 0.81;      // moins de friction
        double zoneMorte = estVerte ? 18.0 : 16.0;          // zone mort réduite
        double vitesseVerticaleMax = estVerte ? 4.2 : 2.6;  // vitesses verticales plus hautes

        double vitesseLigneSecurisee = Math.max(0.0, vitesseLigne);
        double vitesseCible = Math.min(vitesseMax, vitesseLigneSecurisee * facteurHorizontal);
        if (!estVerte) {
            // Les rouges gardent une vitesse plus stable d'une boule à l'autre.
            vitesseCible = vitesseCible * 0.68 + 4.5 * 0.32;
        }
        double deltaVitesse = clamp(vitesseCible - vitesseHorizontaleLisse, -0.25, 0.25);
        double vitesseMaxLocale = vitesseMax;
        if (!estVerte && x < 380) {
            // En fin d'écran, on plafonne un peu la vitesse pour laisser une fenêtre d'esquive stable.
            double facteurApproche = clamp((380.0 - x) / 180.0, 0.0, 1.0);
            vitesseMaxLocale = vitesseMax - (0.55 * facteurApproche);
        }
        vitesseHorizontaleLisse = clamp(vitesseHorizontaleLisse + deltaVitesse, 4.0, vitesseMaxLocale);
        vitesse = vitesseHorizontaleLisse;
        x -= vitesse;

        double vitesseJoueurLimitee = clamp(cibleVitesseY, -6.0, 6.0);
        // Verte: anticipation légère + oscillation. Rouge: AUCUNE anticipation → trajectoire lisible, esquivable.
        double anticipation = estVerte ? vitesseJoueurLimitee * 3.2 : 0.0;
        double cibleLisse = cibleY + anticipation + (estVerte ? Math.sin(frameCounter * 0.055 + phaseOndulation) * 45.0 : 0.0);

        double deltaY = cibleLisse - y;
        if (Math.abs(deltaY) < zoneMorte) {
            deltaY = 0;
        }

        vitesseVerticale += clamp(deltaY * vitessePoursuite, -limiteVerticale, limiteVerticale);
        vitesseVerticale *= amortissement;
        vitesseVerticale = clamp(vitesseVerticale, -vitesseVerticaleMax, vitesseVerticaleMax);

        double ondulation = Math.sin(frameCounter * 0.085 + (estVerte ? 0.0 : 1.1)) * amplitudeOndulation;
        y += vitesseVerticale + ondulation;
        frameCounter++;

        if (y < 20) {
            y = 20;
            vitesseVerticale = 0;
        } else if (y > 580) {
            y = 580;
            vitesseVerticale = 0;
        }
    }
    
    // Vérifier collision avec le cercle
    public boolean collisionAvec(Cercle c) {
        double cx = c.getX();
        double cy = c.getY();
        double cRayon = c.getRayon();
        
        double dist = Math.hypot(cx - x, cy - y);
        double seuil = estVerte ? (rayon + cRayon - 6.0) : (rayon + cRayon - 9.0);
        return dist <= seuil;
    }
    
    public void setVitesse(double vitesse) {
        this.vitesse = vitesse;
    }
}
