package com.bcxin.backend.domain.syncs.services.impls;

import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.core.AppConfigProperty;
import com.bcxin.backend.core.components.StorageProvider;
import com.bcxin.backend.core.exceptions.SaasBadException;
import com.bcxin.backend.core.utils.ExceptionUtils;
import com.bcxin.backend.domain.SimpleLocalLockComponent;
import com.bcxin.backend.domain.enums.SyncType;
import com.bcxin.backend.domain.repositories.DomainSuperviseRepository;
import com.bcxin.backend.domain.syncs.components.HttpRequestProvider;
import com.bcxin.backend.domain.syncs.dtos.*;
import com.bcxin.backend.domain.syncs.repositories.DataSyncQueueRepository;
import com.bcxin.backend.domain.syncs.services.DataSyncQueueService;
import com.bcxin.runtime.domain.snapshoots.FormSyncTargetConfigSnapshot;
import com.bcxin.runtime.domain.syncs.dtos.DataSetDto;
import com.bcxin.runtime.domain.syncs.dtos.FileItemRequestDto;
import com.bcxin.runtime.domain.syncs.entities.DataSyncQueueEntity;
import com.bcxin.runtime.domain.syncs.enums.SyncProcessStatus;
import com.bcxin.saas.core.components.JsonProvider;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service("DataSyncQueueServiceImpl")
public class DataSyncQueueServiceImpl extends DataSyncQueueServiceBase implements DataSyncQueueService {
    public DataSyncQueueServiceImpl(DataSyncQueueRepository dataSyncQueueRepository,
                                    JsonProvider jsonProvider,
                                    HttpRequestProvider httpRequestProvider,
                                    AppConfigProperty appConfigProperty,
                                    StorageProvider storageProvider,
                                    DomainSuperviseRepository domainSuperviseRepository,
                                    SimpleLocalLockComponent simpleLocalLockComponent) {
        super(dataSyncQueueRepository, jsonProvider, httpRequestProvider, appConfigProperty,
                storageProvider, domainSuperviseRepository, simpleLocalLockComponent);
    }

    @Override
    public void dispatchData() {
        this.dispatch(SyncType.DirectlyData);
    }

    @Override
    public void dispatchFile() {
        this.dispatch(SyncType.DirectlyFile);
    }

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    private SyncDataMeta saveNormalRequestData(DbDataImportRequestDto dataImportRequestDto,boolean isData) {
        String path = String.format("/uploads/sync/response/normal/%s/%s-%s.txt",
                isData?"data":"files", simpleDateFormat.format(new Date()), UUID.randomUUID());
        String data = this.jsonProvider.getJson(dataImportRequestDto);
        byte[] content = data.getBytes(StandardCharsets.UTF_8);
        String realPath = this.storageProvider.save(path, content);

        return SyncDataMeta.create(path, content.length, realPath,Collections.EMPTY_LIST);
    }

