package com.friday.tooldriver.service.rpa.taieoc;

import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.friday.base.common.constants.SystemCode;
import com.friday.base.common.response.DubboResult;
import com.friday.base.database.annotation.ListPage;
import com.friday.mystery.coresecurity.constant.SecurityConstant;
import com.friday.operation.api.keepalive.constant.taieoc.TableName;
import com.friday.operation.api.keepalive.dto.taieoc.*;
import com.friday.operation.api.keepalive.service.taieoc.IOcManage;
import com.friday.tooldriver.constants.TaieOcManageCode;
import com.friday.tooldriver.mapper.taieoc.OcGroupMapper;
import com.friday.tooldriver.mapper.taieoc.OcMapper;
import com.friday.tooldriver.mapper.taieoc.OcTenantMapper;
import com.friday.tooldriver.po.taieoc.OcInfoPo;
import com.friday.tooldriver.po.taieoc.OcTenantPo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;


@Service
@Slf4j
public class OcManageImpl implements IOcManage {

    @Autowired
    private OcTenantMapper ocTenantMapper;

    @Autowired
    private OcMapper ocMapper;

    @Autowired
    private OcGroupMapper groupMapper;


    /**
     * 创建中控租户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DubboResult createOcInfo(OcInfoDto reqDto) {
        // 新增中控信息
        if(StringUtils.isAnyEmpty(reqDto.getOcInfo(), reqDto.getSupplierEn(), reqDto.getSupplierCH(), reqDto.getOcIp()) || ObjectUtils.isEmpty(reqDto.getOcTenantInfoDto())){
            return DubboResult.newFailure(TaieOcManageCode.PARAM_VERIFY_ERROR.getCode(), TaieOcManageCode.PARAM_VERIFY_ERROR.getMessage());
        }
        OcInfoPo ocInfoPo = OcInfoPo.createOcInfoPo(reqDto);
        ocMapper.insert(ocInfoPo);
        // 新增中控租户信息
        List<OcTenantPo> ocTenantPos = reqDto.getOcTenantInfoDto().stream().peek(p->{
            p.setUserTenant(reqDto.getUserTenant());
            p.setOperator(reqDto.getOperator());
        }).map(e -> OcTenantPo.createOcTenantPo(ocInfoPo.getId(), e)).collect(Collectors.toList());
        ocTenantMapper.batchInsert(ocTenantPos);
        return DubboResult.newSuccess(TaieOcManageCode.SUCCESS.getMessage());
    }

    /**
     * 更新中控租户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DubboResult updateOcInfo(OcInfoDto reqDto) {
        try{
            if(ObjectUtils.isEmpty(reqDto.getOcInfoId())){
                return DubboResult.newFailure(TaieOcManageCode.PARAM_VERIFY_ERROR.getCode(), TaieOcManageCode.PARAM_VERIFY_ERROR.getMessage());
            }
            ocMapper.update(OcInfoPo.createOcInfoPo(reqDto));
            ocTenantMapper.deleteByOcInfo(reqDto.getOcInfoId(), reqDto.getOperator());
            if(CollectionUtils.isNotEmpty(reqDto.getOcTenantInfoDto())){
                List<OcTenantPo> ocTenantPos = reqDto.getOcTenantInfoDto().stream().peek(p->p.setOperator(reqDto.getOperator())).map(e -> OcTenantPo.createOcTenantPo(reqDto.getOcInfoId(), e)).collect(Collectors.toList());
                ocTenantMapper.batchInsert(ocTenantPos);
            }
            return DubboResult.newSuccess(TaieOcManageCode.SUCCESS.getMessage());
        }catch (Exception e){
            log.error(TaieOcManageCode.OC_TENANT_INFO_UPDATE_ERROR.toString(), e);
            return DubboResult.newFailure(TaieOcManageCode.OC_TENANT_INFO_UPDATE_ERROR.getCode(), TaieOcManageCode.OC_TENANT_INFO_UPDATE_ERROR.getMessage());
        }
    }




    @Override
    @ListPage(tableName = TableName.OC_INFO_PAGE_NAME)
    public DubboResult<ArrayList<OcPageDto>> queryOcPage(OcTenantFilterDto filterDto) {
        DubboResult<ArrayList<OcPageDto>> result;
        List<OcInfoPo> ocInfoPos = ocMapper.selectOcInfo(filterDto);
        ArrayList<OcPageDto> pageDtoList = ocInfoPos.stream().map(e -> {
            OcPageDto pageDto = OcInfoPo.createPage(e);
            List<OcTenantInfoDto> ocTenantPageDto = ocTenantMapper.selectOcTenant(OcTenantFilterDto.ocTenantFilterBuilder().ocInfoId(e.getId()).build())
                    .stream().map(f -> {
                        OcTenantInfoDto infoDto = OcTenantPo.createInfo(f);
                        infoDto.setRelateGroupNum(groupMapper.selectGroupCountByTenant(f.getId()));
                        return infoDto;
                    }).collect(Collectors.toList());
            pageDto.setOcTenantInfoDto(ocTenantPageDto);
            pageDto.setTenantCount(ocTenantPageDto.size());
            return pageDto;
        }).filter(r -> OcTenantExist(filterDto.getOcTenant(), r.getOcTenantInfoDto())).collect(Collectors.toCollection(ArrayList::new));
        result = DubboResult.newSuccess(pageDtoList);
        result.setMessage(TaieOcManageCode.SUCCESS.getMessage());
        return result;
    }

    private boolean OcTenantExist(String tenant, List<OcTenantInfoDto> infoDto){
        List<String> tenantNames = infoDto.stream().map(OcTenantInfoDto::getOcTenant).collect(Collectors.toList());
        return (StringUtils.isEmpty(tenant) || tenantNames.contains(tenant));
    }

    @Override
    public DubboResult<OcInfoDto> queryOcDetail(Long ocInfoId) {
        OcInfoDto infoDto = OcInfoPo.createInfo(ocMapper.selectByPrimaryKey(ocInfoId));
        infoDto.setTenantCount(ocTenantMapper.selectTenantCountByOc(ocInfoId));
        return DubboResult.newSuccess(infoDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DubboResult deleteOcInfo(Long ocId, String operator) {
        ocMapper.deleteByPrimaryKey(ocId, operator);
        ocTenantMapper.deleteByOcInfo(ocId, operator);
        return DubboResult.newSuccess();
    }

    @Override
    public DubboResult<ArrayList<OcInfoDictDto>> queryOcDict(String supplierEn, String tenant) {
        DubboResult<ArrayList<OcInfoDictDto>> result;
        List<OcInfoPo> ocInfo = ocMapper.selectOcInfo(OcTenantFilterDto.ocTenantFilterBuilder()
                .supplierEn(supplierEn)
                .tenant(tenant)
                .build());
        ArrayList<OcInfoDictDto> ocInfoDictDtos = ocInfo.stream().map(e -> OcInfoDictDto.builder()
                .ocInfo(e.getOcInfo())
                .ocTenantDictDtoList(ocTenantMapper.selectOcTenant(OcTenantFilterDto.ocTenantFilterBuilder()
                        .ocInfoId(e.getId())
                        .build()).stream().map(OcTenantPo::createDict).collect(Collectors.toList()))
                .build()
        ).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(OcInfoDictDto::getOcInfo))), ArrayList::new));
        result = DubboResult.newSuccess(ocInfoDictDtos);
        result.setMessage(SystemCode.SUCCESS.getMessage());
        return result;
    }

    @Override
    public DubboResult<ArrayList<String>> queryOcDropList(String supplier, String tenant) {
        List<OcInfoPo> ocInfo = ocMapper.selectOcInfo(OcTenantFilterDto.ocTenantFilterBuilder()
                .supplierEn(StringUtils.isNotEmpty(supplier) ? supplier : null)
                //公用 官网的厂商中控信息
                .tenant(SecurityConstant.portalDefaultTenant)
                .build());
        ArrayList<String> result = ocInfo.stream().map(OcInfoPo::getOcInfo).distinct().collect(Collectors.toCollection(ArrayList::new));
        return DubboResult.newSuccess(result);
    }

    @Override
    public DubboResult<ArrayList<OcInfoDto>> queryOcInfo(OcTenantFilterDto dto) {
        try{
            DubboResult<ArrayList<OcInfoDto>> result;
            List<OcInfoPo> ocInfo = ocMapper.selectOcInfo(dto);
            if(CollectionUtils.isEmpty(ocInfo)){
                return DubboResult.newFailure(TaieOcManageCode.OC_NOT_EXIST.getCode(), TaieOcManageCode.OC_NOT_EXIST.getMessage());
            }
            ArrayList<OcInfoDto> infoDtos = ocInfo.stream().map(OcInfoPo::createInfo).collect(Collectors.toCollection(ArrayList::new));
            result = DubboResult.newSuccess(infoDtos);
            result.setMessage(TaieOcManageCode.SUCCESS.getMessage());
            return result;
        }catch (Exception e){
            return DubboResult.newFailure(TaieOcManageCode.INTERNAL_ERROR.getCode(),TaieOcManageCode.INTERNAL_ERROR.getMessage());
        }

    }

}
