package com.caliverse.admin.domain.service;

import com.caliverse.admin.domain.dao.admin.CaliumMapper;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.entity.web3.ResponseConfirmData;
import com.caliverse.admin.domain.entity.web3.ResponseErrorCode;
import com.caliverse.admin.domain.entity.web3.ResponseRequestData;
import com.caliverse.admin.domain.entity.web3.ResponseWithdrawableData;
import com.caliverse.admin.domain.request.CaliumRequest;
import com.caliverse.admin.domain.request.Web3Request;
import com.caliverse.admin.domain.response.CaliumResponse;
import com.caliverse.admin.domain.response.Web3Response;
import com.caliverse.admin.dynamodb.service.DynamodbCaliumService;
import com.caliverse.admin.global.common.code.CommonCode;
import com.caliverse.admin.global.common.code.ErrorCode;
import com.caliverse.admin.global.common.code.SuccessCode;
import com.caliverse.admin.global.common.constants.MysqlConstants;
import com.caliverse.admin.global.common.constants.Web3Constants;
import com.caliverse.admin.global.common.utils.CommonUtils;
import com.caliverse.admin.history.service.MysqlHistoryLogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
@Slf4j
@RequiredArgsConstructor
public class CaliumService {

    private final CaliumMapper caliumMapper;
    private final HistoryService historyService;
    private final Web3Service web3Service;
//    private final DynamoDBService dynamoDBService;
    private final DynamodbCaliumService dynamodbCaliumService;
    private final MysqlHistoryLogService mysqlHistoryLogService;

    public CaliumResponse getCaliumLimit(){
        Web3Response<ResponseWithdrawableData> web3Response = web3Service.get(
                Web3Constants.URL_SERVER_TYPE,
                null,
                ResponseWithdrawableData.class
        );
        log.info("getCaliumLimit calium WithdrawableInfo: {}", web3Response);

        if(web3Response.isSuccess())
            return CaliumResponse.builder()
                    .status(CommonCode.SUCCESS.getHttpStatus())
                    .result(CommonCode.SUCCESS.getResult())
                    .resultData(CaliumResponse.ResultData.builder()
                            .withdrawableInfo(web3Response.getData())
                            .build()
                    )
                    .build();
        else{
            String code = web3Response.getCode();
            Optional<ResponseErrorCode> error = ResponseErrorCode.fromCode(code);
            return CaliumResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(code)
                    .resultData(CaliumResponse.ResultData.builder()
                            .message(error.get().getMessage())
                            .build()
                    )
                    .build();
        }
    }

    public CaliumResponse getList(Map requestParam){
        //페이징 처리
        requestParam = CommonUtils.pageSetting(requestParam);

        List<Calium> list = caliumMapper.getCaliumRequestList(requestParam);

        double allCnt = caliumMapper.getCaliumTotal();
        double stock_qty = dynamodbCaliumService.getCaliumTotal();

        return CaliumResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(CaliumResponse.ResultData.builder()
                        .caliumList(list)
                        .total(stock_qty)
                        .totalAll(allCnt)
                        .pageNo(requestParam.get("page_no")!=null?
                                Integer.parseInt(requestParam.get("page_no").toString()):1)
                        .build()
                )
                .build();
    }

