package com.fuyuanshen.equipment.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.core.exception.BadRequestException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.customer.domain.Customer;
import com.fuyuanshen.customer.mapper.CustomerMapper;
import com.fuyuanshen.equipment.constants.DeviceConstants;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceAssignments;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.DeviceTypeGrants;
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
import com.fuyuanshen.equipment.domain.form.DeviceForm;
import com.fuyuanshen.equipment.domain.query.DeviceAssignmentQuery;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.domain.query.DeviceTypeQueryCriteria;
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
import com.fuyuanshen.equipment.domain.vo.CustomerVo;
import com.fuyuanshen.equipment.enums.BindingStatusEnum;
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
import com.fuyuanshen.equipment.enums.DeviceActiveStatusEnum;
import com.fuyuanshen.equipment.mapper.DeviceAssignmentsMapper;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeGrantsMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.equipment.service.DeviceAssignmentsService;
import com.fuyuanshen.equipment.service.DeviceService;
import com.fuyuanshen.equipment.service.DeviceTypeGrantsService;
import com.fuyuanshen.system.domain.vo.SysOssVo;
import com.fuyuanshen.system.service.ISysOssService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Description:
 * @Author: WY
 * @Date: 2025/5/16
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

    public static final String USER_ID_SEPARATOR = ":";

    @Value("${file.device.pic}")
    private String filePath;
    @Value("${file.device.ip}")
    private String ip;

    private final DeviceMapper deviceMapper;
    private final DeviceTypeMapper deviceTypeMapper;
    private final CustomerMapper customerMapper;

    private final ISysOssService ossService;

    private final DeviceAssignmentsService deviceAssignmentsService;
    private final DeviceAssignmentsMapper deviceAssignmentsMapper;

    private final DeviceTypeGrantsService deviceTypeGrantsService;
    private final DeviceTypeGrantsMapper deviceTypeGrantsMapper;


    /**
     * 分页查询设备
     *
     * @param criteria 条件
     * @param page     分页参数
     * @return
     * @throws IOException
     */
    @Override
    public TableDataInfo<Device> queryAll(DeviceQueryCriteria criteria, Page<Device> page) throws IOException {

        criteria.setCurrentOwnerId(LoginHelper.getUserId());
        if (criteria.getDeviceType() != null) {
            DeviceTypeGrants deviceTypeGrant = deviceTypeGrantsMapper.selectById(criteria.getDeviceType());
            if (deviceTypeGrant != null) {
                criteria.setDeviceType(deviceTypeGrant.getDeviceTypeId());
            }
        }
        IPage<Device> devices = deviceMapper.findAll(criteria, page);

        List<Device> records = devices.getRecords();
        for (Device record : records) {
            if (record.getDevicePic() == null) {
                record.setDevicePic("");
            }
        }

        return new TableDataInfo<Device>(records, devices.getTotal());
    }


    @Override
    public List<Device> queryAll(DeviceQueryCriteria criteria) {
        criteria.setCurrentOwnerId(LoginHelper.getUserId());
        return deviceMapper.findAll(criteria);
    }


    /**
     * 查询所有设备
     *
     * @param criteria 筛选条件
     * @return
     */
    @Override
    public List<Device> queryAllDevices(DeviceQueryCriteria criteria) {
        return deviceMapper.findAllDevices(criteria);
    }


    /**
     * 新增设备
     *
     * @param deviceForm
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDevice(DeviceForm deviceForm) throws Exception {

        if (deviceForm.getDeviceMac() != null && deviceForm.getBluetoothName() == null) {
            throw new BadRequestException("请填写蓝牙名称！！！");
        }

        Device device1 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_mac", deviceForm.getDeviceMac()));
        if (device1 != null) {
            throw new BadRequestException("设备MAC已存在！！！");
        }
        Device device2 = deviceMapper.selectOne(new QueryWrapper<Device>().eq("device_imei", deviceForm.getDeviceImei()));
        if (device2 != null) {
            throw new BadRequestException("设备IMEI已存在！！！");
        }

        DeviceTypeQueryCriteria queryCriteria = new DeviceTypeQueryCriteria();
        queryCriteria.setDeviceTypeId(deviceForm.getDeviceType());
        queryCriteria.setCustomerId(LoginHelper.getUserId());
        DeviceTypeGrants typeGrants = deviceTypeGrantsMapper.selectById(queryCriteria.getDeviceTypeId());
        if (typeGrants == null) {
            throw new Exception("设备类型不存在!!!");
        }
        DeviceType deviceTypes = deviceTypeMapper.selectById(typeGrants.getDeviceTypeId());
        if (deviceTypes == null) {
            throw new Exception("设备类型不存在!!!");
        }

        // 保存图片并获取URL
        if (deviceForm.getFile() != null) {
            SysOssVo upload = ossService.upload(deviceForm.getFile());
            // 设置图片路径
            deviceForm.setDevicePic(upload.getUrl());
        }

        // 转换对象并插入数据库
        Device device = new Device();

        BeanUtil.copyProperties(deviceForm, device, true);
        device.setDeviceNo(createDeviceNo());
        LoginUser loginUser = LoginHelper.getLoginUser();
        device.setCurrentOwnerId(loginUser.getUserId());
        device.setOriginalOwnerId(loginUser.getUserId());
        device.setCreateByName(loginUser.getNickname());
        device.setTypeName(deviceTypes.getTypeName());
        device.setDeviceType(deviceTypes.getId());
        if (device.getDeviceImei() != null) {
            device.setPubTopic("A/" + device.getDeviceImei());
            device.setSubTopic("B/" + device.getDeviceImei());
        }
        // 0 未绑定
        device.setBindingStatus(0);
        deviceMapper.insert(device);

        // 新增设备类型记录
        DeviceAssignments assignments = new DeviceAssignments();
        assignments.setDeviceId(device.getId());
        assignments.setAssignedAt(LocalDateTime.now());
        // 分配者
        assignments.setAssignerId(loginUser.getUserId());
        assignments.setAssignerName(loginUser.getUsername());
        // 接收者
        assignments.setAssigneeId(loginUser.getUserId());
        assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
        String lever = USER_ID_SEPARATOR + loginUser.getUserId();
        assignments.setLever(lever);
        deviceAssignmentsService.save(assignments);

    }

    private String createDeviceNo() {
        String uuidStr = UUID.fastUUID().toString(); // 获取带 - 的标准格式字符串
        return uuidStr.replaceAll("-", "");
    }


    /**
     * 更新设备信息
     *
     * @param deviceForm /
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(DeviceForm deviceForm) throws Exception {
        DeviceAssignments deviceAssignments = deviceAssignmentsMapper.selectById(deviceForm.getId());

        DeviceTypeQueryCriteria deviceTypeQueryCriteria = new DeviceTypeQueryCriteria();
        deviceTypeQueryCriteria.setDeviceTypeId(deviceAssignments.getDeviceId());
        deviceTypeQueryCriteria.setCustomerId(LoginHelper.getUserId());
        List<DeviceType> deviceTypes = deviceTypeMapper.findAll(deviceTypeQueryCriteria);
        if (deviceTypes.isEmpty()) {
            throw new Exception("设备类型不存在!!!");
        }
        Device device = deviceMapper.selectById(deviceAssignments.getDeviceId());
        if (device == null) {
            throw new Exception("设备不存在!!!");
        }
        // 设备类型
        Long deviceType = device.getDeviceType();

        // 处理上传的图片
        if (deviceForm.getFile() != null) {
            SysOssVo upload = ossService.upload(deviceForm.getFile());
            // 设置图片路径
            deviceForm.setDevicePic(upload.getUrl());
        }

        // 更新字段
        BeanUtil.copyProperties(deviceForm, device, true);
        device.setId(deviceAssignments.getDeviceId());
        device.setDeviceType(deviceType);
        device.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        deviceMapper.updateById(device);
    }


    /**
     * 保存设备图片并返回访问路径
     *
     * @param file      MultipartFile
     * @param deviceMac 设备MAC用于生成唯一文件名
     * @return 文件存储路径 URL 形式
     */
    private String saveDeviceImage(MultipartFile file, String deviceMac) throws IOException {
        if (file == null || file.isEmpty()) {
            return null;
        }

        String originalFileName = file.getOriginalFilename();
        String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        String newFileName = "PS_" + deviceMac + "." + fileExtension;

        File newFile = new File(filePath + DeviceConstants.FILE_ACCESS_ISOLATION + File.separator + newFileName);

        if (!newFile.getParentFile().exists()) {
            newFile.getParentFile().mkdirs();
        }

        log.info("图片保存路径: {}", newFile.getAbsolutePath());
        file.transferTo(newFile);

        return ip + DeviceConstants.FILE_ACCESS_PREFIX + "/" + DeviceConstants.FILE_ACCESS_ISOLATION + "/" + newFileName;
    }


    /**
     * 删除设备
     *
     * @param ids /
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        List<Long> invalidIds = new ArrayList<>();

        for (Long id : ids) {
            DeviceAssignments deviceAssignment = deviceAssignmentsMapper.selectById(id);
            Device device = deviceMapper.selectById(deviceAssignment.getDeviceId());

            if (StringUtils.isNotEmpty(deviceAssignment.getAssigneeName())) {
                throw new BadRequestException(device.getDeviceName() + ":设备已分配，请先解绑设备！！！");
            }

            if (device.getBindingStatus() != null && device.getBindingStatus().equals(1)) {
                throw new BadRequestException(device.getDeviceName() + ":设备已绑定，请先解绑设备！！！");
            }

            // 接收者
            if (Objects.equals(deviceAssignment.getAssigneeId(), device.getOriginalOwnerId())) {
                invalidIds.add(deviceAssignment.getDeviceId());
            }

            // 删除设备:分配记录
            deviceAssignmentsMapper.delete(new LambdaQueryWrapper<DeviceAssignments>()
                    .eq(DeviceAssignments::getDeviceId, deviceAssignment.getDeviceId())
                    .eq(DeviceAssignments::getAssigneeId, deviceAssignment.getAssigneeId()));

        }

        deviceAssignmentsMapper.deleteByIds(ids);
        deviceMapper.deleteByIds(invalidIds);
    }


    /**
     * 分配客户
     *
     * @param customerVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void assignCustomer(CustomerVo customerVo) {

        if (customerVo.getDeviceIds().isEmpty() || customerVo.getCustomerId() == null) {
            throw new RuntimeException("请选择设备或客户");
        }

        // 获取当前登录用户
        LoginUser loginUser = LoginHelper.getLoginUser();
        // 获取分配用户信息
        Customer assignUser = customerMapper.selectById(customerVo.getCustomerId());
        // 获取分配设备信息
        List<DeviceAssignments> assignments = deviceAssignmentsMapper.selectByIds(customerVo.getDeviceIds());

        // 批量更新设备状态
        List<DeviceTypeGrants> deviceTypeGrants = new ArrayList<>();
        for (DeviceAssignments assignment : assignments) {

            if (assignment.getToCustomerId() != null && assignment.getToCustomerId() != 0L) {
                log.info("设备已经分配客户！！！");
                throw new RuntimeException("设备已经分配客户！！！");
            }

            Device device = deviceMapper.selectById(assignment.getDeviceId());

            // 如果设备已分配给需要分配的客户，则跳过
            DeviceAssignmentQuery dq = DeviceAssignmentQuery.builder().deviceId(device.getId()).assigneeId(customerVo.getCustomerId())
                    .active(DeviceActiveStatusEnum.ACTIVE.getCode()).lever(assignment.getLever() + USER_ID_SEPARATOR).build();
            // 查询分配
            List<DeviceAssignments> assignmentsList = deviceAssignmentsMapper.deviceAssignmentsMapper(dq);
            if (CollectionUtil.isNotEmpty(assignmentsList)) {
                log.info("设备 {} 已分配给客户 {}", device.getDeviceName(), device.getCustomerName());
                continue;
            }

            // 更改分配客户
            assignment.setAssigneeName(assignUser.getNickName());
            assignment.setToCustomerId(customerVo.getCustomerId());
            deviceAssignmentsMapper.updateById(assignment);

            // 设备失效
            // 获取用户的设备记录
            DeviceAssignmentQuery dq1 = DeviceAssignmentQuery.builder().deviceId(device.getId()).assignerId(loginUser.getUserId())
                    .active(DeviceActiveStatusEnum.ACTIVE.getCode()).lever(assignment.getLever() + USER_ID_SEPARATOR).build();
            List<DeviceAssignments> ag = deviceAssignmentsMapper.deviceAssignmentsMapper(dq1);
            if (CollectionUtil.isNotEmpty(ag)) {
                for (DeviceAssignments d : ag) {
                    d.setActive(DeviceActiveStatusEnum.INACTIVE.getCode());
                    deviceAssignmentsMapper.updateById(d);
                }
            }

            // 新增设备类型记录
            DeviceAssignments dam = new DeviceAssignments();
            dam.setDeviceId(device.getId());
            dam.setAssignedAt(LocalDateTime.now());
            // 分配者
            dam.setAssignerId(loginUser.getUserId());
            dam.setAssignerName(loginUser.getUsername());
            // 接收者
            dam.setAssigneeId(assignUser.getCustomerId());
            // assignments.setAssigneeName(assignUser.getUsername());
            dam.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
            String lever = assignment.getLever() + USER_ID_SEPARATOR + assignUser.getCustomerId();
            dam.setLever(lever);
            deviceAssignmentsService.save(dam);

            // 判断设备类型是否存在
            DeviceTypeGrants dtg = deviceTypeGrantsMapper.selectOne(new LambdaQueryWrapper<DeviceTypeGrants>()
                    .eq(DeviceTypeGrants::getDeviceTypeId, device.getDeviceType())
                    .eq(DeviceTypeGrants::getCustomerId, assignUser.getCustomerId()));
            if (dtg != null) {
                continue;
            }
            // 创建并保存设备类型授权记录
            DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
            deviceTypeGrant.setGrantedAt(new Date());
            deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
            // 关联分配记录
            deviceTypeGrant.setAssignmentId(dam.getId());
            // 被授权的客户
            deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
            // 授权方客户
            deviceTypeGrant.setGrantorCustomerId(loginUser.getUserId());
            deviceTypeGrants.add(deviceTypeGrant);
        }

        deviceTypeGrantsService.saveBatch(deviceTypeGrants);

    }

    /**
     * 创建并保存设备类型授权记录
     *
     * @param device           当前设备对象
     * @param currentUser      当前登录用户
     * @param customerVo       客户信息
     * @param deviceTypeGrants 授权记录集合
     */
    private void createAndSaveDeviceTypeGrants(Device device, LoginUser currentUser, CustomerVo customerVo, List<DeviceTypeGrants> deviceTypeGrants) {
        // Long generatedId = NanoId.generate(NanoIdLengthEnum.HIGH_CONCURRENCY.getLength());
        DeviceTypeGrants deviceTypeGrant = new DeviceTypeGrants();
        deviceTypeGrant.setGrantedAt(new Date());
        deviceTypeGrant.setDeviceTypeId(device.getDeviceType());
        // deviceTypeGrant.setAssignmentId(generatedId);
        deviceTypeGrant.setCustomerId(customerVo.getCustomerId());
        deviceTypeGrant.setGrantorCustomerId(currentUser.getUserId());
        deviceTypeGrants.add(deviceTypeGrant);
    }


    /**
     * 撤回设备
     *
     * @param ids
     */
    @Override
    @Transactional
    public void withdrawDevice(List<Long> ids) {

        for (Long id : ids) {
            DeviceAssignments assignment = deviceAssignmentsMapper.selectById(id);
            Device device = deviceMapper.selectById(assignment.getDeviceId());
            // 接收者
            assignment.setAssigneeName("");
            assignment.setToCustomerId(0L);
            deviceAssignmentsMapper.updateById(assignment);

            // 获取所有已分配的设备
            DeviceAssignmentQuery dq = DeviceAssignmentQuery.builder().deviceId(device.getId())
                    .active(DeviceActiveStatusEnum.ACTIVE.getCode()).lever(assignment.getLever() + USER_ID_SEPARATOR).build();
            // 查询分配
            List<DeviceAssignments> assignmentsList = deviceAssignmentsMapper.deviceAssignmentsMapper(dq);
            for (DeviceAssignments assignments : assignmentsList) {
                assignments.setActive(DeviceActiveStatusEnum.INACTIVE.getCode());
                deviceAssignmentsMapper.updateById(assignments);
            }
        }

    }


    /**
     * 解绑设备
     *
     * @param deviceForm
     */
    @Override
    @Transactional
    public void unbindDevice(DeviceForm deviceForm) {

    }

    /**
     * WEB端查看APP客户设备绑定
     *
     * @param bo
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<AppDeviceVo> queryAppDeviceList(DeviceQueryCriteria bo, PageQuery pageQuery) {
        if (bo.getBindingUserId() == null) {
            Long userId = AppLoginHelper.getUserId();
            bo.setBindingUserId(userId);
        }
        Page<AppDeviceVo> result = baseMapper.queryAppBindDeviceList(pageQuery.build(), bo);
        return TableDataInfo.build(result);
    }

    @Override
    public int bindDevice(AppDeviceBo bo) {
        Integer mode = bo.getCommunicationMode();
        Long userId = AppLoginHelper.getUserId();
        if (mode == CommunicationModeEnum.FOUR_G.getValue()) {

            String deviceImei = bo.getDeviceImei();
            QueryWrapper<Device> qw = new QueryWrapper<Device>()
                    .eq("device_imei", deviceImei);
            List<Device> devices = baseMapper.selectList(qw);
            if (devices.isEmpty()) {
                throw new RuntimeException("请先将设备入库！！！");
            }
            Device device = devices.get(0);
            if (device.getBindingStatus() != null && device.getBindingStatus() == BindingStatusEnum.BOUND.getCode()) {
                throw new RuntimeException("设备已绑定");
            }
            UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
            deviceUpdateWrapper.eq("id", device.getId())
                    .set("binding_status", BindingStatusEnum.BOUND.getCode())
                    .set("binding_user_id", userId)
                    .set("binding_time", new Date());


            return baseMapper.update(null, deviceUpdateWrapper);
        } else if (mode == CommunicationModeEnum.BLUETOOTH.getValue()) {
            String deviceMac = bo.getDeviceMac();
            QueryWrapper<Device> qw = new QueryWrapper<Device>()
                    .eq("device_mac", deviceMac);
            List<Device> devices = baseMapper.selectList(qw);
            if (devices.isEmpty()) {
                throw new RuntimeException("请先将设备入库！！！");
            }
            Device device = devices.get(0);
            if (device.getBindingStatus() != null && device.getBindingStatus() == BindingStatusEnum.BOUND.getCode()) {
                throw new RuntimeException("设备已绑定");
            }
            UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
            deviceUpdateWrapper.eq("id", device.getId())
                    .set("binding_status", BindingStatusEnum.BOUND.getCode())
                    .set("binding_user_id", userId)
                    .set("binding_time", new Date());
            return baseMapper.update(null, deviceUpdateWrapper);
        } else {
            throw new RuntimeException("通讯方式错误");
        }

    }

    @Override
    public int unBindDevice(Long id) {
        Device device = baseMapper.selectById(id);
        if (device == null) {
            throw new RuntimeException("请先将设备入库！！！");
        }
//        DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
//        String mode = deviceType.getCommunicationMode();
        UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
        deviceUpdateWrapper.eq("id", device.getId())
                .set("binding_status", BindingStatusEnum.UNBOUND.getCode())
                .set("binding_user_id", null)
                .set("binding_time", null);
        return baseMapper.update(null, deviceUpdateWrapper);
    }


    /**
     * WEB端解绑设备
     *
     * @param id
     * @return
     */
    @Override
    public int webUnBindDevice(Long id) {
        DeviceAssignments deviceAssignment = deviceAssignmentsMapper.selectById(id);
        if (deviceAssignment == null) {
            throw new RuntimeException("请先将设备入库！！！");
        }
        return unBindDevice(deviceAssignment.getDeviceId());
    }


    /**
     * 查询设备MAC号
     *
     * @param mac
     * @return
     */
    @Override
    public Boolean queryDevice(String mac) {
        QueryWrapper<Device> wrapper = new QueryWrapper<>();
        wrapper.eq("device_mac", mac);
        List<Device> deviceList = deviceMapper.selectList(wrapper);
        if (CollectionUtil.isNotEmpty(deviceList)) {
            return true;
        }
        return false;
    }


}
