package cz.muni.fi.pa165.electricityTarifMicroservice.electricityprices;

import cz.muni.fi.pa165.electricityTarifMicroservice.electricityprices.dtos.ElectricityPriceGetFullDto;
import cz.muni.fi.pa165.electricityTarifMicroservice.electricityprices.dtos.ElectricityPricePostDto;
import jakarta.annotation.PostConstruct;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;
import java.util.Optional;

@Service
public class ElectricityPriceServiceImpl implements ElectricityPriceService {
  private final ElectricityPriceRepository electricityPriceRepository;
  private final ElectricityPriceMapper mapStructMapper;

  public ElectricityPriceServiceImpl(ElectricityPriceRepository electricityPriceRepository, ElectricityPriceMapper mapStructMapper) {
    this.electricityPriceRepository = electricityPriceRepository;
    this.mapStructMapper = mapStructMapper;
  }

  @PostConstruct
  public void init() {
    electricityPriceRepository.save(
        ElectricityPrice.builder()
            .companyId("1")
            .priceHighTariff(399.0)
            .priceLowTariff(299.0)
            .build());
  }

  @Override
  @Transactional(readOnly = true)
  public double getElectricityPrice(String companyId) {
    ElectricityPrice electricityPrice = electricityPriceRepository.findByCompanyId(companyId);
    if (electricityPrice == null) {
      throw new ResponseStatusException(HttpStatus.NOT_FOUND,"No electricity price information for that company.");
    }
    return getPriceAcordingToDate(electricityPrice);
  }

  @Override
  @Transactional(readOnly = true)
  public ElectricityPriceGetFullDto getElectricityPriceObj(String companyId) {
    return mapStructMapper.electricityPriceToElectricityPriceGetFullDto(electricityPriceRepository.findByCompanyId(companyId));
  }

  private double getPriceAcordingToDate(ElectricityPrice price) {
    LocalTime localTime = LocalTime.now();
    //weekend prices
    if(LocalDate.now().getDayOfWeek() == DayOfWeek.SATURDAY || LocalDate.now().getDayOfWeek() == DayOfWeek.SUNDAY)
      return price.getPriceLowTariff();
    //peak hours
    if(localTime.getHour() > 7 && localTime.getHour() < 21)
      return price.getPriceHighTariff();
    //off-peak hours
    return price.getPriceLowTariff();
  }

  @Override
  @Transactional(readOnly = true)
  public List<ElectricityPriceGetFullDto> getAllElectricityPrice() {
    return mapStructMapper.electricityPriceListToElectricityPriceGetFullDtoList(electricityPriceRepository.findAll());
  }

  @Override
  @Transactional(readOnly = true)
  public Page<ElectricityPriceGetFullDto> getAllElectricityPricePagable(Pageable pageable) {
    return mapStructMapper.mapToPageDto(electricityPriceRepository.findAll(pageable));
  }

  @Override
  @Transactional
  public String deleteElectricityPriceForCompany(String companyId) {
    return Optional.ofNullable(electricityPriceRepository.findByCompanyId(companyId))
            .map(electricityPrice -> {
              electricityPriceRepository.deleteCompany(companyId);
              return "Deleted electricity price for a company.";
            })
            .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Did not delete the electricity prices - company not found."));
  }

  @Override
  @Transactional
  public ElectricityPrice setElectricityPrice(ElectricityPricePostDto req) {
    Optional.ofNullable(electricityPriceRepository.findByCompanyId(req.getCompanyId()))
            .ifPresent(electricityPriceRepository::delete);
    return electricityPriceRepository.save(mapStructMapper.electricityPricePostDtoToElectricityPrice(req));
  }

  @Override
  @Transactional(readOnly = true)
  public double averagePriceHighTariff() {
    return electricityPriceRepository.averagePriceHighTariff();
  }

  @Override
  @Transactional(readOnly = true)
  public double averagePriceLowTariff() {
    return electricityPriceRepository.averagePriceLowTariff();
  }
}
