package model;

import util.Position;
import util.TargetStrategy;

import java.util.*;

public class BoardFireFighterBehavior implements BoardBehavior{
    private static TargetStrategy targetStrategy = new TargetStrategy();
    private static Map<Position, List<Position>> neighbors;

    private static List<Position> rocky;

    private ElementFactory<Rocky> rockyFactory;
    private static  Map<Position, Terrain> terrainMap = new HashMap<>();
    private static int step;
    static Movements fireMovements ;
    static Movements fireFighterMovements;
    static Movements cloudMovements;
    static Movements motorizedMovements;
    private ElementGenerator moutainGenerator;

    public BoardFireFighterBehavior(Map<Position, List<Position>> neighbors, ElementFactory<Fire> fireFactory ,ElementFactory<FireFighter> firefighterFactory,
                                    ElementFactory<Cloud> cloudFactory,ElementFactory<MotorizedFireFighter> motorizedFactory,ElementFactory<Rocky> rockyFactory) {
        this.step=0;
        this.neighbors = neighbors;
        this.rockyFactory=rockyFactory;
        fireMovements=new FireMovements(fireFactory);
        fireFighterMovements=new FireFighterMovements(firefighterFactory);
        cloudMovements=new CloudMovements(cloudFactory);
        motorizedMovements=new MotorizedMovements(motorizedFactory);
        moutainGenerator=new MountainGenerator();
    }

    public void initializeElements(int rowCount, int columnCount) {
         fireMovements.initializeElement(rowCount,columnCount);
         fireFighterMovements.initializeElement(rowCount,columnCount);
         cloudMovements.initializeElement(rowCount,columnCount);
        // Pompiers motorisés
        motorizedMovements.initializeElement(rowCount,columnCount);
        // Rocky
        rocky = new ArrayList<>();
        List<Rocky> rockies = rockyFactory.createElements(rowCount, columnCount);
        for (Rocky rockyElement : rockies) {
            rocky.add(rockyElement.getPosition());
        }

        moutainGenerator.generateElement(rowCount,columnCount);
        generateRoads(rowCount,columnCount);

    }





    public static void extinguish(Position position) {
        fireMovements.getPositions().remove(position);


    }



    public Set<Position> getFirePositions() {
        return (Set<Position>) fireMovements.getPositions();
    }



    public void incrementStep() {
        step++;
    }


    @Override
    public int stepNumber() {
        return step;
    }

    @Override
    public List<Position> updateToNextGeneration() {
        List<Position> modifiedPositions = fireFighterMovements.updateElements();
        modifiedPositions.addAll(fireMovements.updateElements());
        modifiedPositions.addAll(cloudMovements.updateElements());
        modifiedPositions.addAll(motorizedMovements.updateElements());
        incrementStep();
        return modifiedPositions;
    }

    @Override
    public void reset() {
        this.step=0;
        // Vider toutes les positions stockées
        fireMovements.getPositions().clear();
        fireFighterMovements.getPositions().clear();
        cloudMovements.getPositions().clear();
        motorizedMovements.getPositions().clear();
        rocky.clear();
        terrainMap.clear();

    }



    /**
     * Éteint les feux à proximité d'une position donnée.
     *
     * @param firefighterPosition La position actuelle du pompier.
     * @param modifiedPositions   Les positions modifiées pendant ce tour.
     */
    public static void extinguishNearbyFires(Position firefighterPosition, List<Position> modifiedPositions) {
        List<Position> nearbyFires = getNeighbors().getOrDefault(firefighterPosition, Collections.emptyList())
                .stream()
                .filter(fireMovements.getPositions()::contains)
                .toList();
        for (Position fire : nearbyFires) {
            fireMovements.getPositions().remove(fire);
            modifiedPositions.add(fire);
            System.out.println("Feu éteint à : " + fire);
        }
    }

    public static Map<Position, Terrain> getTerrainMap() {
        return terrainMap;
    }
    public static boolean canMoveTo(Position position, Set<Position> firePositions, List<Position> firefighterPositions) {
        // Vérifie si la position est hors des limites (par exemple, en dehors de la grille ou inaccessible)
        if (!neighbors.containsKey(position)) {
            return false;
        }

        // Si la position est occupée par un feu et que le terrain n'est pas traversable par le feu
        if(cloudMovements.getPositions().contains(position))
        {
            return false;
        }
        // Si la position est une montagne, aucun élément ne peut la franchir sauf les nuages
        if (terrainMap.get(position) != null && !cloudMovements.getPositions().contains(position)) {
            return false;  // Impossible de franchir une montagne, sauf pour un nuage
        }
        if(rocky.contains(position))
        {
            return Rocky.canFirePropagate();
        }

        return true;  // La position est traversable
    }
    private void generateRoads(int rowCount, int columnCount) {
        Random random = new Random();

        // Définir les bords de départ et d'arrivée
        int startRow = random.nextInt(rowCount); // Bord gauche
        int endRow = random.nextInt(rowCount);   // Bord droit
        int startCol = 0; // Bord gauche (colonne 0)
        int endCol = columnCount - 1; // Bord droit (dernière colonne)

        // Générer une route connectant ces deux points
        List<Position> path = createPath(new Position(startRow, startCol), new Position(endRow, endCol));

        // Placer la route dans la grille
        for (Position pos : path) {
            if (!terrainMap.containsKey(pos)) { // Éviter les obstacles
                terrainMap.put(pos, new Road(pos));
            }
        }
    }

    /**
     * Génère un chemin connectant deux positions.
     */
    private List<Position> createPath(Position start, Position end) {
        List<Position> path = new ArrayList<>();
        int currentRow = start.row();
        int currentCol = start.column();

        // Algorithme simple de connexion entre les points (chemin en "zigzag")
        while (currentRow != end.row() || currentCol != end.column()) {
            path.add(new Position(currentRow, currentCol));

            // Mouvement vertical
            if (currentRow < end.row()) {
                currentRow++;
            } else if (currentRow > end.row()) {
                currentRow--;
            }

            // Mouvement horizontal
            if (currentCol < end.column()) {
                currentCol++;
            } else if (currentCol > end.column()) {
                currentCol--;
            }
        }

        // Ajouter la position finale
        path.add(end);
        return path;
    }



    public static List<Position> getRocky() {
        return rocky;
    }

    public static int getStep() {
        return step;
    }

    public static Map<Position, List<Position>> getNeighbors() {
        return neighbors;
    }


    public static TargetStrategy getTargetStrategy() {
        return targetStrategy;
    }


    public static Collection<Position> getFirefighterPositions() {
        return fireFighterMovements.getPositions();
    }

    public Collection<Position> getCloudPositions() {
        return cloudMovements.getPositions();
    }

    public List<Position> getMotorizedFighters() {
        return (List<Position>) motorizedMovements.getPositions();
    }

}