package org.dromara.member.controller.app;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.member.domain.bo.AppDeviceBo;
import org.dromara.member.domain.vo.AppDeviceVo;
import org.dromara.member.service.AppDeviceService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * App端设备管理
 *
 * @author pengles
 */
@Tag(name = "App端设备管理", description = "App端设备信息管理接口")
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/device")
public class AppDeviceController extends BaseController {

    private final AppDeviceService appDeviceService;

    /**
     * 查询App端设备信息列表
     */
    @Operation(summary = "查询设备列表", description = "分页查询当前用户的设备信息列表")
    @SaCheckLogin
    @GetMapping("/list")
    public TableDataInfo<AppDeviceVo> list(@Parameter(description = "设备查询条件") @Valid AppDeviceBo bo,
                                           @Parameter(description = "分页参数") @Valid PageQuery pageQuery) {
        // 只能查询当前用户的设备
        bo.setUserId(StpUtil.getLoginIdAsLong());
        return appDeviceService.queryPageList(bo, pageQuery);
    }

    /**
     * 获取App端设备信息详细信息
     */
    @Operation(summary = "获取设备详情", description = "根据设备ID获取详细信息")
    @SaCheckLogin
    @GetMapping("/{deviceId}")
    public R<AppDeviceVo> getInfo(@Parameter(description = "设备ID", required = true)
                                  @PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
        AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
        // 验证设备是否属于当前用户
        if (deviceVo != null && !deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限访问该设备信息");
        }
        return R.ok(deviceVo);
    }

    /**
     * 绑定设备
     */
    @Operation(summary = "绑定设备", description = "绑定新设备到当前用户")
    @SaCheckLogin
    @Log(title = "App端设备信息", businessType = BusinessType.INSERT)
    @PostMapping("/bind")
    public R<Void> bind(@Parameter(description = "设备信息", required = true)
                        @Validated(AddGroup.class) @RequestBody @NotNull(message = "设备信息不能为空") AppDeviceBo bo) {
        // 设置当前用户ID
        bo.setUserId(StpUtil.getLoginIdAsLong());

        // 验证必要字段
        if (StringUtils.isBlank(bo.getDeviceType())) {
            return R.fail("设备类型不能为空");
        }
        if (StringUtils.isBlank(bo.getDeviceName())) {
            return R.fail("设备名称不能为空");
        }

        return toAjax(appDeviceService.bindDevice(bo));
    }

    /**
     * 修改设备信息
     */
    @Operation(summary = "修改设备信息", description = "修改设备信息")
    @SaCheckLogin
    @Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<Void> edit(@Parameter(description = "设备信息", required = true)
                        @Validated(EditGroup.class) @RequestBody @NotNull(message = "设备信息不能为空") AppDeviceBo bo) {
        // 验证设备是否属于当前用户
        AppDeviceVo deviceVo = appDeviceService.queryById(bo.getDeviceId());
        if (deviceVo == null) {
            return R.fail("设备不存在");
        }
        if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限修改该设备信息");
        }

