package com.example.demo.service;

import com.example.demo.exceptions.EmployeeNotFoundException;
import com.example.demo.model.Employee;
import com.example.demo.repository.EmployeeRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Stream;

@Service

public class EmployeeServiceImpl implements IEmployeeService  {

    private static final Logger logger = Logger.getLogger(EmployeeServiceImpl.class.getName());
    @Autowired
    private  EmployeeRepository employeeRepository;

    @Autowired
    private ReactiveMongoTemplate reactiveMongoTemplate;


    @Override
    public Flux<Employee> findAll() {
        return employeeRepository.findAll();
    }
    public Flux<Employee> findAllEmpBySal() {

        AggregationOperation match =Aggregation.match(Criteria.where("role").in("President", "CEO"));
       // AggregationOperation group = Aggregation.group("$_id").first("$name").as("role");
        AggregationOperation sort = Aggregation.sort(Sort.by(Collections.singletonList(Sort.Order.desc("role"))));
        List<AggregationOperation> operationList = new ArrayList<>();
        operationList.add(match);
       // operationList.add(group);
        operationList.add(sort);
        Aggregation typedAggregation = Aggregation.newAggregation(operationList);
        Flux<Employee> employeeFlux = reactiveMongoTemplate.aggregate(typedAggregation, Employee.class, Employee.class);
        return employeeFlux;
    }

    @Override
    public Mono<Employee> findEmployeeById(Integer id) {
            return employeeRepository.findById(id);
    }
    public Mono<Employee> updateEmployee(Employee employee){
        return employeeRepository.findById(employee.getId())
                .map(a ->employee)
                .flatMap(this.employeeRepository::save);

}
    public Mono<Employee> updateEmployeeById(Integer id,  String name){

                return employeeRepository.findById(id).flatMap(employee -> {
                    Employee employee1 =employee;
                    employee1.setName(name);
                    return employeeRepository.save(employee1).map(employee2 -> employee2);
                });

      /*return   employeeRepository.findById(id).flatMap(employee -> {
            Employee e = employee;
            e.setName(name);
          return employeeRepository.save(e);
        });*/
    }
    public Flux<Employee> updateEmployeeBySal(Integer sal,String role){
        Criteria criteria = new Criteria();
        criteria.andOperator(Criteria.where("sal").gte(sal),Criteria.where("sal").lte(200000));
        Query query = new Query(criteria);
        return reactiveMongoTemplate.find(query,Employee.class).flatMap(employee -> {
            Employee e = employee;
            e.setRole(role);
            return employeeRepository.save(e);
        });
      /*return   employeeRepository.findAll().
              filter(a -> a.getSal()>sal).flatMap(employee -> {
         // log.info("in service method of update employee ");
            Employee emp = employee;
            emp.setRole(role);
            return employeeRepository.save(emp);
        });*/

    }
    @Override
    public void createEmp(Employee employee) {
    logger.info("in Create Employee Method");
      employeeRepository.save(employee).
              log("employee name: "+employee.getName());
    }
}