package cn.hanghui.outapi.platform.tenant.service.impl;

import cn.hanghui.outapi.platform.common.entity.rest.RestCode;
import cn.hanghui.outapi.platform.common.entity.rest.RestResult;
import cn.hanghui.outapi.platform.common.utils.ClassUtil;
import cn.hanghui.outapi.platform.common.utils.Preconditions;
import cn.hanghui.outapi.platform.tenant.entity.dto.DeviceDefaultParam;
import cn.hanghui.outapi.platform.tenant.entity.dto.TenantDto;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceDto;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceSearch;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceTemplateDto;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceTemplateLessVo;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceTemplateSearch;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceTemplateVo;
import cn.hanghui.outapi.platform.tenant.entity.dto.hhlocal.HhLocalDeviceVo;
import cn.hanghui.outapi.platform.tenant.entity.enums.ReaderBrandEnum;
import cn.hanghui.outapi.platform.tenant.entity.enums.RelayOpenModelEnum;
import cn.hanghui.outapi.platform.tenant.entity.po.ApplicationType;
import cn.hanghui.outapi.platform.tenant.entity.po.DeviceModel;
import cn.hanghui.outapi.platform.tenant.entity.po.HhLocalDevice;
import cn.hanghui.outapi.platform.tenant.entity.po.HhLocalDeviceTemplate;
import cn.hanghui.outapi.platform.tenant.entity.po.Purchaser;
import cn.hanghui.outapi.platform.tenant.mapper.ApplicationTypeMapper;
import cn.hanghui.outapi.platform.tenant.mapper.DeviceModelMapper;
import cn.hanghui.outapi.platform.tenant.mapper.HhLocalDeviceMapper;
import cn.hanghui.outapi.platform.tenant.mapper.HhLocalDeviceTemplateMapper;
import cn.hanghui.outapi.platform.tenant.mapper.PurchaserMapper;
import cn.hanghui.outapi.platform.tenant.service.HhLocalDeviceService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shisl
 * @package cn.hanghui.outapi.platform.tenant.service.impl
 * @class HhLocalDeviceServiceImpl
 * @date 2024/9/25 上午9:36
 * @description
 */
@Slf4j
@Service
public class HhLocalDeviceServiceImpl implements HhLocalDeviceService {


    @Resource
    private CommonImpl commonImpl;

    @Resource
    private ApplicationTypeMapper applicationTypeMapper;

    @Resource
    private PurchaserMapper purchaserMapper;

    @Resource
    private DeviceModelMapper deviceModelMapper;

    @Resource
    private HhLocalDeviceMapper hhLocalDeviceMapper;

    @Resource
    private HhLocalDeviceTemplateMapper hhLocalDeviceTemplateMapper;


    @Override
    public Boolean templateEdit(HhLocalDeviceTemplateDto dto) {
        checkTemplateDto(dto);
        Long templateId = dto.getDeviceTemplateId();
        if (templateId == null) {
            HhLocalDeviceTemplate template = BeanUtil.copyProperties(dto, HhLocalDeviceTemplate.class);
            hhLocalDeviceTemplateMapper.insert(template);
        } else {
            HhLocalDeviceTemplate base = hhLocalDeviceTemplateMapper.selectById(templateId);
            ClassUtil.throwBusinessException(ObjectUtil.isNull(base), RestCode.FAIL.getCode(), "模版不存在");
            BeanUtil.copyProperties(dto, base);
            hhLocalDeviceTemplateMapper.updateById(base);
        }
        return true;
    }

