package com.ruoyi.ems.controller;

import com.huashe.common.domain.AjaxResult;
import com.huashe.common.exception.BusinessException;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.domain.MeterDevice;
import com.ruoyi.ems.model.QueryDevice;
import com.ruoyi.ems.model.TreeEntity;
import com.ruoyi.ems.service.IAreaService;
import com.ruoyi.ems.service.IMeterDeviceService;
import com.ruoyi.ems.util.AreaUtils;
import io.swagger.annotations.Api;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 计量设备Controller
 *
 * @author ruoyi
 * @date 2024-08-08
 */
@RestController
@RequestMapping("/meterDevice")
@Api(value = "MeterDeviceController", description = "计量设备管理")
public class MeterDeviceController extends BaseController {
    @Autowired
    private IMeterDeviceService meterDeviceService;

    @Autowired
    private IAreaService areaService;

    /**
     * 查询计量设备列表
     */
    @RequiresPermissions("ems:meterdevc:list")
    @GetMapping("/list")
    public TableDataInfo list(QueryDevice queryDevice) {
        startPage();
        List<MeterDevice> list = meterDeviceService.selectMeterDeviceList(queryDevice);
        return getDataTable(list);
    }

    /**
     * 递归查询 区域 下的设备(分页)
     */
    @RequiresPermissions("basecfg:device:list")
    @GetMapping("/listRecursionByArea")
    public TableDataInfo listRecursionByArea(QueryDevice queryDevice) {
        TableDataInfo tabInfo = null;

        try {
            if (StringUtils.isNotEmpty(queryDevice.getLocationRef())) {
                List<Area> areaTree = areaService.selectAreaTree(queryDevice.getLocationRef(), true);
                List<String> areaCodes = new ArrayList<>();
                areaCodes.add(queryDevice.getLocationRef());
                // 递归取出区域子节点code做查询条件（需要将子节点区域关联设备一并取出）
                AreaUtils.getCodeRecursion(areaTree, areaCodes);
                queryDevice.setAreaCodes(areaCodes);
            }

            startPage();
            List<MeterDevice> list = meterDeviceService.selectMeterDeviceList(queryDevice);
            tabInfo = getDataTable(list);
        }
        catch (BusinessException e) {
            tabInfo = new TableDataInfo();
            tabInfo.setCode(e.getCode());
            tabInfo.setMsg(e.getMessage());
        }

        return tabInfo;
    }

    /**
     * 根据设施获取设备树结构
     *
     * @param parentCode 区域code
     * @return 树结构
     */
    @RequiresPermissions("basecfg:meterdevc:list")
    @GetMapping("/getTreeByArea")
    public AjaxResult getTreeByArea(
        @RequestParam(name = "parentCode", required = false, defaultValue = "0") String parentCode,
        QueryDevice queryParam) {
        List<TreeEntity> retList = new ArrayList<>();

        // 查询区域树
        List<Area> areas = areaService.selectAreaTree(parentCode, true);

        // 查询设备列表并按区域分组
        List<MeterDevice> list = meterDeviceService.selectMeterDeviceList(queryParam);
        Map<String, List<MeterDevice>> groupMap = list.stream()
            .collect(Collectors.groupingBy(MeterDevice::getLocationRef, Collectors.toList()));

        // 递归处理每个顶级区域，生成完整树形结构
        for (Area area : areas) {
            TreeEntity treeNode = buildRecursiveTree(area, groupMap);
            if (treeNode != null) { // 仅添加有内容的节点
                retList.add(treeNode);
            }
        }

        return success(retList);
    }

    /**
     * 递归构建区域树节点，区分区域和设备类型
     *
     * @param area     当前区域节点
     * @param groupMap 设备按区域分组的映射
     * @return 当前区域对应的树形节点（若无可挂载内容则返回null）
     */
    private TreeEntity buildRecursiveTree(Area area, Map<String, List<MeterDevice>> groupMap) {
        // 当前区域的树形节点（类型为area）
        TreeEntity currentNode = new TreeEntity();
        currentNode.setId(area.getAreaCode()); // 使用区域编码作为节点ID
        currentNode.setLabel(area.getAreaName()); // 区域名称作为节点标签
        currentNode.setType("area"); // 标记为区域类型
        List<TreeEntity> childNodes = new ArrayList<>();

        // 1. 处理本级设备：转换为device类型节点
        if (groupMap.containsKey(area.getAreaCode())) {
            List<TreeEntity> deviceNodes = convertToTreeEntity(groupMap.get(area.getAreaCode()));
            // 为每个设备节点设置类型为device
            deviceNodes.forEach(deviceNode -> {
                deviceNode.setType("device");
                // 设备节点无子节点，确保children为空
                deviceNode.setChildren(null);
            });
            childNodes.addAll(deviceNodes);
        }

        // 2. 递归处理所有子区域（类型为area）
        if (CollectionUtils.isNotEmpty(area.getChildren())) {
            for (Object childObj : area.getChildren()) {
                Area childArea = (Area) childObj;
                TreeEntity childTreeNode = buildRecursiveTree(childArea, groupMap);
                if (childTreeNode != null) {
                    childNodes.add(childTreeNode);
                }
            }
        }

        // 3. 若当前节点没有任何子节点，不保留该节点
        if (childNodes.isEmpty()) {
            return null;
        }

        currentNode.setChildren(childNodes);
        return currentNode;
    }

    /**
     * 将设备列表转换为TreeEntity列表（基础转换，不包含类型设置）
     *
     * @param devices 设备列表
     * @return 转换后的TreeEntity列表
     */
    private List<TreeEntity> convertToTreeEntity(List<MeterDevice> devices) {
        List<TreeEntity> treeEntities = new ArrayList<>();
        for (MeterDevice device : devices) {
            TreeEntity entity = new TreeEntity();
            entity.setId(device.getDeviceCode()); // 使用设备编码作为ID
            entity.setLabel(device.getDeviceName()); // 使用设备名称作为标签
            // 设备节点的子节点在后续处理中会被设为null
            treeEntities.add(entity);
        }
        return treeEntities;
    }

    /**
     * 导出计量设备列表
     */
    @RequiresPermissions("ems:meterdevc:export")
    @Log(title = "计量设备", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, QueryDevice queryDevice) {
        List<MeterDevice> list = meterDeviceService.selectMeterDeviceList(queryDevice);
        ExcelUtil<MeterDevice> util = new ExcelUtil<MeterDevice>(MeterDevice.class);
        util.exportExcel(response, list, "计量设备数据");
    }

    /**
     * 获取计量设备详细信息
     */
    @RequiresPermissions("ems:meterdevc:query")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(meterDeviceService.selectMeterDeviceById(id));
    }

    /**
     * 新增计量设备
     */
    @RequiresPermissions("ems:meterdevc:add")
    @Log(title = "计量设备", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody MeterDevice meterDevice) {
        return toAjax(meterDeviceService.insertMeterDevice(meterDevice));
    }

    /**
     * 修改计量设备
     */
    @RequiresPermissions("ems:meterdevc:edit")
    @Log(title = "计量设备", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody MeterDevice meterDevice) {
        return toAjax(meterDeviceService.updateMeterDevice(meterDevice));
    }

    /**
     * 删除计量设备
     */
    @RequiresPermissions("ems:meterdevc:remove")
    @Log(title = "计量设备", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(meterDeviceService.deleteMeterDeviceByIds(ids));
    }

    @GetMapping("/cnt")
    public AjaxResult cntMeterDevice(@RequestParam(name = "areaCode", required = false) String areaCode) {
        return success(meterDeviceService.cntMeterDevice(areaCode));
    }
}
