package jnpf.certificate.consumer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.seata.spring.annotation.GlobalTransactional;
import jnpf.base.ActionResult;
import jnpf.certificate.service.CertificateManageApiService;
import jnpf.config.ConfigValueUtil;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.message.enums.permission.v2.OperationTypeMessageEnums;
import jnpf.message.enums.permission.v2.OrganizeCategoryMessageEnums;
import jnpf.message.model.permission.v2.OrganizeUpdateMessageDTO;
import jnpf.model.certificate.vo.CertificateOrganizeBusinessLicenseVO;
import jnpf.permission.V2OrganizeApi;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.util.DateUtil;
import jnpf.util.ServiceException;
import jnpf.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.integration.IntegrationMessageHeaderAccessor;
import org.springframework.integration.acks.AcknowledgmentCallback;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 证照关联处理组织架构消费者。
 */
@Slf4j
@Component
@EnableBinding(CertificateConsumerSource.class)
public class CertificateConsumer {

    private static final String IDEMPOTENT_KEY_PREFIX = "certificate:consume";
    private static final String IDEMPOTENT_VALUE = "1";
    private static final long IDEMPOTENT_EXPIRE_DAYS = 1L;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    @Lazy
    private ConfigValueUtil configValueUtil;

    @Resource
    private CertificateManageApiService certificateManageApiService;

    /**
     * 监听组织架构变更消息并同步证照数据。
     */
    @StreamListener(target = CertificateConsumerSource.INPUT, condition = "headers['ROCKET_TAGS'] == 'TAG_ORGANIZE'")
    public void receiveStoreFranchiseeChange(Message<String> message) {
        AcknowledgmentCallback acknowledgmentCallback = null;
        String idempotentKey = null;
        try {
            MessageHeaders headers = message.getHeaders();
            acknowledgmentCallback = headers.get(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, AcknowledgmentCallback.class);
            if (acknowledgmentCallback != null) {
                acknowledgmentCallback.noAutoAck();
            }

            String payload = message.getPayload();
            if (StrUtil.isBlank(payload)) {
                acknowledgeAccept(acknowledgmentCallback);
                return;
            }

            String rocketKeys = headers.get("ROCKET_KEYS", String.class);
            if (StrUtil.isBlank(rocketKeys)) {
                log.warn("证照组织变更消息缺少ROCKET_KEYS，跳过处理。payload={}", payload);
                acknowledgeAccept(acknowledgmentCallback);
                return;
            }

            idempotentKey = IDEMPOTENT_KEY_PREFIX + ":" + rocketKeys;
            Boolean firstConsume = stringRedisTemplate.opsForValue()
                    .setIfAbsent(idempotentKey, IDEMPOTENT_VALUE, IDEMPOTENT_EXPIRE_DAYS, TimeUnit.DAYS);
            if (!Boolean.TRUE.equals(firstConsume)) {
                acknowledgeAccept(acknowledgmentCallback);
                return;
            }

            List<OrganizeUpdateMessageDTO> messageList;
            try {
                messageList = JSONUtil.toList(JSONUtil.parseArray(payload), OrganizeUpdateMessageDTO.class);
            } catch (Exception e) {
                log.error("证照组织变更消息解析失败，payload={}", payload, e);
                throw e;
            }
            if (CollUtil.isEmpty(messageList)) {
                acknowledgeAccept(acknowledgmentCallback);
                return;
            }

            for (OrganizeUpdateMessageDTO item : messageList) {
                processOrganizeChange(item);
            }
            acknowledgeAccept(acknowledgmentCallback);
        } catch (Exception e) {
            //todo 异常处理
            String msg = e.getMessage();
            if(msg.equals("组织不存在，无法同步营业执照") || msg.equals("切换租户失败")){
                acknowledgeRequeue(acknowledgmentCallback);
            }
            if (StrUtil.isNotBlank(idempotentKey)) {
                stringRedisTemplate.delete(idempotentKey);
            }
            log.error("处理证照组织变更消息失败，message={}", JSONUtil.toJsonStr(message), e);
            throw e;
        } finally {
//            TenantDataSourceUtil.clearSwitchDataSource();
        }
    }

    /**
     * 分发处理组织变更。
     */
    private void processOrganizeChange(OrganizeUpdateMessageDTO item) {
        if (item == null) {
            return;
        }
        OperationTypeMessageEnums operationType = item.getOperationTypeEnum();
        OrganizeCategoryMessageEnums category = item.getOrganizeCategoryEnum();
        if (operationType == null || category == null) {
            return;
        }
        if (!OrganizeCategoryMessageEnums.STORE.equals(category)
                && !OrganizeCategoryMessageEnums.COMPANY.equals(category)) {
            return;
        }

        String tenantId = StrUtil.trim(item.getTenantId());
        if (StrUtil.isBlank(tenantId)) {
            return;
        }
        switchTenant(tenantId);

        if (OperationTypeMessageEnums.ADD.equals(operationType)) {
            handleAdd(item);
            return;
        }
        if (OperationTypeMessageEnums.UPDATE.equals(operationType)) {
            handleUpdate(item);
            return;
        }
        if (OperationTypeMessageEnums.DELETE.equals(operationType)) {
            handleDelete(item);
        }
    }

    /**
     * 处理新增。
     * 门店：新增营业执照+食品经营许可证两条缺失证照。
     * 公司：同步新增营业执照。
     */
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    protected void handleAdd(OrganizeUpdateMessageDTO item) {
        if (OrganizeCategoryMessageEnums.STORE.equals(item.getOrganizeCategoryEnum())) {
            handleStoreAdd(item.getId());
            return;
        }
        if (OrganizeCategoryMessageEnums.COMPANY.equals(item.getOrganizeCategoryEnum())) {
            CertificateOrganizeBusinessLicenseVO req = buildCompanyLicense(item.getId(), item.getJsonEntity());
            certificateManageApiService.saveBusinessLicense(req);
        }
    }

