package com.multictrl.modules.business.controller;

import cn.hutool.json.JSONObject;
import com.multictrl.common.annotation.ApiOrder;
import com.multictrl.common.annotation.LogOperation;
import com.multictrl.common.constant.BusinessConstant;
import com.multictrl.common.exception.ErrorCode;
import com.multictrl.common.utils.CacheUtils;
import com.multictrl.common.utils.Result;
import com.multictrl.common.validator.ValidatorUtils;
import com.multictrl.modules.business.dto.camera.*;
import com.multictrl.modules.business.service.CameraService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;

/**
 * 云台相机控制
 *
 * @author Sdy
 * @since 1.0.0 2026/4/28
 */
@RestController
@RequestMapping("business/camera")
@Tag(name = "云台相机控制")
@ApiOrder(7)
@RequiredArgsConstructor
public class CameraController {
    private final CameraService cameraService;

    @LogOperation("框选变焦")
    @PostMapping("/frameZoom/{dockSn}")
    @Operation(summary = "框选变焦")
    @RequiresPermissions("bus:camera:frameZoom")
    public Result<Object> frameZoom(@PathVariable String dockSn, @RequestBody FrameZoom frameZoom) {
        ValidatorUtils.validateEntity(frameZoom);

        return new Result<>().ok(cameraService.frameZoom(dockSn, frameZoom));
    }

    @LogOperation("切换相机模式")
    @PostMapping("/modeSwitch/{dockSn}")
    @Operation(summary = "切换相机模式")
    @RequiresPermissions("bus:camera:modeSwitch")
    public Result<Object> modeSwitch(@PathVariable String dockSn,
                                     @Parameter(name = "mode", description = "模式 0:拍照 1:录像 2:智能低光 3:全景拍照")
                                     @RequestParam Integer mode) {

        return new Result<>().ok(cameraService.modeSwitch(dockSn, mode));
    }

    @LogOperation("拍照录像")
    @PostMapping("/photoVideo/{dockSn}")
    @Operation(summary = "拍照录像")
    @RequiresPermissions("bus:camera:photoVideo")
    public Result<Object> photoVideo(@PathVariable String dockSn,
                                     @Parameter(name = "mode", description = "类型 camera_photo_take开始拍照 camera_photo_stop停止拍照（目前仅支持全景拍照模式） " +
                                             "camera_recording_start开始录像 camera_recording_stop停止录像")
                                     @RequestParam String mode) {
        if (!mode.equals("camera_photo_take") && !mode.equals("camera_photo_stop") &&
                !mode.equals("camera_recording_start") && !mode.equals("camera_recording_stop")) {
            return new Result<>().error(ErrorCode.PARAMS_ERROR);
        }

        return new Result<>().ok(cameraService.photoVideo(dockSn, mode));
    }

    @LogOperation("画面拖动控制")
    @PostMapping("/screenDrag/{dockSn}")
    @Operation(summary = "画面拖动控制")
    @RequiresPermissions("bus:camera:screenDrag")
    public Result<Object> screenDrag(@PathVariable String dockSn, @RequestBody ScreenDrag screenDrag) {
        ValidatorUtils.validateEntity(screenDrag);

        return new Result<>().ok(cameraService.screenDrag(dockSn, screenDrag));
    }

    @LogOperation("双击成为AIM")
    @PostMapping("/aim/{dockSn}")
    @Operation(summary = "双击成为AIM")
    @RequiresPermissions("bus:camera:aim")
    public Result<Object> aim(@PathVariable String dockSn, @RequestBody AimParam aimParam) {
        ValidatorUtils.validateEntity(aimParam);

        return new Result<>().ok(cameraService.aim(dockSn, aimParam));
    }

