package com.ruoyi.web.controller.app;

import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.annotation.Log;
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.domain.ValidGroup;
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.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.device.domain.DeviceView;
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.dto.DeviceRegisterDTO;
import com.ruoyi.ss.device.domain.dto.DeviceWifiDTO;
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.DeviceValidator;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.meterReadingRecord.domain.SmMeterReadingRecordQuery;
import com.ruoyi.ss.meterReadingRecord.service.ISmMeterReadingRecordService;
import com.ruoyi.ss.suit.domain.enums.SuitTimeUnit;
import com.ruoyi.ss.suit.service.SuitValidator;
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 java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

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

    @Autowired
    private DeviceService smDeviceService;

    @Autowired
    private ISmMeterReadingRecordService smMeterReadingRecordService;

    @Autowired
    private DeviceAssembler deviceAssembler;

    @Autowired
    private DeviceValidator deviceValidator;

    @Autowired
    private DeviceConverter deviceConverter;

    @Autowired
    private SuitValidator suitValidator;


    @Log(title = "商户修改设备信息", businessType = BusinessType.UPDATE, operatorType = OperatorType.MOBILE)
    @ApiOperation("商户修改设备信息")
    @PutMapping
    public AjaxResult edit(@RequestBody @Validated({ValidGroup.FrontUpdate.class}) DeviceBO data) {
        Long userId = getUserId();
        // 转换
        data = deviceConverter.toBOByAppUpdate(data, userId);

        // 判断是否有权限更改
        if (!deviceValidator.canOpera(data.getDeviceId(), userId) ) {
            return error("您无权修改该设备");
        }
        // 判断套餐
        if (CollectionUtils.isNotEmptyElement(data.getSuitIds()) && !suitValidator.isBelong(data.getSuitIds(), userId)) {
            return error("有套餐不属于您，无权修改");
        }
        ServiceUtil.assertion(deviceValidator.preUpdateByApp(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);
        deviceAssembler.assembleRealServiceRate(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) {
        // 判断是否有权限更改
        if (!deviceValidator.canOpera(deviceId, getUserId()) ) {
            return error("您无权操作此设备");
        }
        DeviceVO device = smDeviceService.selectById(deviceId);
        ServiceUtil.assertion(device == null, "设备不存在");
        deviceAssembler.assembleAllowSwitch(device, getUserId());
        ServiceUtil.assertion(!device.getAllowSwitch(), "您无权操作此设备");

        DevicePowerStatus powerStatus = DevicePowerStatus.parse(status);
        return toAjax(smDeviceService.switchDevice(device, powerStatus, "商户开关设备"));
    }

    @Log(title = "绑定设备", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("绑定设备")
    @PutMapping("/bind")
    public AjaxResult bind(@RequestBody Device device) {
        if (StringUtils.isAllBlank(device.getDeviceNo(), device.getMac())) {
            return error("设备编号和mac不能同时为空");
        }
        if (StringUtils.hasText(device.getDeviceNo())) {
            return AjaxResult.success("操作成功", smDeviceService.bindBySn(device.getStoreId(), getUserId(), device.getDeviceNo()));
        } else {
            return AjaxResult.success("操作成功", smDeviceService.bindByMac(device.getStoreId(), 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("{deviceId}/reset")
    public AjaxResult reset(@PathVariable @ApiParam("设备id") Long deviceId) {
        if (!deviceValidator.canOpera(deviceId, getUserId()) ) {
            return error("您无权操作此设备");
        }
        return toAjax(smDeviceService.resetWithBill(deviceId, true, null, "商户设备归零:id=" + deviceId, true, true));
    }

    @ApiOperation("获取设备用电量分析")
    @GetMapping("/electric/count")
    public AjaxResult count(@Validated({ValidGroup.Query.class}) SmMeterReadingRecordQuery dto)
    {
        return success(smMeterReadingRecordService.selectCount(dto));
    }

    @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(), "您无权操作此设备");

        // 电量
        if ( "0".equals(timeUnit)) {
            return toAjax(smDeviceService.addEle(deviceId, amount, withIot, "商户手动充值"));
        }
        // 时长
        else {
            SuitTimeUnit unit = SuitTimeUnit.getByValue(timeUnit);
            if (unit == null) {
                return error("非法的时长单位");
            }
            long seconds = amount.multiply(new BigDecimal(unit.getConversion())).longValue();
            return toAjax(smDeviceService.addTime(deviceId, seconds, withIot, "商户手动充值"));
        }
    }

    @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 deviceNo,
                                  @RequestParam(required = false) String mac) {
        DeviceVO device = null;
        if (deviceId != null) {
            device = smDeviceService.selectById(deviceId);
        } else if (StringUtils.hasText(deviceNo)) {
            device = smDeviceService.selectByDeviceNo(deviceNo);
        } else if (StringUtils.hasText(mac)) {
            device = smDeviceService.selectByAnyMac(mac);
        } else {
            return error("设备ID、SN、MAC必须传入其中一个");
        }
        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.selectByDeviceNo(deviceNo));
    }

    @Log(title = "管理员设备录入", businessType = BusinessType.INSERT, operatorType = OperatorType.MOBILE)
    @ApiOperation("管理员设备录入")
    @PostMapping
    @DeviceAdminRequired
    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")
    @DeviceAdminRequired
    public AjaxResult getAllMac() {
        return success(smDeviceService.selectMacSnList(new DeviceQuery()));
    }

    @ApiOperation("管理员过滤已录入的设备MAC和SN列表")
    @DeviceAdminRequired
    @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("管理员开关设备")
    @DeviceAdminRequired
    @PutMapping("/admin/{deviceId}/switch")
    public AjaxResult getExistMac(@PathVariable @ApiParam("设备ID") Long deviceId, @RequestParam @ApiParam("是否开启") Boolean open) {
        return toAjax(smDeviceService.switchDevice(deviceId, 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.selectByDeviceNo(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) {
        if (!deviceValidator.canOpera(dto.getDeviceId(), getUserId())) {
            return error("您无权操作");
        }
        dto.setReason("商户远程配网");
        return toAjax(smDeviceService.setWifi(dto));
    }

}
