package com.mortals.xhx.module.device.service.impl;

import com.alibaba.fastjson.JSON;
import com.mortals.framework.common.Rest;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDCacheServiceImpl;
import com.mortals.xhx.common.code.DeviceMethodEnum;
import com.mortals.xhx.common.code.DeviceStatusEnum;
import com.mortals.xhx.common.code.EnabledEnum;
import com.mortals.xhx.common.pdu.LoginForm;
import com.mortals.xhx.common.pdu.UploadDeviceReq;
import com.mortals.xhx.common.pdu.device.DeviceReq;
import com.mortals.xhx.feign.device.IDeviceFeign;
import com.mortals.xhx.feign.device.IDeviceMessageFeign;
import com.mortals.xhx.module.device.dao.DeviceDao;
import com.mortals.xhx.module.device.model.*;
import com.mortals.xhx.module.device.service.DeviceFileService;
import com.mortals.xhx.module.device.service.DeviceService;
import com.mortals.xhx.module.device.service.DeviceWorkmanService;
import com.mortals.xhx.module.workman.model.WorkmanEntity;
import com.mortals.xhx.module.workman.service.WorkmanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * DeviceService
 * 设备 service实现
 *
 * @author zxfei
 * @date 2023-02-25
 */
@Service("deviceService")
@Slf4j
public class DeviceServiceImpl extends AbstractCRUDCacheServiceImpl<DeviceDao, DeviceEntity, Long> implements DeviceService {

    @Autowired
    private IDeviceFeign deviceFeign;
    @Value("${token.loginName:'admin'}")
    private String loginName;
    @Value("${token.password:'admin'}")
    private String password;

    @Autowired
    private DeviceFileService deviceFileService;
    @Autowired
    private DeviceWorkmanService deviceWorkmanService;
    @Autowired
    private WorkmanService workmanService;

    @Autowired
    private IDeviceMessageFeign messageFeign;

    @Override
    protected String getExtKey(DeviceEntity data) {
        return data.getDeviceCode();
    }


    @Override
    protected void findAfter(DeviceEntity entity, Context context, List<DeviceEntity> list) throws AppException {
        list.forEach(item -> {
            String workmans = deviceWorkmanService.find(new DeviceWorkmanQuery().deviceId(item.getId())).stream().map(i -> i.getWorkmanName()).collect(Collectors.joining(","));
            item.setWorkmans(workmans);
            int count = deviceFileService.count(new DeviceFileQuery().deviceId(item.getId()), context);
            item.setScrollNum(count);
        });
        super.findAfter(entity, context, list);
    }

    @Override
    public Rest<DeviceEntity> deviceInfoByCode(String deviceCode, Context context) {
        DeviceEntity deviceEntity = this.selectOne(new DeviceQuery().deviceCode(deviceCode), context);
        if (ObjectUtils.isEmpty(deviceEntity)) {
            throw new AppException("设备编码未找到相应设备！code:" + deviceCode);
        }
        List<DeviceWorkmanEntity> deviceWorkmanEntityList = deviceWorkmanService.find(new DeviceWorkmanQuery().deviceId(deviceEntity.getId()));
        List<DeviceFileEntity> deviceFileEntityList = deviceFileService.find(new DeviceFileQuery().deviceId(deviceEntity.getId()), context);
        deviceEntity.setDeviceWorkmanEntityList(deviceWorkmanEntityList);
        deviceEntity.setDeviceFileEntityList(deviceFileEntityList);

        return Rest.ok(deviceEntity);

    }

    @Override
    public void active(String deviceCode, Context context) {
        DeviceEntity deviceEntity = this.selectOne(new DeviceQuery().deviceCode(deviceCode));
        if (ObjectUtils.isEmpty(deviceEntity)) throw new AppException("当前设备不存在！");
        if (deviceEntity.getDeviceStatus() > DeviceStatusEnum.未激活.getValue())
            throw new AppException("当前设备已激活！");
        deviceEntity.setDeviceStatus(DeviceStatusEnum.离线.getValue());
        deviceEntity.setEnabled(EnabledEnum.启用.getValue());
        this.getDao().update(deviceEntity);

        String token = getToken();
        DeviceReq deviceReq = new DeviceReq();
        deviceReq.setReceiveMethod(DeviceMethodEnum.ACTIVE.getValue());
        deviceReq.setDeviceCode(deviceCode);
        Rest<String> rest = deviceFeign.deviceCall(deviceReq, token);
        log.info("激活结果：{}", JSON.toJSONString(rest));
    }

    @Override
    public void deviceEnabled(Long id, Integer enabled, Context context) {
        DeviceEntity deviceEntity = this.get(id, context);
        if (ObjectUtils.isEmpty(deviceEntity)) throw new AppException("当前设备不存在！");
        deviceEntity.setEnabled(enabled);
        deviceEntity.setUpdateTime(new Date());
        deviceEntity.setUpdateUserId(getContextUserId(context));
        this.getDao().update(deviceEntity);
        String token = getToken();
        DeviceReq deviceReq = new DeviceReq();
        deviceReq.setReceiveMethod(DeviceMethodEnum.ENABLED.getValue());
        deviceReq.setDeviceCode(deviceEntity.getDeviceCode());
        Rest<String> rest = deviceFeign.deviceCall(deviceReq, token);
        log.info("启用结果：{}", JSON.toJSONString(rest));
    }