    @Override
    protected void executeSyncFileCore(DataSyncParameter dataSyncParameter) {
        /*
        DataSyncQueueEntity data = dataSyncParameter.getDataSyncQueueEntity();

        StringBuilder sb = new StringBuilder();
        try {
            sb.append(String.format("%s: 正在执行: DataSyncQueueServiceImpl.dispatchFile:%s",
                    new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()),
                    dataSyncParameter.getDataSyncQueueEntity().getId()));

            FormSyncTargetConfigSnapshot formSyncTargetConfig = dataSyncParameter.getFormSyncTargetConfig();

            SyncDataSetDTO syncDataSetDTO = this.jsonProvider.getData(getSyncRealData(data), SyncDataSetDTO.class);
            DataSetDto dataSetDto = syncDataSetDTO.getDataSetDto();

            sb.append("开遍历dataSetDto.getRows():" + dataSetDto.getTableName());
            Collection<FileItemRequestDto> fileItemRequestDtos =
                    dataSetDto.getRows().stream()
                            .flatMap(ii -> ii.getFieldValues().stream())
                            .filter(ii -> ii.getIsFileValue() &&
                                    StringUtils.hasLength((String) ii.getValue()) &&
                                    !"null".equals(ii.getValue()))
                            .flatMap(ii -> {
                                Collection<FileItemRequestDto> tmpItemDtos = new ArrayList<>();
                                sb.append(String.format(";Item请求.name=%s; value=%s: ", ii.getName(), ii.getValue()));
                                JSONArray targetPathJSONArray = this.jsonProvider.getData(String.valueOf(ii.getValue()), JSONArray.class);
                                JSONArray sourceUrlJSONArray = this.jsonProvider.getData(String.valueOf(ii.getOriginalValue()), JSONArray.class);
                                for (int index = 0; index < targetPathJSONArray.size(); index++) {
                                    try {
                                        JSONObject targetPathJSONObject = targetPathJSONArray.getJSONObject(index);
                                        JSONObject originalJSONObject = sourceUrlJSONArray.getJSONObject(index);
                                        String targetPath = getFilePathFromJson(targetPathJSONObject);
                                        if (!StringUtils.hasLength(targetPath)) {
                                            continue;
                                        }

                                        FileItemRequestDto fileItemRequestDto = new FileItemRequestDto();
                                        fileItemRequestDto.setName(ii.getName());
                                        fileItemRequestDto.setTargetPath(targetPath);

                                        String originalUrl = getFilePathFromJson(originalJSONObject);
                                        if (!originalUrl.startsWith("http")) {
                                            String domainUrl = appConfigProperty.getDomainUrl();
                                            if (StringUtils.endsWithIgnoreCase(domainUrl, "/")) {
                                                domainUrl = domainUrl.substring(0, domainUrl.length() - 1);
                                            }
                                            if (originalUrl.startsWith("/")) {
                                                originalUrl = originalUrl.substring(1);
                                            }
                                            originalUrl = String.format("%s/%s", domainUrl, originalUrl);
                                        }

                                        fileItemRequestDto.setSourceUrl(originalUrl);
                                        tmpItemDtos.add(fileItemRequestDto);
                                    } catch (Exception ex) {
                                        sb.append("解析异常：" + ex.toString());
                                        logger.error(String.format("预备同步文件: 异常: %s", ExceptionUtils.getStackMessage(ex)));
                                    }
                                }

                                return tmpItemDtos.stream();
                            }).filter(ii -> ii != null)
                            .collect(Collectors.toList());

            FileSyncRequestDto fileSyncRequestDto = FileSyncRequestDto.create(data.getId(), fileItemRequestDtos);

            sb.append("准备执行Post请求:" + formSyncTargetConfig.getFileUploadUrl());
            HttpResponse response =
                    this.httpRequestProvider.post(
                            formSyncTargetConfig.getFileUploadUrl(),
                            formSyncTargetConfig.getHeaders(),
                            this.jsonProvider.getJson(fileSyncRequestDto));

            sb.append(String.format("执行结果为: status=%s", response.getStatus()));
            String responseBody = response.body();
            if (response.getStatus() >= 200 && response.getStatus() < 300) {
                FileSyncResponse fileSyncResponse = this.jsonProvider.getData(responseBody, FileSyncResponse.class);
                if (fileSyncResponse.getFileItems().stream().anyMatch(ix -> !ix.isSuccess())) {
                    data.changeFileSyncStatus(SyncProcessStatus.Error, responseBody);
                } else {
                    data.changeFileSyncStatus(SyncProcessStatus.Done, responseBody);
                }
            } else {
                data.changeFileSyncStatus(SyncProcessStatus.Error, responseBody);
            }
        } catch (Exception ex) {
            String msg = String.format("%s: DataSyncQueueServiceImpl.dispatchFile【跟踪: %s】同步异常:%s",
                    new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()),
                    sb,
                    ExceptionUtils.getStackMessage(ex));
            logger.error(msg);
            throw new SaasBadException(msg, ex);
        }
         */

        this.executeSyncDataCore(dataSyncParameter);
    }