    public CaliumResponse getDetail(Long id){
        Calium calium = caliumMapper.getCaliumRequestDetail(id);

        log.info("getDetail call Detail Info: {}", calium);

        return CaliumResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(CaliumResponse.ResultData.builder()
                        .calium(calium)
                        .build())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public CaliumResponse postCaliumRequest(CaliumRequest caliumRequest){
        caliumRequest.setCreateBy(CommonUtils.getAdmin().getId());

        Web3Request apiRequest = Web3Request.builder()
                .serverType(Web3Constants.SERVER_NAME)
                .historyMessage(caliumRequest.getContent())
                .requestor(CommonUtils.getAdmin().getName())
                .amount(-Math.abs(caliumRequest.getCount())).build(); // 음수로 변환

        Web3Response<ResponseRequestData> web3Response = web3Service.callWeb3Api(Web3Constants.URL_REQUEST, HttpMethod.POST, apiRequest, ResponseRequestData.class);

        if(!web3Response.isSuccess()){
            log.error("postEvent Web3 api error: {}", web3Response);
            String code = web3Response.getCode();
            ResponseErrorCode error = ResponseErrorCode.fromCode(code).get();
            return CaliumResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(code)
                    .resultData(CaliumResponse.ResultData.builder()
                            .message(error.getMessage())
                            .build()
                    )
                    .build();
        }

        log.info("postEvent Request Api Response: {}", web3Response);
        ResponseRequestData responseData = web3Response.getData();
        caliumRequest.setRequestId(responseData.get_id());
        caliumRequest.setCreateTime(responseData.getCreateTime());

        int result = caliumMapper.postCaliumRequest(caliumRequest);
        log.info("postEvent AdminToolDB Event Save: {}", caliumRequest);

        Calium calium = caliumMapper.getCaliumRequestDetail(caliumRequest.getId());

        mysqlHistoryLogService.insertHistoryLog(
                HISTORYTYPE.CALIUM_ADD,
                MysqlConstants.TABLE_NAME_CALIUM_REQUEST,
                HISTORYTYPE.CALIUM_ADD.name(),
                calium,
                CommonUtils.getAdmin().getEmail(),
                CommonUtils.getClientIp()
        );

        //로그 기록
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("dept",caliumRequest.getDept());
        jsonObject.put("count",caliumRequest.getCount());
        jsonObject.put("content",caliumRequest.getContent());
        historyService.setLog(HISTORYTYPE.CALIUM_ADD, jsonObject);

        return CaliumResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .resultData(CaliumResponse.ResultData.builder()
                        .message(SuccessCode.SAVE.getMessage())
                        .build())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public CaliumResponse updateCaliumCharged(CaliumRequest caliumRequest){
        log.info("updateCaliumCharged calium Request: {}", caliumRequest);
        Calium calium = caliumMapper.getCaliumRequestDetail(caliumRequest.getId());
        Long id = CommonUtils.getAdmin().getId();
        // 상태가 승인완료거나 요청한 본인이 아니면 에러처리
        if(!calium.getStatus().equals(Calium.CALIUMREQUESTSTATUS.COMPLETE) || !calium.getCreateBy().equals(id.toString())){
            log.error("updateCaliumCharged Calium Request Status or User Not Match  status: {}, id: {}", calium.getStatus(), id);
            return CaliumResponse.builder()
                    .status(CommonCode.ERROR.getHttpStatus())
                    .result(ErrorCode.ERROR_CALIUM_FINISH.toString())
                    .resultData(CaliumResponse.ResultData.builder()
                            .build()
                    )
                    .build();
        }

        dynamodbCaliumService.updateCaliumTotal(caliumRequest.getCount());

        updateCaliumRequest(caliumRequest.getId(), Calium.CALIUMREQUESTSTATUS.FINISH);

        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("dynamoDB_update",dynamoResult);

        historyService.setLog(HISTORYTYPE.CALIUM_TOTAL_UPDATE, jsonObject);

        return CaliumResponse.builder()
                .status(CommonCode.SUCCESS.getHttpStatus())
                .result(CommonCode.SUCCESS.getResult())
                .build();
    }

    @Transactional(transactionManager = "transactionManager")
    public void getScheduleCaliumRequestList(){
        List<Calium> scheduleList = caliumMapper.getScheduleCaliumRequest();
        for(Calium calium : scheduleList){
            String url = Web3Constants.URL_REQUEST_CONFIRM + calium.getRequestId();
            Web3Response<ResponseConfirmData> web3Response = web3Service.get(
                    url,
                    null,
                    ResponseConfirmData.class
            );

            if(web3Response.isSuccess()){
                ResponseConfirmData data = web3Response.getData();
                String state = data.getState();
                if(state.equals("confirm")){
                    updateCaliumRequest(calium.getId(), Calium.CALIUMREQUESTSTATUS.COMPLETE, data);
                    log.info("getScheduleCaliumRequestList Calium Request Confirm: {}", data);
                }else if(state.equals("cancel")){
                    updateCaliumRequest(calium.getId(), Calium.CALIUMREQUESTSTATUS.REJECT, data);
                    log.info("getScheduleCaliumRequestList Calium Request Cancel: {}", data);
                }
            }else{
                String code = web3Response.getCode();
                Optional<ResponseErrorCode> error = ResponseErrorCode.fromCode(code);
                log.error("getScheduleCaliumRequestList calium confirm request request_id: {}, Error: {}", calium.getRequestId(), error.get().getMessage());
            }
        }
    }

    private void updateCaliumRequest(Long id, Calium.CALIUMREQUESTSTATUS status){
        Map<String,Object> map = new HashMap<>();
        map.put("id", id);
        map.put("status", status.toString());
        map.put("updateBy", CommonUtils.getAdmin().getId());
        caliumMapper.updateStatusCaliumRequest(map);
    }

    private void updateCaliumRequest(Long id, Calium.CALIUMREQUESTSTATUS status, ResponseConfirmData data){
        Map<String,Object> map = new HashMap<>();
        map.put("id", id);
        map.put("status", status.toString());
        map.put("stateTime", data.getStateTime());
        map.put("stateMessage", data.getState().equals("confirm") ? data.getStateMessage(): "");
        caliumMapper.updateStatusCaliumRequest(map);
    }
}