    @LogOperation("变焦")
    @PostMapping("/focalLengthSet/{dockSn}")
    @Operation(summary = "变焦")
    @RequiresPermissions("bus:camera:focalLengthSet")
    public Result<Object> focalLengthSet(@PathVariable String dockSn, @RequestBody FocalLengthSet focalLengthSet) {
        Object videoType = CacheUtils.get(BusinessConstant.UAV_VIDEO_TYPE + dockSn);
        focalLengthSet.setCameraType(Objects.requireNonNullElse((String) videoType, "wide"));
        ValidatorUtils.validateEntity(focalLengthSet);

        return new Result<>().ok(cameraService.focalLengthSet(dockSn, focalLengthSet));
    }

    @LogOperation("重置云台")
    @PostMapping("/gimbalReset/{dockSn}")
    @Operation(summary = "重置云台")
    @RequiresPermissions("bus:camera:gimbalReset")
    public Result<Object> gimbalReset(@PathVariable String dockSn,
                                      @Parameter(name = "mode", description = "模式 0:回中 1:向下 2:偏航回中 3:俯仰向下")
                                      @RequestParam Integer mode) {

        return new Result<>().ok(cameraService.gimbalReset(dockSn, mode));
    }

    @LogOperation("Look At")
    @PostMapping("/lookAt/{dockSn}")
    @Operation(summary = "Look At", description = "lookat 功能指飞行器将从当前朝向转向实际经纬高度指定的点，" +
            "在 M30/M30T 机型上建议使用锁定机头的方式，仅云台转动场景下在抵达云台限位角后 lookat 功能将出现异常")
    @RequiresPermissions("bus:camera:lookAt")
    public Result<Object> lookAt(@PathVariable String dockSn, @RequestBody LookAt lookAt) {
        ValidatorUtils.validateEntity(lookAt);

        return new Result<>().ok(cameraService.lookAt(dockSn, lookAt));
    }

    @LogOperation("分屏")
    @PostMapping("/screenSplit/{dockSn}")
    @Operation(summary = "分屏")
    @RequiresPermissions("bus:camera:screenSplit")
    public Result<Object> screenSplit(@PathVariable String dockSn,
                                      @Parameter(name = "enable", description = "是否使能分屏 1开启分屏 0关闭分屏")
                                      @RequestParam Integer enable) {

        return new Result<>().ok(cameraService.screenSplit(dockSn, enable));
    }

    @LogOperation("照片、视频存储设置")
    @PostMapping("/storageSet/{dockSn}")
    @Operation(summary = "照片、视频存储设置")
    @RequiresPermissions("bus:camera:storageSet")
    public Result<Object> storageSet(@PathVariable String dockSn, @RequestBody StorageSet storageSet) {
        ValidatorUtils.validateEntity(storageSet);

        return new Result<>().ok(cameraService.storageSet(dockSn, storageSet));
    }

    @LogOperation("相机曝光模式设置")
    @PostMapping("/exposureModeSet/{dockSn}")
    @Operation(summary = "相机曝光模式设置")
    @RequiresPermissions("bus:camera:exposureModeSet")
    public Result<Object> exposureModeSet(@PathVariable String dockSn,
                                          @Parameter(name = "mode", description = "曝光模式 1:自动 2:快门优先曝光 3:光圈优先曝光 4:手动曝光")
                                          @RequestParam Integer mode) {

        return new Result<>().ok(cameraService.exposureModeSet(dockSn, mode));
    }

    @LogOperation("相机曝光值调节")
    @PostMapping("/exposureSet/{dockSn}")
    @Operation(summary = "相机曝光值调节")
    @RequiresPermissions("bus:camera:exposureSet")
    public Result<Object> exposureSet(@PathVariable String dockSn,
                                      @Parameter(name = "value", description = "曝光值 1:-5.0EV 2:-4.7EV 3:-4.3EV 4:-4.0EV " +
                                              "5:-3.7EV 6:-3.3EV 7:-3.0EV 8:-2.7EV 9:-2.3EV 10:-2.0EV 11:-1.7EV 12:-1.3EV " +
                                              "13:-1.0EV ...查看接口(获取相机曝光值)")
                                      @RequestParam String value) {

        return new Result<>().ok(cameraService.exposureSet(dockSn, value));
    }

