package enseirb.myinpulse.service.database;

import static enseirb.myinpulse.model.ProjectDecisionValue.PENDING;

import enseirb.myinpulse.model.*;
import enseirb.myinpulse.repository.ProjectRepository;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.Optional;

@Service
public class ProjectService {

    protected static final Logger logger = LogManager.getLogger();

    private final ProjectRepository projectRepository;

    @Autowired
    ProjectService(ProjectRepository projectRepository) {
        this.projectRepository = projectRepository;
    }

    public Iterable<Project> getAllProjects() {
        return this.projectRepository.findAll();
    }

    public Project getProjectById(Long id) {
        Optional<Project> project = this.projectRepository.findById(id);
        if (project.isEmpty()) {
            logger.error("No project found with id {}", id);
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
        }
        return project.get();
    }

    public Iterable<Project> getProjectsByAdminId(Administrator administrator) {
        return this.projectRepository.findByProjectAdministrator(administrator);
    }

    // TODO: validation
    public Project addNewProject(Project project) {
        return this.projectRepository.save(project);
    }

    public void updateProjectName(long idProject, String name) {
        Project project = getProjectById(idProject);
        project.setProjectName(name);
        this.projectRepository.save(project);
    }

    public void updateProjectLogo(long idProject, byte[] logo) {
        Project project = getProjectById(idProject);
        project.setLogo(logo);
        this.projectRepository.save(project);
    }

    public void updateProjectStatus(long idProject, ProjectDecisionValue status) {
        Project project = getProjectById(idProject);
        project.setProjectStatus(status);
        this.projectRepository.save(project);
    }

    public void updateProjectEntrepreneurParticipation(
            long idProject, Entrepreneur entrepreneurParticipation) {
        Project project = getProjectById(idProject);
        project.updateListEntrepreneurParticipation(entrepreneurParticipation);
        this.projectRepository.save(project);
    }

    public void updateProjectListSectionCell(long idProject, SectionCell sectionCell) {
        Project project = getProjectById(idProject);
        project.updateListSectionCell(sectionCell);
        this.projectRepository.save(project);
    }

    public void updateProjectAdministrator(long idProject, Administrator administrator) {
        Project project = getProjectById(idProject);
        project.setProjectAdministrator(administrator);
        this.projectRepository.save(project);
    }

    public Project updateProject(
            Long id,
            String projectName,
            byte[] logo,
            ProjectDecisionValue projectStatus,
            Entrepreneur entrepreneurParticipation,
            SectionCell sectionCell,
            Administrator administrator) {
        Optional<Project> project = this.projectRepository.findById(id);

        if (project.isEmpty()) {
            logger.error("Project with id {} not found.", id);
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
        }

        if (projectName != null) {
            project.get().setProjectName(projectName);
        }

        if (logo != null) {
            project.get().setLogo(logo);
        }
        if (projectStatus != null) {
            // TODO: check if this is really useful
            /*
            if (!validateStatus(projectStatus)) {
                logger.error("updateProjectStatus: Invalid status {}", projectStatus);
                throw new ResponseStatusException(
                        HttpStatus.NOT_ACCEPTABLE, "Ce status n'est pas accepté");
            }
            */
            project.get().setProjectStatus(projectStatus);
        }
        if (entrepreneurParticipation != null) {
            project.get().updateListEntrepreneurParticipation(entrepreneurParticipation);
        }
        if (sectionCell != null) {
            project.get().updateListSectionCell(sectionCell);
        }
        if (administrator != null) {
            project.get().setProjectAdministrator(administrator);
        }

        return this.projectRepository.save(project.get());
    }

    public Boolean validateStatus(String status) {
        return List.of("PENDING", "ACTIVE", "ENDED").contains(status);
    }

    public Iterable<Project> getPendingProjects() {
        return this.projectRepository.findByProjectStatus(PENDING);
    }

    public void deleteProjectById(Long id) {
        this.projectRepository.deleteById(id);
    }

    public Project getProjectByName(String name, boolean noerror) {
        Optional<Project> project = this.projectRepository.findByProjectName(name);
        if (project.isEmpty()) {
            if (noerror) logger.error("No project found with name {}", name);
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Ce projet n'existe pas");
        }
        return project.get();
    }

    public Project getProjectByName(String name) {
        return getProjectByName(name, false);
    }
}