package com.ruoyi.web.controller.app;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OperatorType;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ss.device.domain.Device;
import com.ruoyi.ss.device.domain.DeviceBO;
import com.ruoyi.ss.device.domain.DeviceQuery;
import com.ruoyi.ss.device.domain.DeviceView;
import com.ruoyi.ss.device.domain.dto.DeviceRegisterDTO;
import com.ruoyi.ss.device.domain.dto.DeviceWifiDTO;
import com.ruoyi.ss.device.domain.dto.PlacementDTO;
import com.ruoyi.ss.device.domain.enums.DevicePowerStatus;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceAssembler;
import com.ruoyi.ss.device.service.DeviceConverter;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.order.service.IOrderValidator;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.web.core.annotation.DeviceAdminRequired;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 设备Controller
 * @author qzz
 * 2024/3/5
 */
@Api(tags = "设备")
@RestController
@RequestMapping("/app/device")
public class AppDeviceController extends BaseController {

    @Autowired
    private DeviceService smDeviceService;

    @Autowired
    private DeviceAssembler deviceAssembler;

    @Autowired
    private DeviceValidator deviceValidator;

    @Autowired
    private IStoreService storeService;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private DeviceConverter deviceConverter;

    @Resource
    private IOrderValidator orderValidator;

    @Log(title = "商户修改设备信息", businessType = BusinessType.UPDATE, operatorType = OperatorType.MOBILE)
    @ApiOperation("商户修改设备信息")
    @PutMapping
    public AjaxResult edit(@RequestBody @Validated DeviceBO data) {
        return toAjax(smDeviceService.updateSmDevice(data));
    }

    @ApiOperation("查询商户设备列表")
    @GetMapping("/list")
    public TableDataInfo list(DeviceQuery smDevice) {
        startPage();
        startOrderBy();
        smDevice.setUserId(getUserId());
        List<DeviceVO> list = smDeviceService.selectSmDeviceList(smDevice);
        smDeviceService.pullDeviceInfoList(list);
        return getDataTable(list);
    }

    @ApiOperation("查询店铺设备列表")
    @GetMapping("/listByStore/{storeId}")
    @JsonView(JsonViewProfile.App.class)
    public TableDataInfo listByStore(@PathVariable("storeId") Long storeId, DeviceQuery query) {
        startPage();
        query.setStoreId(storeId);
        List<DeviceVO> list = smDeviceService.selectSmDeviceList(query);
        smDeviceService.pullDeviceInfoList(list);
//        deviceAssembler.assembleBusinessTime(list); // 店铺营业时间
        return getDataTable(list);
    }

    @ApiOperation("获取设备详细信息")
    @GetMapping(value = "/{deviceId}")
    public AjaxResult getInfo(@PathVariable("deviceId") Long deviceId) {
//        smDeviceService.pullDeviceInfo(Collections.singletonList(deviceId));
        DeviceVO device = smDeviceService.selectById(deviceId);
        List<DeviceVO> list = Collections.singletonList(device);
//        deviceAssembler.assembleOrderCountInfo(list);   // 订单统计信息
        deviceAssembler.assembleAllowSwitch(list, getUserId());
        return success(device);
    }