    @Override
    protected void executeSyncDataCore(DataSyncParameter dataSyncParameter) {
        DataSyncQueueEntity data = dataSyncParameter.getDataSyncQueueEntity();
        StringBuilder sb = new StringBuilder();
        try {
            sb.append(String.format("%s: 正在执行: DataSyncQueueServiceImpl.dispatchData:%s",
                    new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()),
                    dataSyncParameter.getDataSyncQueueEntity().getId()));

            FormSyncTargetConfigSnapshot formSyncTargetConfig = dataSyncParameter.getFormSyncTargetConfig();
            String url = formSyncTargetConfig.getUrl();
            sb.append("；开始获取this.jsonProvider.getData(getSyncRealData(data), DataSetDto.class)");
            SyncDataSetDTO syncDataSetDTO = this.jsonProvider.getData(getSyncRealData(data), SyncDataSetDTO.class);

            DataSetDto dataSetDto = syncDataSetDTO.getDataSetDto();
            DbDataImportRequestDto.DataSet dbDataSet = DbDataImportRequestDto.DataSet
                    .create(data.getId(), dataSyncParameter.getMapKey(),
                            dataSetDto.getRows(), dataSetDto.getDeletedIds());

            sb.append("；开始获取DbDataImportRequestDto.create(Collections.singleton(dbDataSet))");
            DbDataImportRequestDto requestDto =
                    DbDataImportRequestDto.create(data.getData(),
                    Collections.singleton(dbDataSet));

            SyncDataResponse syncDataResponse = SyncDataResponse.create(
                    url,
                    formSyncTargetConfig.getHeaders(),
                    "暂不存储请求参数"
                    //this.jsonProvider.getJson(saveNormalRequestData(requestDto, true))
            );
            sb.append("；开始推送Post请求：  this.httpRequestProvider.post(syncDataResponse.getRequestUrl()");
            HttpResponse result =
                    this.httpRequestProvider.post(url,
                            syncDataResponse.getRequestHeaders(),
                            this.jsonProvider.getJson(requestDto));


            sb.append(String.format("；响应结果状态为：  %s; 结果:%s", result.getStatus(), result.body()));
            syncDataResponse.assign(result.getStatus(), result.body());

            if (result.getStatus() >= 200 && result.getStatus() < 300) {
                data.changeDataSyncStatus(SyncProcessStatus.Done, this.jsonProvider.getJson(syncDataResponse));
            } else {
                data.changeDataSyncStatus(SyncProcessStatus.Error, this.jsonProvider.getJson(syncDataResponse));
            }

            sb.append(String.format("%s:异常: DataSyncQueueServiceImpl.dispatchData:url=%s; 响应状态=%s; 详细= %s",
                    new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()),
                    url,
                    result.getStatus(), data.getResult()));

            this.printBusinessMsg(sb.toString());
        }
        catch (Exception ex) {
            String msg = String.format("%s:异常: DataSyncQueueServiceImpl.dispatchData:【跟踪：%s】%s; 详细: %s",
                    new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()),
                    sb,
                    dataSyncParameter.getDataSyncQueueEntity().getId(),
                    ExceptionUtils.getStackMessage(ex));
            logger.error(msg);

            throw new SaasBadException(msg, ex);
        }
    }

    @Override
    protected boolean isMatchExecuteCondition(boolean isDispatchFile, DataSyncQueueEntity data) {
        return ((data.getStatus() == SyncProcessStatus.Initialize && !isDispatchFile) ||
                (data.getFileSyncStatus() == SyncProcessStatus.Initialize && isDispatchFile)) &&
                super.isMatchExecuteCondition(isDispatchFile, data);
    }
}