package fr.monkhanny.dorfromantik.gui;

import java.awt.*;
import java.util.List;
import java.util.Objects;
import javax.swing.*;

/**
 * Un composant graphique Swing pour afficher un histogramme représentant les scores moyens des groupes.
 * Chaque barre représente un groupe et est colorée différemment en fonction de s'il est mis en surbrillance.
 * 
 * Les barres sont ombrées et incluent des labels pour indiquer les scores moyens, ainsi que les noms des groupes.
 * 
 * @version 1.0
 * @author Moncef STITI
 */
public class BarChartPanel extends JPanel {

    /** Liste des scores moyens des groupes. */
    private final List<Integer> groupAverages;
    
    /** Indice du groupe mis en surbrillance. */
    private final int highlightedGroup;

    /** Couleur de la barre pour le groupe du joueur. */
    private static final Color PLAYER_GROUP_COLOR = new Color(204, 0, 0);

    /** Couleur des barres pour les autres groupes. */
    private static final Color OTHER_GROUP_COLOR = new Color(0, 0, 204);

    /** Couleur de l'ombre projetée par les barres. */
    private static final Color SHADOW_COLOR = new Color(0, 0, 0, 60);

    /** Couleur du texte affiché sur les barres. */
    private static final Color TEXT_COLOR = Color.BLACK;

    /** Police pour le label "Score moyen". */
    private static final Font AVERAGE_FONT = new Font("Arial", Font.ITALIC, 12);

    /** Police pour les labels des groupes. */
    private static final Font GROUP_LABEL_FONT = new Font("Arial", Font.BOLD, 16);

    /** Police pour afficher les scores des groupes. */
    private static final Font SCORE_FONT = new Font("Arial", Font.BOLD, 14);

    /** Marge autour de l'histogramme. */
    private static final int PADDING = 30;

    /** Décalage de l'ombre en pixels. */
    private static final int SHADOW_OFFSET = 2;

    /**
     * Construit un nouveau panneau d'histogramme.
     * 
     * @param groupAverages Liste des scores moyens des groupes.
     *                      La taille de cette liste détermine le nombre de barres dans l'histogramme.
     * @param highlightedGroup Indice du groupe à mettre en surbrillance.
     *                         Si cet indice ne correspond à aucun groupe, aucune barre ne sera mise en surbrillance.
     * @throws NullPointerException si {@code groupAverages} est {@code null}.
     */
    public BarChartPanel(List<Integer> groupAverages, int highlightedGroup) {
        this.groupAverages = Objects.requireNonNull(groupAverages, "Group averages cannot be null");
        this.highlightedGroup = highlightedGroup;

        // Configuration du panneau
        setOpaque(false);
        setBackground(new Color(0, 0, 0, 0));
        setAlignmentX(Component.CENTER_ALIGNMENT);
    }

    /**
     * Dessine le composant graphique, incluant les barres, les labels et les scores.
     * 
     * @param g Le contexte graphique.
     */
    @Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    
    if (groupAverages.isEmpty()) {
        return;
    }

    Graphics2D g2d = (Graphics2D) g.create();
        try {
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int width = getWidth();
            int height = getHeight();
            int barWidth = width / (groupAverages.size() + 1);
            int maxScore = groupAverages.stream()
                .mapToInt(Integer::intValue)
                .max()
                .orElse(0);

            for (int i = 0; i < groupAverages.size(); i++) {
                int barHeight = calculateBarHeight(maxScore, height, groupAverages.get(i));
                int xPosition = (i + 1) * barWidth;

                Color barColor = (i == highlightedGroup) ? PLAYER_GROUP_COLOR : OTHER_GROUP_COLOR;

                g2d.setColor(SHADOW_COLOR);
                g2d.fillRect(xPosition + SHADOW_OFFSET, height - barHeight - PADDING + SHADOW_OFFSET, barWidth - 5, barHeight);

                g2d.setColor(barColor);
                g2d.fillRect(xPosition, height - barHeight - PADDING, barWidth - 5, barHeight);

                // Ajustez dynamiquement la position des textes
                int textY = height - barHeight - PADDING - 20; // Score position
                if (textY < PADDING) {
                    textY = PADDING - 2; // Éviter le chevauchement au sommet
                }

                String avgScoreText = String.valueOf(groupAverages.get(i));
                g2d.setFont(SCORE_FONT);
                g2d.setColor(TEXT_COLOR);
                drawCenteredString(g2d, avgScoreText, xPosition, barWidth, textY);

                // Position de "Score moyen"
                int labelY = textY - 15; // Placer légèrement au-dessus du score
                if (labelY < PADDING) {
                    labelY = PADDING - 17; // Éviter les débordements
                }

                g2d.setFont(AVERAGE_FONT);
                drawCenteredString(g2d, "Score moyen : ", xPosition, barWidth, labelY);

                g2d.setFont(GROUP_LABEL_FONT);
                String groupLabel = "Groupe " + (i + 1);
                drawCenteredString(g2d, groupLabel, xPosition, barWidth, height - 10);
            }
        } finally {
            g2d.dispose();
        }
    }


    /**
     * Calcule la hauteur d'une barre proportionnellement au score maximum.
     * 
     * @param maxScore Le score maximum parmi tous les groupes
     * @param height La hauteur totale du composant
     * @param score Le score du groupe courant
     * @return La hauteur de la barre
     */
    private int calculateBarHeight(int maxScore, int height, int score) {
        return (int) ((double) score / maxScore * (height - 2 * PADDING));
    }

    /**
     * Dessine une chaîne centrée horizontalement dans une section de la largeur du composant.
     * 
     * @param g2d Le contexte graphique
     * @param text Le texte à dessiner
     * @param xOffset La position x de départ de la section
     * @param sectionWidth La largeur de la section
     * @param y La position y où dessiner le texte
     */
    private void drawCenteredString(Graphics2D g2d, String text, int xOffset, int sectionWidth, int y) {
        FontMetrics metrics = g2d.getFontMetrics();
        int textWidth = metrics.stringWidth(text);
        int textX = xOffset + (sectionWidth - textWidth) / 2;
        g2d.drawString(text, textX, y);
    }

    /**
     * Retourne la taille préférée du panneau.
     * 
     * @return La taille préférée
     * @see Dimension
     */
    @Override
    public Dimension getPreferredSize() {
        // Définir une taille préférée par défaut si non spécifiée
        return new Dimension(400, 200);
    }
}