package com.caliverse.admin.mongodb.service;

import com.caliverse.admin.domain.entity.FieldChange;
import com.caliverse.admin.domain.entity.log.LogAction;
import com.caliverse.admin.domain.entity.log.LogStatus;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.constants.CommonConstants;
import com.caliverse.admin.global.common.exception.RestApiException;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.global.component.manager.TransactionIdManager;
import com.caliverse.admin.mongodb.ChangeDetector;
import com.caliverse.admin.mongodb.entity.EDBOperationType;
import com.caliverse.admin.mongodb.repository.MysqlHistoryLogRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;

@Service
@RequiredArgsConstructor
@Slf4j
public class MysqlHistoryLogService {

    private final TransactionIdManager transactionIdManager;
    private final MysqlHistoryLogRepository mysqlHistoryLogRepository;
    private final BusinessLogService businessLogService;

    public <T> void insertHistoryLog(
            String prodId,
            LogAction action,
            LogStatus logStatus,
            String tableName,
            String message,
            T data
    ){
        try {
            List<FieldChange> changes = ChangeDetector.detectInsertChanges(data);

            if(!changes.isEmpty() || action != null) {

                CompletableFuture<String> logFuture = businessLogService.logMariadb(
                        prodId,
                        action,
                        tableName,
                        EDBOperationType.INSERT,
                        CommonUtils.getAdmin() == null ? CommonConstants.SYSTEM : CommonUtils.getAdmin().getEmail(),
                        CommonUtils.getClientIp() == null ? CommonConstants.SYSTEM : CommonUtils.getClientIp(),
                        data,
                        logStatus,
                        changes,
                        message,
                        transactionIdManager.getCurrentTransactionId()
                );

                logFuture.whenComplete((result, throwable) -> {
                    if (throwable != null) {
                        log.warn("Business log failed for info: {}, error: {}", CommonUtils.objectByString(data), throwable.getMessage());
                    }
                });
            }
        }catch(Exception e){
            log.error("Insert historyLog Save Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_HISTORY_SAVE.getMessage());
        }
    }

    public <T> void updateHistoryLog(
            String prodId,
            LogAction action,
            LogStatus logStatus,
            String tableName,
            String message,
            T beforeData,
            T afterData
    ){
        try {
            List<FieldChange> changes = ChangeDetector.detectChanges(
                    beforeData,
                    afterData
            );
            if(!changes.isEmpty() || action != null) {
                CompletableFuture<String> logFuture = businessLogService.logMariadb(
                        prodId,
                        action,
                        tableName,
                        EDBOperationType.UPDATE,
                        CommonUtils.getAdmin() == null ? CommonConstants.SYSTEM : CommonUtils.getAdmin().getEmail(),
                        CommonUtils.getClientIp() == null ? CommonConstants.SYSTEM : CommonUtils.getClientIp(),
                        afterData,
                        logStatus,
                        changes,
                        message,
                        transactionIdManager.getCurrentTransactionId()
                );

                logFuture.whenComplete((result, throwable) -> {
                    if (throwable != null) {
                        log.warn("Business log failed for info: {}, error: {}", CommonUtils.objectByString(afterData), throwable.getMessage());
                    }
                });
            }
        }catch(Exception e){
            log.error("Update historyLog Save Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_HISTORY_SAVE.getMessage());
        }
    }

    public <T> void deleteHistoryLog(
            String prodId,
            LogAction action,
            LogStatus logStatus,
            String tableName,
            String message,
            T data
    ){
        try {
            List<FieldChange> changes;
            if (data instanceof Collection && !((Collection<?>) data).isEmpty()) {
                changes = ChangeDetector.detectCollectionChanges((Collection<?>) data, tableName);
            } else {
                changes = ChangeDetector.detectDeleteChanges(data);
            }

            if(!changes.isEmpty() || action != null){
                CompletableFuture<String> logFuture = businessLogService.logMariadb(
                        prodId,
                        action,
                        tableName,
                        EDBOperationType.DELETE,
                        CommonUtils.getAdmin() == null ? CommonConstants.SYSTEM : CommonUtils.getAdmin().getEmail(),
                        CommonUtils.getClientIp() == null ? CommonConstants.SYSTEM : CommonUtils.getClientIp(),
                        data,
                        logStatus,
                        changes,
                        message,
                        transactionIdManager.getCurrentTransactionId()
                );

                logFuture.whenComplete((result, throwable) -> {
                    if (throwable != null) {
                        log.warn("Business log failed for info: {}, error: {}", CommonUtils.objectByString(data), throwable.getMessage());
                    }
                });
            }
        }catch(Exception e){
            log.error("Delete historyLog Save Error", e);
            throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_HISTORY_SAVE.getMessage());
        }
    }
}
