package com.arms.api.serverinfo.service;

import com.arms.api.serverinfo.model.dto.ServerInfoDTO;
import com.arms.api.serverinfo.model.vo.ServerInfoVO;
import com.arms.api.serverinfo.model.entity.ServerInfoEntity;
import com.arms.api.util.UUIDUtil;
import com.arms.api.util.aes.AES256Decryption;
import com.arms.api.util.aspect.DwrSendAlarm;
import com.arms.api.serverinfo.model.entity.JiraServerPureEntity;
import com.arms.api.issue.almapi.msa_communicate.BackendJiraServer;
import com.arms.api.util.aspect.SlackSendAlarm;
import com.arms.api.util.errors.ErrorCode;

import com.arms.egovframework.javaservice.esframework.repository.common.EsCommonRepositoryWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.arms.api.serverinfo.model.vo.ServerInfoVO.fromEntity;


@Slf4j
@Service("serverInfo_서비스")
@AllArgsConstructor
public class ServerInfoServiceImpl implements ServerInfoService {

    private final EsCommonRepositoryWrapper<ServerInfoEntity> esCommonRepositoryWrapper;

    private final BackendJiraServer backendJiraServer;

    private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private final AES256Decryption aes256Decryption;

    @Override
    public String getDecryptPasswordOrToken(String passwordToken){
        return aes256Decryption.decrypt(passwordToken);
    }

    @Override
    public ServerInfoEntity saveOrUpdateServerInfo(ServerInfoDTO serverInfoDTO) {
        ServerInfoEntity result;

        try {
            ServerInfoEntity serverInfoEntity = ServerInfoEntity.builder()
                        .connectId(serverInfoDTO.getConnectId())
                        .type(serverInfoDTO.getType())
                        .uri(serverInfoDTO.getUri())
                        .userId(serverInfoDTO.getUserId())
                        .passwordOrToken(serverInfoDTO.getPasswordOrToken())
                        .createdDate(serverInfoDTO.getCreatedDate())
                        .updatedDate(serverInfoDTO.getUpdatedDate())
                    .build();
            result = esCommonRepositoryWrapper.save(serverInfoEntity);
        }
        catch (Exception e) {
            log.error(e.getMessage());
            throw new IllegalArgumentException(e.getMessage(), e);
        }

        return result;
    }

    @Override
    public List<ServerInfoVO> serverInfoListByConnectIds(List<String> connectIds) {

        return connectIds.stream()
                .map(esCommonRepositoryWrapper::findDocById)
                .filter(Objects::nonNull)
                .map(ServerInfoVO::fromEntityPublic)
                .collect(Collectors.toList());
    }

    @Override
    @Async
    @DwrSendAlarm(messageOnStart = "serverInfoVO 백업 시작", messageOnEnd = "serverInfoVO 백업 종료")
    @SlackSendAlarm(messageOnStart = "serverInfoVO 백업 시작", messageOnEnd = "serverInfoVO 백업 종료")
    public void serverInfoBackup() {
        String logMessagePrefix = "[ ServerInfoServiceImpl :: serverInfoBackup ]";
        String shortUUID = UUIDUtil.createShortUUID();

        LocalDateTime startTime = LocalDateTime.now();
        log.info("[{}] :: {} :: started at {}", shortUUID, logMessagePrefix, startTime.format(timeFormatter));

        ResponseEntity<List<JiraServerPureEntity>> response = backendJiraServer.getJiraServerMonitor();
        List<JiraServerPureEntity> serverInfoList = response.getBody();

        Optional.ofNullable(serverInfoList)
            .orElseGet(Collections::emptyList)
            .forEach(serverInfo -> {
                ServerInfoEntity serverInfoEntity =
                        Optional.ofNullable(esCommonRepositoryWrapper.findDocById(serverInfo.getC_jira_server_etc()))
                                .orElseGet(ServerInfoEntity::new);
                serverInfoEntity.setUri(serverInfo.getC_jira_server_base_url());
                serverInfoEntity.setType(serverInfo.getC_jira_server_type());
                serverInfoEntity.setUserId(serverInfo.getC_jira_server_connect_id());
                serverInfoEntity.setPasswordOrToken(serverInfo.getC_jira_server_connect_pw());
                serverInfoEntity.setConnectId(serverInfo.getC_jira_server_etc());
                esCommonRepositoryWrapper.save(serverInfoEntity);
            });

        LocalDateTime endTime = LocalDateTime.now();
        Duration elapsed = Duration.between(startTime, endTime);
        log.info("[{}] :: {} :: finished at {} (completed in {} ms)", shortUUID, logMessagePrefix, endTime.format(timeFormatter), elapsed.toMillis());
    }

    @Override
    public void deleteServerInfo(String serverId) {
        esCommonRepositoryWrapper.deleteById(serverId);
    }

    @Override
    public ServerInfoVO verifyServerInfo(String serverId) {

        if (serverId == null) {
            log.error("이슈 상세정보 가져오기 Error: 연결_아이디 {}" , ErrorCode.PARAMETER_SERVER_ID_MISSING.getErrorMsg());
            throw new IllegalArgumentException("이슈 상세정보 가져오기 Error: 연결_아이디 " + ErrorCode.PARAMETER_SERVER_ID_MISSING.getErrorMsg());
        }

        ServerInfoVO serverInfoVO = getServerInfo(serverId);

        if (serverInfoVO == null) {
            log.error("등록된 서버 정보가 아닙니다.");
            throw new IllegalArgumentException(ErrorCode.SERVER_INFO_ERROR.getErrorMsg());
        }
        else if (serverInfoVO.getUri() == null || serverInfoVO.getUri().isEmpty()) {
            throw new IllegalArgumentException(ErrorCode.SERVER_URI_INFO_ERROR.getErrorMsg());
        }
        else if (serverInfoVO.getUserId() == null || serverInfoVO.getUserId().isEmpty()) {
            log.error("사용자 아이디 조회에 실패했습니다.");
            throw new IllegalArgumentException(ErrorCode.SERVER_ID_INFO_ERROR.getErrorMsg());
        }
        else {
            String decryptPasswordOrToken = getDecryptPasswordOrToken(serverInfoVO.getPasswordOrToken());
            if (decryptPasswordOrToken == null || decryptPasswordOrToken.isEmpty()) {
                log.info("비밀 번호 및 토큰 정보 조회에 실패했습니다.");
                throw new IllegalArgumentException(ErrorCode.SERVER_PW_OR_API_TOKEN_INFO_ERROR.getErrorMsg());
            }
        }

        return serverInfoVO;
    }

    private ServerInfoVO getServerInfo(String serverId) {
        ServerInfoEntity serverInfoEntity = esCommonRepositoryWrapper.findDocById(serverId);
        return fromEntity(serverInfoEntity);
    }

    @Override
    public Map<String, String> getServerIdToTypeMap() {
        return esCommonRepositoryWrapper.findAllHits().toDocs().stream()
                .collect(Collectors.toMap(ServerInfoEntity::getConnectId, ServerInfoEntity::getType));
    }


}