    @LogOperation("相机对焦模式设置")
    @PostMapping("/focusModeSet/{dockSn}")
    @Operation(summary = "相机对焦模式设置", description = "注意: Matrice 30 系列飞行器只支持 zoom 镜头下配置该参数")
    @RequiresPermissions("bus:camera:focusModeSet")
    public Result<Object> focusModeSet(@PathVariable("dockSn") String dockSn,
                                       @Parameter(name = "mode", description = "对焦模式 1:MF 2:AFS 3:AFC")
                                       @RequestParam Integer mode) {

        return new Result<>().ok(cameraService.focusModeSet(dockSn, mode));
    }

    @LogOperation("相机对焦值设置")
    @PostMapping("/focusSet/{dockSn}")
    @Operation(summary = "相机对焦值设置", description = "注意: Matrice 30 系列飞行器只支持 zoom 镜头下配置该参数")
    @RequiresPermissions("bus:camera:focusSet")
    public Result<Object> focusSet(@PathVariable("dockSn") String dockSn,
                                   @Parameter(name = "value", description = "对焦值:范围参见飞行器物模型属性 zoom_max_focus_value 和 zoom_min_focus_value")
                                   @RequestParam Integer value) {

        return new Result<>().ok(cameraService.focusSet(dockSn, value));
    }

    @LogOperation("点对焦")
    @PostMapping("/pointFocusAction/{dockSn}")
    @Operation(summary = "点对焦")
    @RequiresPermissions("bus:camera:pointFocusAction")
    public Result<Object> pointFocusAction(@PathVariable String dockSn, @RequestBody PointFocusAction pointFocusAction) {
        ValidatorUtils.validateEntity(pointFocusAction);

        return new Result<>().ok(cameraService.pointFocusAction(dockSn, pointFocusAction));
    }

    @LogOperation("红外测温模式设置")
    @PostMapping("/irMeteringModeSet/{dockSn}")
    @Operation(summary = "红外测温模式设置", description = "注意: Matrice 30 系列飞行器只支持 zoom 镜头下配置该参数")
    @RequiresPermissions("bus:camera:focusSet")
    public Result<Object> irMeteringModeSet(@PathVariable("dockSn") String dockSn,
                                            @Parameter(name = "value", description = "对焦值:范围参见飞行器物模型属性 zoom_max_focus_value 和 zoom_min_focus_value")
                                            @RequestParam Integer value) {

        return new Result<>().ok(cameraService.focusSet(dockSn, value));
    }

    @LogOperation("红外测温点设置")
    @PostMapping("/irMeteringPointSet/{dockSn}")
    @Operation(summary = "红外测温点设置")
    @RequiresPermissions("bus:camera:irMeteringPointSet")
    public Result<Object> irMeteringPointSet(@PathVariable String dockSn, @RequestBody IrMeteringPointSet irMeteringPointSet) {
        ValidatorUtils.validateEntity(irMeteringPointSet);

        return new Result<>().ok(cameraService.irMeteringPointSet(dockSn, irMeteringPointSet));
    }

    @LogOperation("红外测温区域设置")
    @PostMapping("/irMeteringAreaSet/{dockSn}")
    @Operation(summary = "红外测温区域设置")
    @RequiresPermissions("bus:camera:irMeteringAreaSet")
    public Result<Object> irMeteringAreaSet(@PathVariable String dockSn, @RequestBody IrMeteringAreaSet irMeteringAreaSet) {
        ValidatorUtils.validateEntity(irMeteringAreaSet);

        return new Result<>().ok(cameraService.irMeteringAreaSet(dockSn, irMeteringAreaSet));
    }

    @GetMapping("/getExposureValue")
    @Operation(summary = "获取相机曝光值")
    public Result<List<JSONObject>> getExposureValue() {

        return new Result<List<JSONObject>>().ok(cameraService.getExposureValue());
    }
}
