package com.bytesw.bytebot.service;

import com.bytesw.bytebot.bean.FlightBean;
import com.bytesw.bytebot.model.Airport;
import com.bytesw.bytebot.model.Flight;
import com.bytesw.bytebot.repository.AirportRepository;
import com.bytesw.bytebot.repository.FlightRepository;
import com.bytesw.xdf.exception.NotFoundException;
import com.bytesw.xdf.sql.beans.Pagination;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@Transactional
public class FlightService extends CustomPaginationService<Flight> {
    @Autowired
    private FlightRepository flightRepository;

    @Autowired
    private AirportRepository airportRepository;

    public Long create(FlightBean bean) {
        Optional<Airport> origin = this.airportRepository.findById(bean.getOriginAirportId());
        Optional<Airport> destination = this.airportRepository.findById(bean.getDestinationAirportId());
        if (!origin.isPresent()) {
            throw new NotFoundException();
        }
        if (!destination.isPresent()) {
            throw new NotFoundException();
        }
        Flight model = new Flight();
        model.setAirline(bean.getAirline());
        model.setAirplane(bean.getAirplane());
        model.setArrivalDate(bean.getArrivalDate());
        model.setDepartureDate(bean.getDepartureDate());
        model.setArrivalTime(bean.getArrivalTime());
        model.setDepartureTime(bean.getDepartureTime());
        model.setOrigin(origin.get());
        model.setDestination(destination.get());
        return this.flightRepository.save(model).getId();
    }

    public Long update(FlightBean bean, Long id) {
        Optional<Flight> found = this.flightRepository.findById(id);
        if (!found.isPresent()) {
            throw new NotFoundException();
        }
        Optional<Airport> origin = this.airportRepository.findById(bean.getOriginAirportId());
        Optional<Airport> destination = this.airportRepository.findById(bean.getDestinationAirportId());
        if (!origin.isPresent()) {
            throw new NotFoundException();
        }
        if (!destination.isPresent()) {
            throw new NotFoundException();
        }
        Flight model = found.get();
        model.setAirline(bean.getAirline());
        model.setAirplane(bean.getAirplane());
        model.setArrivalDate(bean.getArrivalDate());
        model.setDepartureDate(bean.getDepartureDate());
        model.setArrivalTime(bean.getArrivalTime());
        model.setDepartureTime(bean.getDepartureTime());
        model.setOrigin(origin.get());
        model.setDestination(destination.get());
        return this.flightRepository.save(model).getId();
    }

    public void delete(Long id) {
        Optional<Flight> found = this.flightRepository.findById(id);
        if (!found.isPresent()) {
            throw new NotFoundException();
        }
        this.flightRepository.delete(found.get());
    }

    public FlightBean getFlight(Long id) {
        Optional<Flight> found = flightRepository.findById(id);

        if (!found.isPresent()) {
            throw new NotFoundException();
        }
        FlightBean bean = new FlightBean();
        bean.setId(found.get().getId());
        bean.setAirline(found.get().getAirline());
        bean.setAirplane(found.get().getAirplane());
        bean.setArrivalDate(found.get().getArrivalDate());
        bean.setDepartureDate(found.get().getDepartureDate());
        bean.setArrivalTime(found.get().getArrivalTime());
        bean.setDepartureTime(found.get().getDepartureTime());
        bean.setOriginAirportId(found.get().getOrigin().getId());
        bean.setOriginAirportName(found.get().getOrigin().getAirportName());
        bean.setDestinationAirportId(found.get().getDestination().getId());
        bean.setDestinationAirportName(found.get().getDestination().getAirportName());
        return bean;
    }

    public List<Flight> getFlightAll() {
        List<Flight> list = this.flightRepository.findAll();
        if (list.isEmpty()) {
            throw new NotFoundException("Error al listar reservas.");
        }
        return list;
    }

    public void searchByPagination(Pagination<FlightBean> pagination) {
        if (pagination.getItemsPerPage() == 0) {
            pagination.setItemsPerPage(10);
        }

        Sort sort = null;
        if (pagination.getSortFields() != null) {
            sort = createSort(pagination);
        }

        Pageable pageable = null;
        if (sort != null) {
            pageable = PageRequest.of(pagination.getCurrentPage(), pagination.getItemsPerPage(), sort);
        } else {
            pageable = PageRequest.of(pagination.getCurrentPage(), pagination.getItemsPerPage());
        }

        Specification<Flight> specification = (Specification<Flight>) (root, query, criteriaBuilder)
                -> criteriaBuilder.notEqual(root.get("id"), 0);

        if (pagination.getFilterExpression() != null && pagination.getFilterExpression().length() > 0) {
            specification = createSpecification(pagination.getFilterExpression()).and(specification);
        }

        Page<Flight> page = flightRepository.findAll(specification, pageable);

        pagination.setTotalItems(page.getTotalElements());
        pagination.setTotalPages(page.getTotalPages());

        // Clone to array
        List<FlightBean> list = new ArrayList<>();

        for (Flight flight : page.getContent()) {
            list.add(FlightBean.miniClone(flight));
        }

        pagination.setData(list);
    }
}