        // 设置当前用户ID
        bo.setUserId(StpUtil.getLoginIdAsLong());
        return toAjax(appDeviceService.updateByBo(bo));
    }

    /**
     * 解绑设备
     */
    @Operation(summary = "解绑设备", description = "解绑指定设备")
    @SaCheckLogin
    @Log(title = "App端设备信息", businessType = BusinessType.DELETE)
    @DeleteMapping("/{deviceId}")
    public R<Void> unbind(@Parameter(description = "设备ID", required = true)
                          @PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
        return toAjax(appDeviceService.unbindDevice(deviceId, StpUtil.getLoginIdAsLong()));
    }

    /**
     * 获取我的设备列表
     */
    @Operation(summary = "获取我的设备", description = "获取当前用户的所有设备列表")
    @SaCheckLogin
    @GetMapping("/my")
    public R<List<AppDeviceVo>> getMyDevices() {
        List<AppDeviceVo> devices = appDeviceService.queryByUserId(StpUtil.getLoginIdAsLong());
        return R.ok(devices);
    }

    /**
     * 获取活跃设备列表
     */
    @Operation(summary = "获取活跃设备", description = "获取当前用户的活跃设备列表")
    @SaCheckLogin
    @GetMapping("/active")
    public R<List<AppDeviceVo>> getActiveDevices() {
        List<AppDeviceVo> devices = appDeviceService.getActiveDevices(StpUtil.getLoginIdAsLong());
        return R.ok(devices);
    }

    /**
     * 更新设备状态
     */
    @Operation(summary = "更新设备状态", description = "更新设备的激活状态")
    @SaCheckLogin
    @Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
    @PutMapping("/{deviceId}/status")
    public R<Void> updateStatus(@Parameter(description = "设备ID", required = true)
                                @PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId,
                                @Parameter(description = "设备状态(0-禁用,1-启用)", required = true)
                                @RequestParam @NotBlank(message = "设备状态不能为空") @Pattern(regexp = "^[01]$", message = "设备状态只能为0或1") String isActive) {
        // 验证设备是否属于当前用户
        AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
        if (deviceVo == null) {
            return R.fail("设备不存在");
        }
        if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限修改该设备状态");
        }

        // 验证状态值
        if (!"0".equals(isActive) && !"1".equals(isActive)) {
            return R.fail("状态值无效");
        }

        return toAjax(appDeviceService.updateActiveStatus(deviceId, isActive));
    }

    /**
     * 更新设备推送令牌
     */
    @Operation(summary = "更新推送令牌", description = "更新设备的推送令牌")
    @SaCheckLogin
    @Log(title = "App端设备信息", businessType = BusinessType.UPDATE)
    @PutMapping("/{deviceId}/push-token")
    public R<Void> updatePushToken(@Parameter(description = "设备ID", required = true)
                                   @PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId,
                                   @Parameter(description = "推送令牌", required = true)
                                   @RequestParam @NotBlank(message = "推送令牌不能为空") @Size(max = 255, message = "推送令牌长度不能超过255个字符") String pushToken) {
        // 验证设备是否属于当前用户
        AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
        if (deviceVo == null) {
            return R.fail("设备不存在");
        }
        if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限修改该设备推送令牌");
        }

        if (StringUtils.isBlank(pushToken)) {
            return R.fail("推送令牌不能为空");
        }

        return toAjax(appDeviceService.updatePushToken(deviceId, pushToken));
    }

    /**
     * 设备心跳
     */
    @Operation(summary = "设备心跳", description = "更新设备心跳时间")
    @SaCheckLogin
    @PostMapping("/{deviceId}/heartbeat")
    public R<Void> heartbeat(@Parameter(description = "设备ID", required = true)
                             @PathVariable @NotNull(message = "设备ID不能为空") @Positive(message = "设备ID必须为正数") Long deviceId) {
        // 验证设备是否属于当前用户
        AppDeviceVo deviceVo = appDeviceService.queryById(deviceId);
        if (deviceVo == null) {
            return R.fail("设备不存在");
        }
        if (!deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限操作该设备");
        }

        return toAjax(appDeviceService.heartbeat(deviceId));
    }

    /**
     * 根据推送令牌获取设备信息
     */
    @Operation(summary = "根据推送令牌获取设备", description = "根据推送令牌获取设备信息")
    @SaCheckLogin
    @GetMapping("/by-push-token")
    public R<AppDeviceVo> getDeviceByPushToken(@Parameter(description = "推送令牌", required = true)
                                               @RequestParam @NotBlank(message = "推送令牌不能为空") @Size(max = 255, message = "推送令牌长度不能超过255个字符") String pushToken) {
        if (StringUtils.isBlank(pushToken)) {
            return R.fail("推送令牌不能为空");
        }

        AppDeviceVo deviceVo = appDeviceService.queryByPushToken(pushToken);
        // 验证设备是否属于当前用户
        if (deviceVo != null && !deviceVo.getUserId().equals(StpUtil.getLoginIdAsLong())) {
            return R.fail("无权限访问该设备信息");
        }

        return R.ok(deviceVo);
    }

}