    private void checkTemplateDto(HhLocalDeviceTemplateDto dto) {
        //应用类型
        if (Preconditions.isNotBlank(dto.getApplicationTypeId())) {
            ApplicationType applicationType = applicationTypeMapper.selectById(dto.getApplicationTypeId());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(applicationType), RestCode.FAIL.getCode(), "应用类型不存在");
            ClassUtil.throwBusinessException(ObjectUtil.isNull(applicationType.getIsDeleted()), RestCode.FAIL.getCode(), "应用类型已删除");
        }
        //设备类型（硬件）
        if (Preconditions.isNotBlank(dto.getDeviceModelHardwareId())) {
            DeviceModel deviceModelHardware = deviceModelMapper.selectById(dto.getDeviceModelHardwareId());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(deviceModelHardware), RestCode.FAIL.getCode(), "设备类型（硬件）不存在");
            ClassUtil.throwBusinessException(ObjectUtil.isNull(deviceModelHardware.getIsDeleted()), RestCode.FAIL.getCode(), "设备类型（硬件）已删除");
        }

    }

    @Override
    public List<HhLocalDeviceTemplateLessVo> templateList() {
        LambdaQueryWrapper<HhLocalDeviceTemplate> wrapper = new LambdaQueryWrapper<>();
        //查询的基础条件
        wrapper.select(HhLocalDeviceTemplate::getId, HhLocalDeviceTemplate::getTemplateName);
        wrapper.eq(HhLocalDeviceTemplate::getIsDeleted, Boolean.FALSE);
        wrapper.orderByDesc(HhLocalDeviceTemplate::getId);
        List<HhLocalDeviceTemplate> templates = hhLocalDeviceTemplateMapper.selectList(wrapper);
        return templates.stream().map(p -> new HhLocalDeviceTemplateLessVo()
                .setDeviceTemplateId(p.getId())
                .setTemplateName(p.getTemplateName())).collect(Collectors.toList());
    }

    @Override
    public IPage<HhLocalDeviceTemplateVo> templatePage(HhLocalDeviceTemplateSearch dto) {
        Page<HhLocalDeviceTemplate> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        LambdaQueryWrapper<HhLocalDeviceTemplate> wrapper = this.getWrapper(dto);
        IPage<HhLocalDeviceTemplate> iPage = hhLocalDeviceTemplateMapper.selectPage(page, wrapper);
        Map<Long, ApplicationType> applicationTypeMap = commonImpl.getApplicationTypeMap(iPage, HhLocalDeviceTemplate::getApplicationTypeId);
        Map<Long, DeviceModel> deviceModelHardwareMap = commonImpl.getDeviceModelMap(iPage, HhLocalDeviceTemplate::getDeviceModelHardwareId);
        return iPage.convert(t -> {
            HhLocalDeviceTemplateVo item = BeanUtil.copyProperties(t, HhLocalDeviceTemplateVo.class);
            item.setDeviceTemplateId(t.getId());
            if (applicationTypeMap.containsKey(t.getApplicationTypeId())) {
                item.setApplicationType(applicationTypeMap.get(t.getApplicationTypeId()).getApplicationType());
            }
            if (deviceModelHardwareMap.containsKey(t.getDeviceModelHardwareId())) {
                item.setDeviceModelHardware(deviceModelHardwareMap.get(t.getDeviceModelHardwareId()).getDeviceModel());
            }
            return item;
        });
    }

    private LambdaQueryWrapper<HhLocalDeviceTemplate> getWrapper(HhLocalDeviceTemplateSearch dto) {
        LambdaQueryWrapper<HhLocalDeviceTemplate> wrapper = new LambdaQueryWrapper<>();
        //查询的传参条件
        wrapper.eq(ObjectUtil.isNotNull(dto.getDeviceTemplateId()), HhLocalDeviceTemplate::getId, dto.getDeviceTemplateId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getApplicationTypeId()), HhLocalDeviceTemplate::getApplicationTypeId, dto.getApplicationTypeId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getDeviceModelHardwareId()), HhLocalDeviceTemplate::getDeviceModelHardwareId, dto.getDeviceModelHardwareId());
        //查询的基础条件
        wrapper.eq(HhLocalDeviceTemplate::getIsDeleted, Boolean.FALSE);
        wrapper.orderByDesc(HhLocalDeviceTemplate::getId);
        return wrapper;
    }

    @Override
    public Boolean templateDelete(Long deviceTemplateId) {
        HhLocalDeviceTemplate template = hhLocalDeviceTemplateMapper.selectById(deviceTemplateId);
        ClassUtil.throwBusinessException(ObjectUtil.isNull(template), RestCode.FAIL.getCode(), "模版不存在");
        ClassUtil.throwBusinessException(ObjectUtil.isNull(template.getIsDeleted()), RestCode.FAIL.getCode(), "模版已删除");
        hhLocalDeviceTemplateMapper.deleteById(deviceTemplateId);
        return Boolean.TRUE;
    }

    @Override
    public HhLocalDeviceTemplateVo templateDetail(Long deviceTemplateId) {
        HhLocalDeviceTemplate deviceTemplate = hhLocalDeviceTemplateMapper.selectById(deviceTemplateId);
        ClassUtil.throwBusinessException(ObjectUtil.isNull(deviceTemplate), "模版不存在");
        ClassUtil.throwBusinessException(deviceTemplate.getIsDeleted(), "模版已删除");
        HhLocalDeviceTemplateVo templateVo = BeanUtil.copyProperties(deviceTemplate, HhLocalDeviceTemplateVo.class);
        templateVo.setDeviceTemplateId(deviceTemplate.getId());
        return templateVo;
    }

    @Override
    public RestResult<Boolean> add(HhLocalDeviceDto dto) {
        if (dto.getSn() == null) {
            return RestResult.error("参数有误");
        }

        if (checkSn(dto)) { //校验设备是否存在
            if (dto.getId() != null) {
                return RestResult.error("数据不存在或已删除");
            }
            return RestResult.error("设备已存在");
        }

        HhLocalDevice device = null;
        if (dto.getId() != null) {
            device = hhLocalDeviceMapper.selectById(dto.getId());
            if (device == null || device.getIsDeleted() == null || device.getIsDeleted()) {
                return RestResult.error("数据不存在或已删除");
            }
        } else {
            device = new HhLocalDevice();
            device.setStatus(Boolean.TRUE);
            device.setCreateTime(new Date());
            device.setVersion(1);
            device.setIsDeleted(Boolean.FALSE);
            device.setFirstAuthTime(new Date());
        }

        //处理参数
        handleParams(device, dto);

        if (dto.getId() != null) {
            hhLocalDeviceMapper.updateById(device);
        } else {
            hhLocalDeviceMapper.insert(device);
        }
        return RestResult.ok(Boolean.TRUE);
    }

    private Boolean checkSn(HhLocalDeviceDto dto) {
        List<HhLocalDevice> devices = hhLocalDeviceMapper.selectList(Wrappers.lambdaQuery(HhLocalDevice.class).eq(HhLocalDevice::getSn, dto.getSn()).eq(HhLocalDevice::getIsDeleted, Boolean.FALSE));
        if (devices != null && devices.size() > 0) {
            if (dto.getId() == null) {
                return Boolean.TRUE;
            } else {
                List<Long> ids = devices.stream().map(HhLocalDevice::getId).collect(Collectors.toList());
                if (!ids.contains(dto.getId())) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }

    private void handleParams(HhLocalDevice device, HhLocalDeviceDto dto) {
        BeanUtil.copyProperties(dto, device);
        //购买方
        if (Preconditions.isNotBlank(dto.getPurchaserId())) {
            Purchaser purchaser = purchaserMapper.selectById(dto.getPurchaserId());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(purchaser), "购买方不存在");
            ClassUtil.throwBusinessException(ObjectUtil.isNull(purchaser.getIsDeleted()), "购买方已删除");
            device.setPurchaserId(purchaser.getId());
        }
        //应用类型
        if (Preconditions.isNotBlank(dto.getApplicationTypeId())) {
            ApplicationType applicationType = applicationTypeMapper.selectById(dto.getApplicationTypeId());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(applicationType), "应用类型不存在");
            ClassUtil.throwBusinessException(ObjectUtil.isNull(applicationType.getIsDeleted()), "购买方已删除");
            device.setApplicationTypeId(applicationType.getId());
        }
        //设备类型（硬件）
        if (Preconditions.isNotBlank(dto.getDeviceModelHardwareId())) {
            DeviceModel deviceModelHardware = deviceModelMapper.selectById(dto.getDeviceModelHardwareId());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(deviceModelHardware), "设备类型（硬件）不存在");
            ClassUtil.throwBusinessException(ObjectUtil.isNull(deviceModelHardware.getIsDeleted()), "设备类型（硬件）已删除");
            device.setDeviceModelHardwareId(deviceModelHardware.getId());
        }
        //继电器开门模式
        if (ObjectUtil.isNotNull(dto.getRelayOpenModel())) {
            RelayOpenModelEnum relayOpenModelEnum = RelayOpenModelEnum.getEnumByCode(dto.getRelayOpenModel());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(relayOpenModelEnum), "继电器开门模式不存在");
        }
        //Ic14443阅读器品牌
        if (ObjectUtil.isNotNull(dto.getIc14443ReaderBrand())) {
            ReaderBrandEnum readerBrandEnum = ReaderBrandEnum.queryEnumByCode(dto.getIc14443ReaderBrand());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(readerBrandEnum), "Ic14443阅读器品牌不存在");
        }
        //Ic15693阅读器品牌
        if (ObjectUtil.isNotNull(dto.getIc15693ReaderBrand())) {
            ReaderBrandEnum readerBrandEnum = ReaderBrandEnum.queryEnumByCode(dto.getIc15693ReaderBrand());
            ClassUtil.throwBusinessException(ObjectUtil.isNull(readerBrandEnum), "Ic15693阅读器品牌不存在");
        }
        device.setUpdateTime(new Date());
        device.setRelayOpenModel(dto.getRelayOpenModel());
        if (RelayOpenModelEnum.OPEN_CLOSE.getCode().equals(dto.getRelayOpenModel())) {
            device.setOpenCloseInterval(dto.getOpenCloseInterval() == null ? DeviceDefaultParam.defaultOpenCloseInterval : dto.getOpenCloseInterval());
            device.setSignalInterval(dto.getSignalInterval() == null ? DeviceDefaultParam.defaultSignalInterval : dto.getSignalInterval());
        } else if (RelayOpenModelEnum.OPEN_GATE_CLOSE.getCode().equals(dto.getRelayOpenModel())) {
            device.setGateTimeOut(dto.getGateTimeOut() == null ? DeviceDefaultParam.defaultGateTimeOut : dto.getGateTimeOut());
        }

    }

    @Override
    public RestResult<IPage<HhLocalDeviceVo>> page(HhLocalDeviceSearch dto) {
        LambdaQueryWrapper<HhLocalDevice> wrapper = this.getDeviceWrapper(dto);
        Page<HhLocalDevice> page = new Page<>(dto.getPageNumber(), dto.getPageSize());
        IPage<HhLocalDevice> iPage = hhLocalDeviceMapper.selectPage(page, wrapper);

        Map<Long, Purchaser> purchaserMap = commonImpl.getPurchaserMap(iPage, HhLocalDevice::getPurchaserId);
        Map<Long, ApplicationType> applicationTypeMap = commonImpl.getApplicationTypeMap(iPage, HhLocalDevice::getApplicationTypeId);
        Map<Long, DeviceModel> deviceModelHardwareMap = commonImpl.getDeviceModelMap(iPage, HhLocalDevice::getDeviceModelHardwareId);

        IPage<HhLocalDeviceVo> convert = iPage.convert(t -> {
            HhLocalDeviceVo item = BeanUtil.copyProperties(t, HhLocalDeviceVo.class);
            if (purchaserMap.containsKey(t.getPurchaserId())) {
                item.setCompanyName(purchaserMap.get(t.getPurchaserId()).getCompanyName());
            }
            if (applicationTypeMap.containsKey(t.getApplicationTypeId())) {
                item.setApplicationType(applicationTypeMap.get(t.getApplicationTypeId()).getApplicationType());
            }
            if (deviceModelHardwareMap.containsKey(t.getDeviceModelHardwareId())) {
                item.setDeviceModelHardware(deviceModelHardwareMap.get(t.getDeviceModelHardwareId()).getDeviceModel());
            }
            return item;
        });
        return RestResult.ok(convert);
    }

    private LambdaQueryWrapper<HhLocalDevice> getDeviceWrapper(HhLocalDeviceSearch dto) {
        LambdaQueryWrapper<HhLocalDevice> wrapper = new LambdaQueryWrapper<>();
        //查询的传参条件
        wrapper.like(StrUtil.isNotBlank(dto.getSn()), HhLocalDevice::getSn, dto.getSn());
        wrapper.eq(ObjectUtil.isNotNull(dto.getPurchaserId()), HhLocalDevice::getPurchaserId, dto.getPurchaserId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getApplicationTypeId()), HhLocalDevice::getApplicationTypeId, dto.getApplicationTypeId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getDeviceModelHardwareId()), HhLocalDevice::getDeviceModelHardwareId, dto.getDeviceModelHardwareId());
        wrapper.eq(ObjectUtil.isNotNull(dto.getStatus()), HhLocalDevice::getStatus, dto.getStatus());
        //基础条件
        wrapper.eq(HhLocalDevice::getIsDeleted, Boolean.FALSE);
        wrapper.orderByDesc(HhLocalDevice::getId);
        return wrapper;
    }

    @Override
    public RestResult<Boolean> del(Long deviceId) {
        HhLocalDevice device = hhLocalDeviceMapper.selectById(deviceId);
        if (device != null && device.getIsDeleted() != null && !device.getIsDeleted()) {
            hhLocalDeviceMapper.deleteById(device);
        }
        return RestResult.ok(Boolean.TRUE);
    }

    @Override
    public RestResult<Boolean> opeDeviceAuth(Long deviceId, Boolean auth) {
        HhLocalDevice device = hhLocalDeviceMapper.selectById(deviceId);
        if (device != null && !device.getIsDeleted()) {
            device.setStatus(auth);
            device.setUpdateTime(new Date());
            hhLocalDeviceMapper.updateById(device);
        }
        return RestResult.ok(Boolean.TRUE);
    }

    @Override
    public RestResult<List<String>> snlist() {
        List<HhLocalDevice> devices = hhLocalDeviceMapper.selectList(Wrappers.lambdaQuery(HhLocalDevice.class).select(HhLocalDevice::getSn).eq(HhLocalDevice::getStatus, Boolean.TRUE).eq(HhLocalDevice::getIsDeleted, Boolean.FALSE));
        List<String> sns = devices.stream().map(HhLocalDevice::getSn).collect(Collectors.toList());
        return RestResult.ok(sns == null || sns.isEmpty() ? Collections.emptyList() : sns);
    }

    @Override
    public RestResult<List<HhLocalDeviceVo>> snConfig(TenantDto dto) {
        List<HhLocalDevice> devices = hhLocalDeviceMapper.selectList(Wrappers.lambdaQuery(HhLocalDevice.class).eq(HhLocalDevice::getStatus, Boolean.TRUE).eq(HhLocalDevice::getSn, dto.getSn()).eq(HhLocalDevice::getIsDeleted, Boolean.FALSE));
        if (devices == null || devices.size() == 0) {
            return RestResult.error("设备商户平台未授权");
        }
        List<HhLocalDeviceVo> vos = BeanUtil.copyToList(devices, HhLocalDeviceVo.class);
        return RestResult.ok(vos != null ? completeOthers(vos) : Collections.emptyList());
    }

    private List<HhLocalDeviceVo> completeOthers(List<HhLocalDeviceVo> vos) {
        Map<Long, Purchaser> purchaserMap = commonImpl.getPurchaserMap(vos, HhLocalDeviceVo::getPurchaserId);
        Map<Long, ApplicationType> applicationTypeMap = commonImpl.getApplicationTypeMap(vos, HhLocalDeviceVo::getApplicationTypeId);
        Map<Long, DeviceModel> deviceModelHardwareMap = commonImpl.getDeviceModelMap(vos, HhLocalDeviceVo::getDeviceModelHardwareId);
        vos.stream().forEach(item -> {
            if (purchaserMap.containsKey(item.getPurchaserId())) {
                item.setCompanyName(purchaserMap.get(item.getPurchaserId()).getCompanyName());
            }
            if (applicationTypeMap.containsKey(item.getApplicationTypeId())) {
                item.setApplicationType(applicationTypeMap.get(item.getApplicationTypeId()).getApplicationType());
            }
            if (deviceModelHardwareMap.containsKey(item.getDeviceModelHardwareId())) {
                item.setDeviceModelHardware(deviceModelHardwareMap.get(item.getDeviceModelHardwareId()).getDeviceModel());
            }
        });
        return vos;
    }

}
