package org.Models;

/**
 * Uniquement afin de se servir d'une paire de coordonées.
 */
import java.awt.Point;

import java.util.Observable;
import java.util.Random;

import org.Models.Pieces.PieceI;
import org.Models.Pieces.PieceJ;
import org.Models.Pieces.PieceL;
import org.Models.Pieces.PieceO;
import org.Models.Pieces.PieceS;
import org.Models.Pieces.PieceT;
import org.Models.Pieces.PieceZ;

/**
 * Gère la logique principale du jeu Tetris, y compris la gestion de la grille,
 * des pièces, de la musique, de l'ordonnancement et de l'état de la partie.
 */
@SuppressWarnings("deprecation")
public class Jeu extends Observable implements Runnable {
    private Grille grille;
    private Ordonnanceur ordonnanceur;
    private Musique musique;

    private PieceCourante pieceSuivante;
    private int pieceSuivanteX;
    private int pieceSuivanteY;
    public boolean jeuEnCours = true;

    /**
     * Crée une nouvelle instance du jeu avec la grille et la musique spécifiées.
     *
     * @param grille la grille de jeu
     * @param musique le gestionnaire de musique
     */
    public Jeu(Grille grille, Musique musique) {

        this.grille = grille;
        this.musique = musique;
        this.musique = musique;

        this.grille.setPieceCourante(getNouvellePiece());

        this.pieceSuivante = getNouvellePiece();

        this.ordonnanceur = new Ordonnanceur(this, 1000);
        this.ordonnanceur.start();
    }

    /**
     * Génère et retourne une nouvelle pièce aléatoire.
     *
     * @return une nouvelle pièce courante
     */
    private PieceCourante getNouvellePiece() {
        Random random = new Random();
        int randomiiii = random.nextInt(7);

        PieceCourante nouvellePiece;
        switch (randomiiii) {
            case 0:
                nouvellePiece = new PieceI();

                break;
            case 1:
                nouvellePiece = new PieceL();

                break;
            case 2:
                nouvellePiece = new PieceJ();

                break;
            case 3:
                nouvellePiece = new PieceO();

                break;
            case 4:
                nouvellePiece = new PieceS();

                break;
            case 5:
                nouvellePiece = new PieceT();

                break;
            case 6:
                nouvellePiece = new PieceZ();

                break;
            default:
                nouvellePiece = new PieceL();
                break;
        }
        return nouvellePiece;
    }

    /**
     * Retourne la pièce suivante.
     *
     * @return la pièce suivante
     */
    public PieceCourante getPieceSuivante() {
        return pieceSuivante;
    }

    public int getPieceSuivanteX() {
        return pieceSuivanteX;
    }

    public int getPieceSuivanteY() {
        return pieceSuivanteY;
    }

    /**
     * Retourne la grille de jeu.
     *
     * @return la grille
     */
    public Grille getGrille() {
        return grille;
    }

    /**
     * Vérifie si la partie est terminée (collision en haut de la grille).
     *
     * @return true si la partie est terminée, false sinon
     */
    public boolean estFinPartie() {
        for (Point caseColoree : this.grille.motifPieceCouranteColoriee()) {
            if (this.grille.getCase(caseColoree.y, caseColoree.x)) {
                finPartie();
                return true;
            }
        }

        return false;
    }

    /**
     * Termine la partie, arrête l'ordonnanceur et la musique.
     */
    public void finPartie() {
        this.jeuEnCours = false;
        ordonnanceur.interrupt();
        if (musique != null) {
            System.out.println("Arret musique");
            musique.arreterMusique();
        }
        setChanged();
        notifyObservers();
    }

    /**
     * Réinitialise tous les paramètres de la partie pour relancer le jeu.
     */
    public void reinitialiserPartie() {
        if (ordonnanceur != null) {
            ordonnanceur.stopOrdonnanceur();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }

        this.grille.initGrille();
        this.grille.setPieceCourante(getNouvellePiece());
        this.grille.setScore(0);
        this.grille.setNbLignesSupprimees(0);
        this.pieceSuivante = getNouvellePiece();
        this.jeuEnCours = true;

        this.ordonnanceur = new Ordonnanceur(this, 1000);
        this.ordonnanceur.start();
        setChanged();
        notifyObservers();
    }

    public void pauseJeu() {
        grille.setEnPause(true);
        if (musique != null) {
            musique.basculePlayPause();
        }
    }

    public void reprendreJeu() {
        grille.setEnPause(false);
        if (musique != null) {
            musique.basculePlayPause();
        }
    }

    /**
     * Méthode exécutée périodiquement par l'ordonnanceur pour faire avancer le jeu.
     */
    @Override
    public void run() {
        if (!jeuEnCours || grille.estEnPause()) {
            return;
        }

        if (estFinPartie()) {
            finPartie();
            return;
        }

        if (!this.grille.doitFixerPiece()) {
            this.grille.deplacerPiece(Direction.BAS);
        } else {
            this.grille.fixerPiece();
            this.grille.setPieceCourante(pieceSuivante);
            this.pieceSuivante = getNouvellePiece();
        }

        setChanged();
        notifyObservers();
    }
}