    @Log(title = "设备通断电", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("设备通断电")
    @PutMapping("/{deviceId}/changePower")
    public AjaxResult close(@PathVariable @ApiParam("设备id") Long deviceId, String status) {
        DeviceVO device = smDeviceService.selectById(deviceId);
        ServiceUtil.assertion(device == null, "设备不存在");
        deviceAssembler.assembleAllowSwitch(device, getUserId());
        ServiceUtil.assertion(!device.getAllowSwitch(), "您无权操作此设备");

        DevicePowerStatus powerStatus = DevicePowerStatus.parse(status);
        return success(smDeviceService.changePowerStatus(device, powerStatus,"小程序设备通断电" ));
    }

    @Log(title = "绑定设备", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("绑定设备")
    @PutMapping("/bind")
    public AjaxResult bind(@RequestBody Device device) {
        if (StringUtils.isAllBlank(device.getSn(), device.getMac())) {
            return error("设备编号和mac不能同时为空");
        }
        Long storeId = storeService.selectStoreIdByMerchantId(getUserId());
        if (StringUtils.hasText(device.getSn())) {
            return AjaxResult.success("操作成功", smDeviceService.bindBySn(storeId, getUserId(), device.getSn()));
        } else {
            return AjaxResult.success("操作成功", smDeviceService.bindByMac(storeId, getUserId(), device.getMac()));
        }
    }

    @Log(title = "解除设备绑定", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("解除设备绑定")
    @DeleteMapping("/mch/unbind/{deviceId}")
    public AjaxResult mchUnbind(@PathVariable @ApiParam("设备id") Long deviceId) {
        ServiceUtil.assertion(!deviceValidator.isMch(deviceId, getUserId()), "这不是您的设备");
        return toAjax(smDeviceService.unbind(deviceId));
    }

    @Log(title = "商户充值设备", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("商户充值设备")
    @PutMapping("/addTime/{deviceId}")
    public AjaxResult addTime(@PathVariable @ApiParam("设备id") Long deviceId,
                              @ApiParam("数值") @RequestParam BigDecimal amount,
                              @ApiParam("单位") @RequestParam(required = false, defaultValue = "3") String timeUnit,
                              @ApiParam("是否操作物联网设备") @RequestParam(required = false, defaultValue = "true") Boolean withIot
    ) {
        DeviceVO device = smDeviceService.selectById(deviceId);
        ServiceUtil.assertion(device == null, "设备不存在");
        deviceAssembler.assembleAllowSwitch(device, getUserId());
        ServiceUtil.assertion(!device.getAllowSwitch(), "您无权操作此设备");

        return toAjax(1);
    }

    @ApiOperation("刷新设备信息")
    @GetMapping("/{deviceId}/refreshIot")
    public AjaxResult syncIot(@PathVariable @ApiParam("设备id") Long deviceId) {
        smDeviceService.pullDeviceInfo(Collections.singletonList(deviceId));
        return success();
    }

    @ApiOperation("刷新数据信息v2")
    @GetMapping("/v2/refreshIot")
    public AjaxResult syncIotBySn(@RequestParam(required = false) Long deviceId,
                                  @RequestParam(required = false) String sn) {
        if (deviceId == null && StringUtils.isBlank(sn)) {
            return error("设备ID和SN必须传入其中一个");
        }
        DeviceVO device = null;
        if (deviceId != null) {
            device = smDeviceService.selectById(deviceId);
        } else if (StringUtils.hasText(sn)) {
            device = smDeviceService.selectBySn(sn);
        }
        smDeviceService.pullDeviceInfo(device);
        return success();
    }

    @ApiOperation("判断设备是否已经被绑定")
    @GetMapping("/isBind")
    public AjaxResult isBind(@RequestParam(required = false) @ApiParam("设备mac") String mac,
                              @RequestParam(required = false) @ApiParam("设备sn") String deviceNo) {
        if (StringUtils.hasText(mac)) {
            return success(smDeviceService.bindCodeByMac(mac));
        } else if (StringUtils.hasText(deviceNo)) {
            return success(smDeviceService.bindCodeBySn(deviceNo));
        } else {
            return error("至少传入一个MAC号或SN码");
        }
    }

    @ApiOperation("获取设备，包含套餐列表")
    @JsonView(DeviceView.SuitList.class)
    @GetMapping("/{deviceNo}/withSuitList")
    public AjaxResult getDeviceWithSuitList(@PathVariable String deviceNo) {
        return success(smDeviceService.getDeviceWithSuitList(deviceNo));
    }

    @ApiOperation("通过SN码获取设备信息")
    @GetMapping("/{deviceNo}/bySn")
    @JsonView(JsonViewProfile.App.class)
    public AjaxResult getByDeviceNo(@PathVariable @ApiParam("设备编号(SN)") String deviceNo) {
        return success(smDeviceService.selectBySn(deviceNo));
    }

    @Log(title = "管理员设备录入", businessType = BusinessType.INSERT, operatorType = OperatorType.MOBILE)
    @ApiOperation("管理员设备录入")
    @PostMapping
    public AjaxResult register(@RequestBody @Validated DeviceRegisterDTO dto) {
        return toAjax(smDeviceService.register(dto));
    }

//    @ApiOperation("管理员通过MAC获取设备信息")
//    @GetMapping("/admin/byMac")
//    @DeviceAdminRequired
//    public AjaxResult getByMac(String mac) {
//        return success(smDeviceService.selectByAnyMac(mac));
//    }

    @ApiOperation("管理员获取已录入的设备Mac列表")
    @GetMapping("/listAllMac")
    public AjaxResult getAllMac() {
        return success(smDeviceService.selectMacSnList(new DeviceQuery()));
    }

    @ApiOperation("管理员过滤已录入的设备MAC和SN列表")
    @GetMapping("/getExistMac/{mac}")
    public AjaxResult getExistMac(@PathVariable @ApiParam("设备mac") List<String> mac) {
        DeviceQuery query = new DeviceQuery();
        query.setMacList(mac);
        return success(smDeviceService.selectMacSnList(query));
    }

//    @ApiOperation("管理员开关设备")
//    @PutMapping("/admin/{deviceId}/switch")
//    public AjaxResult deviceSwitch(@PathVariable @ApiParam("设备ID") Long deviceId, @RequestParam @ApiParam("是否开启") Boolean open) {
//        return toAjax(smDeviceService.switchDevice(deviceId, open, "商户开关设备"));
//    }

    @ApiOperation("商户开关设备")
    @PutMapping("/adminMch/{equipmentId}/switch")
    public AjaxResult equipmentSwitch(@PathVariable @ApiParam("设施id") Long equipmentId, @RequestParam @ApiParam("是否开启") Boolean open) {
        return toAjax(smDeviceService.switchEquipment(equipmentId, open,false,"商户开关设施"));
    }

    @ApiOperation("房间开关")
    @PostMapping("/adminAll/{roomId}/switch")
    public AjaxResult adminGet(@PathVariable @ApiParam("房间id") Long roomId ,@RequestParam @ApiParam("是否开启") Boolean open, @RequestParam @ApiParam("订单号") String orderNo) {
        // 1. 如果没有在订单时间内  不能开门  2. 店铺状态为营业才能开门  3. 用户是否是当前用户
        ServiceUtil.assertion(orderValidator.preOpenDoor(roomId,orderNo));
        return toAjax(smDeviceService.roomAllSwitchDevice(roomId, open,"小程序房间开关"));
    }

    @ApiOperation("大厅全开/全关")
    @PostMapping("/adminAllEqu/{storeId}/switch")
    @DeviceAdminRequired
    public AjaxResult adminAllEqu(@PathVariable @ApiParam("店铺id") Long storeId ,@RequestParam @ApiParam("是否开启") Boolean open) {
        return toAjax(smDeviceService.hallEquAllSwitchDevice(storeId, open,"小程序大厅全开/全关"));
    }

//    @ApiOperation("管理员修改设备电压系数")
//    @DeviceAdminRequired
//    @PutMapping("/admin/{deviceId}/vxs")
//    public AjaxResult getExistMac(@PathVariable @ApiParam("设备ID") Long deviceId, @RequestParam @ApiParam("电压系数") BigDecimal vxs) {
//        return toAjax(smDeviceService.updateVxs(deviceId, vxs, "小程序管理员修改设备电压系数"));
//    }

//    @ApiOperation("管理员获取设备信息接口")
//    @GetMapping("/admin/get")
//    @DeviceAdminRequired
//    public AjaxResult adminGet(@RequestParam(required = false) String sn) {
//        DeviceVO device = null;
//        if (StringUtils.hasText(sn)) {
//            device = smDeviceService.selectBySn(sn);
//        } else {
//            return error("请输入SN码");
//        }
//        return success(device);
//    }


    @ApiOperation("获取正在使用中的设备列表")
    @GetMapping("/usingDevice")
    @JsonView(JsonViewProfile.App.class)
    public AjaxResult getUsingDevice() {
       return success(smDeviceService.selectUsingDevice(getUserId()));
    }

    @ApiOperation("设置设备WIFI密码")
    @PutMapping("/setWifi")
    public AjaxResult setWifi(@RequestBody DeviceWifiDTO dto) {

        return toAjax(smDeviceService.setWifi(dto));
    }

    /**
     * 投放设备
     */
    @PostMapping("/placement")
    public AjaxResult placementDevice(@RequestBody PlacementDTO dto) {
        logger.info("投放设备：【dto={}】", JSON.toJSONString(dto));
        return toAjax(smDeviceService.placementDevice(dto));
    }

    /**
     * 下架设备
     */
    @PostMapping("/offline/{deviceId}")
    public AjaxResult offline(@PathVariable("deviceId") Long deviceId) {
        logger.info("下架设备：【deviceId={}】", deviceId);
        return toAjax(smDeviceService.offline(deviceId));
    }

    /**
     * 修改设备名称
     */
    @PostMapping("/editName/{deviceId}")
    public AjaxResult editName(@PathVariable("deviceId") Long deviceId,@RequestParam(required = false)String deviceName) {
        logger.info("下架设备：【deviceId={},name={}】", deviceId,deviceName);
        Device device = new Device();
        device.setDeviceId(deviceId);
        device.setDeviceName(deviceName);
        return toAjax(smDeviceService.updateSmDevice(device));
    }

}
