package linea;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Jeu implements KeyListener, ActionListener {

    //-------------------------------------------------------------------------
    // PROPRIETES
    //-------------------------------------------------------------------------
    protected ZoneDessin ecran = new ZoneDessin();
    protected Cercle demiCercleAvant;
    protected Cercle demiCercleArriere;
    protected Ligne ligne;
    
    private int _niv = 1;
    protected Timer horloge;
    protected double score = 0;
    protected JLabel labScore;
    protected JLabel labMeilleurScore;
    private DatabaseConnection db;
    private int idCompte;
    private int meilleurSansCompte = 0;
    private int mortsSansCompte = 0;
    private int tempsSansCompteSec = 0;
    private long debutPartieMs = 0;

    private int meilleurActuel() {
        return idCompte > 0 ? db.getMeilleurScoreParCompte(idCompte) : meilleurSansCompte;
    }

    private String statsActuelles() {
        if (idCompte > 0) {
            return db.getStatsParCompte(idCompte);
        }
        return "Nombre de morts : " + mortsSansCompte
                + "\nTemps de jeu total : " + tempsSansCompteSec + " s"
                + "\nMeilleur score : " + meilleurSansCompte;
    }

    private void enregistrerPartie(int scoreActuel, int tempsPartieSec) {
        if (idCompte > 0) {
            db.sauvegarderScore(scoreActuel, idCompte, 1, tempsPartieSec);
            return;
        }
        meilleurSansCompte = Math.max(meilleurSansCompte, scoreActuel);
        mortsSansCompte += 1;
        tempsSansCompteSec += tempsPartieSec;
    }

    //-------------------------------------------------------------------------
    // CONSTRUCTEUR
    //-------------------------------------------------------------------------
    public Jeu(DatabaseConnection db, int idCompte) {
        this.db = db;
        this.idCompte = idCompte;
        labScore = new JLabel();
        labScore.setText("<html><h3>score : 0</h3></html>");

        labMeilleurScore = new JLabel();

        JPanel panneauScores = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
        panneauScores.setOpaque(false);
        panneauScores.add(labScore);
        panneauScores.add(labMeilleurScore);
        ecran.add(panneauScores, BorderLayout.NORTH);
        rafraichirMeilleurScore();
    }

    private void rafraichirMeilleurScore() {
        labMeilleurScore.setText("<html><h3>meilleur : " + meilleurActuel() + "</h3></html>");
    }

    private boolean choisirNouveauCompte() {
        List<String> pseudos = new ArrayList<>(db.getPseudos());
        pseudos.add(0, "Sans compte");

        String choix = (String) JOptionPane.showInputDialog(
                null,
                "Choisissez le compte pour la prochaine partie :",
                "Changer de compte",
                JOptionPane.QUESTION_MESSAGE,
                null,
                pseudos.toArray(String[]::new),
                pseudos.get(0)
        );

        if (choix == null) {
            return false;
        }

        if ("Sans compte".equals(choix)) {
            idCompte = -1;
            meilleurSansCompte = 0;
            mortsSansCompte = 0;
            tempsSansCompteSec = 0;
        } else {
            idCompte = db.getIdParPseudo(choix);
        }
        rafraichirMeilleurScore();
        return true;
    }

    //-------------------------------------------------------------------------
    // METHODES DE GESTION DU JEU
    //-------------------------------------------------------------------------

    /**
     * Centralise la création et la configuration des objets du jeu.
     * Évite de répéter ce code dans demarrer() et resetLevel().
     */
    private void initialiserPartie() {
        // 1. Nettoyage de l'écran
        ecran.reinitialiser();
        
        // 2. Création des instances
        demiCercleAvant = new Cercle(90, -180);
        demiCercleArriere = new Cercle(90, 180);
        ligne = new Ligne(_niv);

        // 3. Configuration visuelle
        demiCercleArriere.setCouleur(new Color(0.8f, 0.0f, 0.0f));
        demiCercleAvant.setCouleur(new Color(0.0f, 0.8f, 0.0f));

        // 4. Ajout à l'écran (l'ordre définit la superposition)
        ecran.ajouterObjet(demiCercleArriere);
        ecran.ajouterObjet(ligne);
        ecran.ajouterObjet(demiCercleAvant);
    }

    public void demarrer() {
        JFrame fenetre = new JFrame("Linea Game");
        
        // Initialise les objets une première fois
        initialiserPartie();

        ecran.addKeyListener(this);
        ecran.setFocusable(true);
        fenetre.setContentPane(ecran);
        fenetre.pack();
        fenetre.setLocation(100, 100);
        fenetre.setVisible(true);
        fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Création et lancement du timer
        horloge = new Timer(40, this);
        horloge.start();
        debutPartieMs = System.currentTimeMillis();
    }

    private void resetLevel() {
        // Réinitialisation des variables de jeu
        score = 0;
        labScore.setText("<html><h3>score : 0</h3></html>");

        // Ré-initialisation des objets graphiques
        initialiserPartie();
        debutPartieMs = System.currentTimeMillis();

        // Relance le timer existant et redonne le focus
        if (horloge != null) horloge.restart();
        ecran.requestFocusInWindow();
    }

    //-------------------------------------------------------------------------
    // EVENEMENTS (Timer & Clavier)
    //-------------------------------------------------------------------------

    @Override
    public void actionPerformed(ActionEvent e) {
        ecran.traiterBoucleAnimation();

        if (ecran.aCollision()) {
            horloge.stop();

            int scoreActuel = (int) score;
            int tempsPartieSec = (int) ((System.currentTimeMillis() - debutPartieMs) / 1000L);
            enregistrerPartie(scoreActuel, tempsPartieSec);
            
            rafraichirMeilleurScore();

            while (true) {
                Object[] options = {"Relancer", "Changer de compte", "Voir stats", "Quitter"};
                int choix = JOptionPane.showOptionDialog(null,
                    "Perdu\nScore : " + scoreActuel + "\nMeilleur : " + meilleurActuel(),
                        "Game Over",
                        JOptionPane.DEFAULT_OPTION,
                        JOptionPane.INFORMATION_MESSAGE,
                        null, options, options[0]);

                if (choix == 0) {
                    resetLevel();
                    break;
                }
                if (choix == 1) {
                    if (choisirNouveauCompte()) {
                        resetLevel();
                        break;
                    }
                    continue;
                }
                if (choix == 2) {
                    JOptionPane.showMessageDialog(null, statsActuelles(), "Statistiques", JOptionPane.INFORMATION_MESSAGE);
                    continue;
                }
                System.exit(0);
            }
            
            return;
        }

        // Calcul du score basé sur le temps écoulé
        score += (0.05 + (0.05 * horloge.getDelay() / 100.0));
        labScore.setText("<html><h3>score : " + (int)score + "</h3></html>");
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            demiCercleAvant.Monter();
            demiCercleArriere.Monter();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            demiCercleAvant.ArreterMonter();
            demiCercleArriere.ArreterMonter();
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {}
}