package model;

import util.Position;

import java.util.*;


public class FirefighterBoard implements Board<List<ModelElement>> {
  private final int columnCount;
  private final int rowCount;
  private Map<Position, Fire> fires = new HashMap<>();
  private Map<Position, Extinguisher> extinguishers = new HashMap<>();
  private Map<Position, Obstacle> obstacles = new HashMap<>();

  private final Position[][] positions;
  private int step = 0;
  private final Random randomGenerator = new Random();


  public FirefighterBoard(int columnCount, int rowCount) {
    this.columnCount = columnCount;
    this.rowCount = rowCount;
    this.positions = new Position[rowCount][columnCount];

    initializePositions();
    initializeElements();
  }

  private void initializePositions() {
    for (int column = 0; column < columnCount; column++) {
      for (int row = 0; row < rowCount; row++) {
        positions[row][column] = new Position(row, column);
      }
    }
  }


  public void initializeElements() {
    obstacles.clear();
    extinguishers.clear();
    fires.clear();
    for(ModelElement modelElement : ModelElement.values()){
      for(int elementCount = 0; elementCount< modelElement.getInitialNumber();elementCount++){
        Position position = randomPosition();
        if(modelElement.isObstacle()){
          obstacles.put(position, (Obstacle) modelElement.getModelElementClass(position));
        } else if (modelElement.isExtinguisher()) {
          extinguishers.put(position, (Extinguisher) modelElement.getModelElementClass(position));
        }
        else{
          fires.put(position, (Fire) modelElement.getModelElementClass(position));
        }
      }
    }
  }

  private Position randomPosition() {
    return positions[randomGenerator.nextInt(rowCount)][randomGenerator.nextInt(columnCount)];
  }

  @Override
  public List<ModelElement> getState(Position position) {
    List<ModelElement> result = new ArrayList<>();
    if (fires.containsKey(position)) result.add(ModelElement.FIRE);


    for (Extinguisher extinguisher : extinguishers.values()) {
      if (extinguisher.getPosition().equals(position)) result.add(extinguisher.getElement());
    }

    for (Obstacle obstacle : obstacles.values()) {
      if (obstacle.getPosition().equals(position)) result.add(obstacle.getElement());
    }

    return result;
  }

  @Override
  public int rowCount() {
    return rowCount;
  }

  @Override
  public int columnCount() {
    return columnCount;
  }

  public List<Position> updateToNextGeneration() {

    Fire fire = new Fire(randomPosition());
    List<Position> modifiedPositions = new ArrayList<>();

    for(Extinguisher element : extinguishers.values()){
      modifiedPositions.addAll(element.update(this));
    }
    modifiedPositions.addAll(fire.update(this));

    step++;
    return modifiedPositions;
  }

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

  public Map<Position,Fire>getFires(){
    return this.fires;
  }

  @Override
  public Map<Position, Extinguisher> getExtinguishers() {
    return extinguishers;
  }

  public Map<Position, Obstacle> getObstacles() {
    return obstacles;
  }


  @Override
  public void reset() {
    step = 0;
    initializeElements();
  }

  @Override
  public void setState(List<ModelElement> state, Position position) {

    if(extinguishers.containsKey(position)){
      extinguishers.remove(position);
      extinguishers.get(position).extinguish(this,position);
    }
    for (ModelElement element : state) {
      switch (element) {
        case FIRE -> fires.put(position, new Fire(position));
        case FIREFIGHTER -> extinguishers.put(position,new FireFighter(position));
        case CLOUD ->  extinguishers.put(position,new Cloud(position));
      }
    }
  }





}