package ru.soune.nocopy.service.tariff;

import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.tarriff.TariffDTO;
import ru.soune.nocopy.dto.tarriff.TariffRequest;
import ru.soune.nocopy.entity.tarif.Tariff;
import ru.soune.nocopy.entity.tarif.TariffTimeTerm;
import ru.soune.nocopy.entity.tarif.TariffType;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.TariffNotFoundException;
import ru.soune.nocopy.repository.TariffInfoRepository;
import ru.soune.nocopy.repository.TariffRepository;

import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class TariffService {

    private final TariffRepository tariffRepository;

    private final TariffInfoRepository tariffInfoRepository;

    public void addTariff(String tariffName, double price, String type, int tokens, long diskSize, long maxUsers,
                          int maxFilesCount, String tariffTerm, String description, String accountType) {
        Tariff tariff = new Tariff();
        tariff.setName(tariffName);
        tariff.setPrice(price);
        tariff.setType(type);
        tariff.setTokens(tokens);
        tariff.setDiskSize(diskSize);
        tariff.setMaxUsers(maxUsers);
        tariff.setMaxFilesCount(maxFilesCount);
        tariff.setTariffTerm(TariffTimeTerm.valueOf(tariffTerm.toUpperCase()));
        tariff.setDescription(description);
        tariff.setTariffAccountType(accountType);

        tariffRepository.save(tariff);
    }

    public List<TariffDTO> getTariffByAccountType(User user) {
        String typeAccount = user.canManageCompanySettings() ? "b2b": "b2c";

        return tariffRepository.findByTariffAccountType(typeAccount)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    public Boolean existTariffInfoByTariffId(Long id) {
        return tariffInfoRepository.existsByTariffId(id);
    }

    public List<TariffDTO> getTariffByAccountTypeAndTariffTerm(User user, TariffTimeTerm tariffTerm) {
        String typeAccount = user.canManageCompanySettings() ? "b2b": "b2c";

        return tariffRepository.findByTariffAccountTypeAndTariffTerm(typeAccount, tariffTerm)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    public Page<Tariff> getTariffs(Pageable pageable) {
        return tariffRepository.findAll(pageable);
    }

    public Page<Tariff> getTariffByType(String type, Pageable pageable) {
        return tariffRepository.findByTariffAccountType(type, pageable);
    }

    public List<TariffDTO> getTariffByType(String type) {
        return tariffRepository.findByTariffAccountType(type)
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    public List<TariffDTO> getAllTariffs() {
        return tariffRepository.findAllByOrderByPriceAsc()
                .stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    public TariffDTO getTariffById(Long id) {
        return tariffRepository.findById(id)
                .map(this::convertToDTO)
                .orElseThrow(() ->  new TariffNotFoundException("Tariff not found"));
    }

    public TariffDTO getTariffByType(TariffType type) {
        return tariffRepository.findByType(type.toString())
                .map(this::convertToDTO)
                .orElseThrow(() ->  new TariffNotFoundException("Tariff not found"));
    }

    @Transactional
    public TariffDTO updateTariff(Long id, TariffDTO tariffDTO, TariffRequest tariffRequest) {
        Tariff tariff = tariffRepository.findById(id)
                .orElseThrow(() -> new TariffNotFoundException("Tariff not found"));
        Tariff updateTariffFromDTO = updateTariffFromDTO(tariff, tariffDTO, tariffRequest);
        Tariff save = tariffRepository.save(updateTariffFromDTO);

        return convertToDTO(save);
    }

    @Transactional
    public void deleteTariff(Long id) {
        tariffRepository.deleteById(id);
    }

    private TariffDTO convertToDTO(Tariff tariff) {
        TariffTimeTerm tariffTerm = tariff.getTariffTerm();

        return new TariffDTO(
                tariff.getId(),
                tariff.getType(),
                tariff.getName(),
                tariff.getPrice(),
                tariff.getTokens(),
                tariff.getMaxFilesCount(),
                tariff.getDiskSize(),
                tariff.getMaxUsers(),
                tariffTerm == null ? "" : tariffTerm.name(),
                tariff.getDescription() == null ? "" : tariff.getDescription()
        );
    }

    private Tariff updateTariffFromDTO(Tariff tariff, TariffDTO dto, TariffRequest tariffRequest) {
        if (tariffRequest.getType() != null) {
            tariff.setType(tariffRequest.getType());
        }
        if (tariffRequest.getName() != null) {
            tariff.setName(tariffRequest.getName());
        }
        if (tariffRequest.getPrice() != null) {
            tariff.setPrice(tariffRequest.getPrice());
        }
        if (tariffRequest.getTokens() != null) {
            tariff.setTokens(tariffRequest.getTokens());
        }
        if (tariffRequest.getMaxFilesCount() != null) {
            tariff.setMaxFilesCount(tariffRequest.getMaxFilesCount());
        }
        if (tariffRequest.getDiskSize() != null) {
            tariff.setDiskSize(tariffRequest.getDiskSize());
        }
        if (tariffRequest.getMaxUsers() != null) {
            tariff.setMaxUsers(tariffRequest.getMaxUsers());
        }
        if (tariffRequest.getDescription() != null) {
            tariff.setDescription(tariffRequest.getDescription());
        }
        if (tariffRequest.getTariffTerm() != null) {
            tariff.setTariffTerm(TariffTimeTerm.valueOf(tariffRequest.getTariffTerm()));
        }

        return tariff;
    }
}
