package com.r11.tools.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.mappers.MockedMessageMapper;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import com.r11.tools.repository.MockedResponseRepository;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * Service for {@link com.r11.tools.controller.MockController} and {@link com.r11.tools.controller.MockController}
 * Allows for performing CRUD operations on {@link MockedMessageDto}
 * @author Rafał Żukowicz
 * @author Gabriel Modzelewski
 */
@Service
@AllArgsConstructor
public class KlausServiceImpl implements KlausService {
    private final MockedMessageMapper mockedMessageMapper;
    private final Logger log = LogManager.getRootLogger();
    private final MockedResponseRepository mockedResponseRepository;
    private final ObjectMapper objectMapper;

    /**
     * Removes message of given id in given key-uuid set
     * @param clientUUID the key-uuid of given set of messages
     * @param mockedResponseId unique id of given message
     * @return confirmation and status 200 OK
     */
    @Override
    public ResponseEntity<String> deleteMockedResponse(UUID clientUUID, int mockedResponseId) {
        String key = clientUUID.toString() + "_" + mockedResponseId;
        mockedResponseRepository.deleteById(key);
        log.info("Message: "+mockedResponseId+" has been removed.");
        return new ResponseEntity<>("MockedResponse has been removed successfully",
                new HttpHeaders(), HttpStatus.ACCEPTED);
    }

    /**
     * Returns all messages of given key-uuid
     * @param clientUUID the key-uuid of given set of messages
     * @return List of {@link MockedMessageDto}
     */
    @Override
    public List<MockedMessageDto> getAllMockedResponses(UUID clientUUID){
        Optional<List<MockedMessage>> listOptional = mockedResponseRepository.findAllByClientUUID(clientUUID);
        log.info("Messages for UUID: "+clientUUID+" has been fetched from DB.");
        return listOptional.map(mockedMessages -> mockedMessages.stream()
                .map(mockedMessageMapper::mockedMessageToMockedMessageDto)
                .collect(Collectors.toList())).orElse(List.of());
    }

    /**
     * Returns {@link MockedMessageDto} of given id and key-uuid. If message doesn't then empty message is returned
     * @param clientUUID the key-uuid of given set of messages
     * @param mockedResponseId unique id of given message
     * @return {@link MockedMessageDto} object
     */
    @SneakyThrows
    @Override
    public MockedMessageDto getMockedResponse(UUID clientUUID, int mockedResponseId){
        String key = clientUUID.toString() + "_" + mockedResponseId;
        Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(key);
        MockedMessageDto mockedMessageDto = MockedMessageDto.builder()
                .clientUUID(clientUUID)
                .mockedResponseId(mockedResponseId)
                .build();
        if (optionalMockedMessage.isPresent()) {
            mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());
            //log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
            return mockedMessageDto;
        }
        //log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
        return mockedMessageDto;
    }

    /**
     * Allows to modify mocked message. If message of given id and key-uuid doesn't exist a new entry is created
     * @param mockedMessageDto message to be saved
     * @return Confirmation and status 200 OK
     */
    @SneakyThrows
    @Override
    public ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto) {
        mockedResponseRepository.save(mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto));
        //log.info(mockedMessageDto.toString().replaceAll("\"", "\\\\\""));
        return new ResponseEntity<>("MockedResponse has been setup successfully!", new HttpHeaders(),
                HttpStatus.ACCEPTED);
    }

}