    /**
     * 处理编辑。
     * 门店：无需处理。
     * 公司：同步更新营业执照。
     */
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    protected void handleUpdate(OrganizeUpdateMessageDTO item) {
        if (OrganizeCategoryMessageEnums.STORE.equals(item.getOrganizeCategoryEnum())) {
            return;
        }
        if (OrganizeCategoryMessageEnums.COMPANY.equals(item.getOrganizeCategoryEnum())) {
            CertificateOrganizeBusinessLicenseVO req = buildCompanyLicense(item.getId(), item.getJsonEntity());
            certificateManageApiService.saveBusinessLicense(req);
        }
    }

    /**
     * 处理删除。
     * 按组织ID删除该组织主体下全部证照。
     */
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    protected void handleDelete(OrganizeUpdateMessageDTO item) {
        String organizeId = StrUtil.trim(item.getId());
        if (StrUtil.isBlank(organizeId)) {
            return;
        }
        certificateManageApiService.deleteBusinessLicense(organizeId, null);
    }

    /**
     * 门店新增时补齐默认缺失证照。
     */
    private void handleStoreAdd(String storeId) {
        String targetStoreId = StrUtil.trim(storeId);
        if (StrUtil.isBlank(targetStoreId)) {
            return;
        }
        certificateManageApiService.initStoreDefaultCertificates(targetStoreId);
    }

    /**
     * 构建公司营业执照同步参数，逻辑与 V2OrganizeServiceImpl 的公司新增/编辑保持一致。
     */
    private CertificateOrganizeBusinessLicenseVO buildCompanyLicense(String organizeId, String jsonEntity) {
        String targetOrganizeId = StrUtil.trim(organizeId);
        ServiceException.isTrue(StrUtil.isNotBlank(targetOrganizeId), "组织ID不能为空");

        CertificateOrganizeBusinessLicenseVO licenseVO = new CertificateOrganizeBusinessLicenseVO();
        licenseVO.setOrganizeId(targetOrganizeId);

        JSONObject jsonObject = parseJSONEntity(jsonEntity);

        licenseVO.setCertificateImage(jsonObject.getStr("licenseImg"));
        licenseVO.setCompanyName(jsonObject.getStr("fullName"));

        JSONObject propertyJson = parsePropertyJson(jsonObject);

        //前端如果没值传的是""空串，直接去获取JsonArry会报错，这里判断一下
        String businessTermText = propertyJson.getStr("businessTerm");
        if(StringUtil.isNotBlank(businessTermText)){
            licenseVO.setBusinessTerm(businessTermText);

            JSONArray businessTerm = propertyJson.getJSONArray("businessTerm");
            if(businessTerm.size() == 2){
                licenseVO.setIssueDate(businessTerm.getStr(0));
                licenseVO.setExpireDate(businessTerm.getStr(1));
            }
        }

        String managerName = propertyJson.getStr("managerName");
        if (managerName != null) {
            licenseVO.setLegalRepresentative(managerName);
        }
        String address = propertyJson.getStr("address");
        if (address!= null) {
            licenseVO.setCompanyAddress(address);
        }
        Integer businessTermLong = propertyJson.getInt("businessTermLong");
        if (businessTermLong!= null) {
            licenseVO.setIsLongTerm(businessTermLong);
        }

        Date establishDate = propertyJson.getDate("foundedTime");
        if(Objects.nonNull(establishDate)){
            licenseVO.setEstablishDate(DateUtil.daFormat(establishDate));
        }
        return licenseVO;
    }

    private JSONObject parseJSONEntity(String jsonEntity) {
        if (StrUtil.isBlank(jsonEntity) || !JSONUtil.isTypeJSONObject(jsonEntity)) {
            return new JSONObject();
        }
        return JSONUtil.parseObj(jsonEntity);
    }
    /**
     * 从组织消息 jsonEntity 中解析 propertyJson。
     */
    private JSONObject parsePropertyJson(JSONObject jsonEntity) {
        if (Objects.isNull(jsonEntity)) {
            return new JSONObject();
        }
        JSONObject propertyObj = jsonEntity.getJSONObject("propertyJson");
        if(Objects.isNull(propertyObj)){
            return new JSONObject();
        }
        return propertyObj;
    }

    private Integer toInteger(Object value) {
        if (value == null) {
            return null;
        }
        try {
            return Integer.parseInt(String.valueOf(value));
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 切换租户数据源。
     */
    private void switchTenant(String tenantId) {
        if (!configValueUtil.isMultiTenancy()) {
            log.info("证照组织变更消息：配置为非多租户，跳过切换租户。tenantId={}", tenantId);
            return;
        }
        try {
            TenantDataSourceUtil.switchTenant(tenantId);
        } catch (Exception e) {
            throw new RuntimeException("切换租户失败tenantId:"+tenantId, e);
        }
    }

    /**
     * 手动确认消费成功。
     */
    private void acknowledgeAccept(AcknowledgmentCallback acknowledgmentCallback) {
        if (acknowledgmentCallback == null || acknowledgmentCallback.isAcknowledged()) {
            return;
        }
        acknowledgmentCallback.acknowledge(AcknowledgmentCallback.Status.ACCEPT);
    }

    /**
     * 手动回执重试。
     */
    private void acknowledgeRequeue(AcknowledgmentCallback acknowledgmentCallback) {
        if (acknowledgmentCallback == null || acknowledgmentCallback.isAcknowledged()) {
            return;
        }
        acknowledgmentCallback.acknowledge(AcknowledgmentCallback.Status.REQUEUE);
    }
}