    private String getToken() {
        LoginForm loginForm = new LoginForm();
        loginForm.setLoginName(loginName);
        loginForm.setPassword(password);
        Rest<String> rest = deviceFeign.getToken(loginForm);
        String token = rest.getData();
        return token;
    }


    @Override
    protected void saveAfter(DeviceEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getDeviceWorkmanEntityList())) {
            saveDeviceWorkman(entity, context);
        }

        if (!ObjectUtils.isEmpty(entity.getDeviceFileEntityList())) {
            saveDeviceFile(entity, context);
        }
        notifyDevice(entity);
    }

    private void notifyDevice(DeviceEntity entity) {
        UploadDeviceReq uploadDeviceReq = new UploadDeviceReq();
        uploadDeviceReq.setDeviceCodeList(Arrays.asList(entity.getDeviceCode()));
        uploadDeviceReq.setAction("edition");
        log.info("downMsg:{}", JSON.toJSONString(uploadDeviceReq));
        messageFeign.downMsg(uploadDeviceReq);
    }

    @Override
    protected void updateAfter(DeviceEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getDeviceWorkmanEntityList())) {
            //先删除 再添加
            DeviceWorkmanQuery deviceWorkmanQuery = new DeviceWorkmanQuery();
            deviceWorkmanQuery.setDeviceId(entity.getId());
            Long[] deviceIds = deviceWorkmanService.find(deviceWorkmanQuery).stream().map(DeviceWorkmanEntity::getId).toArray(Long[]::new);
            deviceWorkmanService.remove(deviceIds, context);
            saveDeviceWorkman(entity, context);
        }

        if (!ObjectUtils.isEmpty(entity.getDeviceFileEntityList())) {
            DeviceFileQuery deviceFileQuery = new DeviceFileQuery();
            deviceFileQuery.setDeviceId(entity.getId());
            Long[] deviceIds = deviceFileService.find(deviceFileQuery).stream().map(DeviceFileEntity::getId).toArray(Long[]::new);
            deviceFileService.remove(deviceIds, context);
            saveDeviceFile(entity, context);
        }

        notifyDevice(entity);
    }

    private void saveDeviceFile(DeviceEntity entity, Context context) {
        List<DeviceFileEntity> deviceFileEntities = entity.getDeviceFileEntityList().stream().map(item -> {
            DeviceEntity deviceEntity = this.get(entity.getId(), context);
            item.setDeviceId(deviceEntity.getId());
            item.setDeviceCode(deviceEntity.getDeviceCode());
            item.setDeviceName(deviceEntity.getDeviceName());
            item.setCreateUserId(this.getContextUserId(context));
            item.setCreateTime(new Date());
            return item;
        }).collect(Collectors.toList());

        if (!ObjectUtils.isEmpty(deviceFileEntities)) {
            deviceFileService.save(deviceFileEntities);
        }
    }

    private void saveDeviceWorkman(DeviceEntity entity, Context context) {
        List<DeviceWorkmanEntity> deviceWorkmanEntityList = entity.getDeviceWorkmanEntityList().stream().map(item -> {
            DeviceWorkmanEntity deviceWorkmanEntity = new DeviceWorkmanEntity();
            Long workmanId = item.getWorkmanId();
            WorkmanEntity workmanEntity = workmanService.get(workmanId);
            BeanUtils.copyProperties(workmanEntity, deviceWorkmanEntity);
            DeviceEntity deviceEntity = this.get(entity.getId());

            deviceWorkmanEntity.setWorkmanId(workmanEntity.getId());
            deviceWorkmanEntity.setWorkmanName(workmanEntity.getName());
            deviceWorkmanEntity.setDeviceId(entity.getId());
            deviceWorkmanEntity.setDeviceName(deviceEntity.getDeviceName());
            deviceWorkmanEntity.setDeviceCode(deviceEntity.getDeviceCode());
            deviceWorkmanEntity.setCreateUserId(this.getContextUserId(context));
            deviceWorkmanEntity.setCreateTime(new Date());
            return deviceWorkmanEntity;
        }).collect(Collectors.toList());
        if (!ObjectUtils.isEmpty(deviceWorkmanEntityList)) {
            deviceWorkmanService.save(deviceWorkmanEntityList);
        }
    }

    @Override
    protected void removeAfter(Long[] ids, Context context, int result) throws AppException {
        super.removeAfter(ids, context, result);
        DeviceWorkmanQuery deviceWorkmanQuery = new DeviceWorkmanQuery();
        deviceWorkmanQuery.setDeviceIdList(Arrays.asList(ids));
        Long[] deviceIds = deviceWorkmanService.find(deviceWorkmanQuery).stream().map(DeviceWorkmanEntity::getId).toArray(Long[]::new);
        deviceWorkmanService.remove(deviceIds, context);

        DeviceFileQuery deviceFileQuery = new DeviceFileQuery();
        deviceFileQuery.setDeviceIdList((Arrays.asList(ids)));
        deviceIds = deviceFileService.find(deviceFileQuery).stream().map(DeviceFileEntity::getId).toArray(Long[]::new);
        deviceFileService.remove(deviceIds, context);
    }
}