package com.dji.sample.manage.controller;

import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.dto.DeviceDictionaryDTO;
import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
import com.dji.sample.manage.model.param.DeviceSearchParam;
import com.dji.sample.manage.service.IDeviceDictionaryService;
import com.dji.sample.manage.service.IDeviceService;
import com.dji.sdk.common.HttpResultResponse;
import com.dji.sdk.common.PaginationData;
import com.dji.sdk.exception.CloudSDKErrorEnum;
import com.dji.sdk.mqtt.property.PropertySetReplyResultEnum;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

/**
 * @author sean.zhou
 * @version 0.1
 * @date 2021/11/15
 */
@RestController
@Slf4j
@RequestMapping("${url.manage.prefix}${url.manage.version}/devices")
public class DeviceController {

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private IDeviceDictionaryService deviceDictionaryService;

    /**
     * Get the topology list of all online devices in one workspace.
     * @param workspaceId
     * @return
     */
    @GetMapping("/{workspace_id}/devices")
    public HttpResultResponse<List<DeviceDTO>> getDevices(@PathVariable("workspace_id") String workspaceId) {
        List<DeviceDTO> devicesList = deviceService.getDevicesTopoForWeb(workspaceId);

        return HttpResultResponse.success(devicesList);
    }

    /**
     * After binding the device to the workspace, the device data can only be seen on the web.
     * @param device
     * @param deviceSn
     * @return
     */
    @PostMapping("/{device_sn}/binding")
    public HttpResultResponse bindDevice(@RequestBody DeviceDTO device, @PathVariable("device_sn") String deviceSn) {
        device.setDeviceSn(deviceSn);
        boolean isUpd = deviceService.bindDevice(device);
        return isUpd ? HttpResultResponse.success() : HttpResultResponse.error();
    }

    /**
     * Obtain device information according to device sn.
     * @param workspaceId
     * @param deviceSn
     * @return
     */
    @GetMapping("/{workspace_id}/devices/{device_sn}")
    public HttpResultResponse getDevice(@PathVariable("workspace_id") String workspaceId,
                                        @PathVariable("device_sn") String deviceSn) {
        Optional<DeviceDTO> deviceOpt = deviceService.getDeviceBySn(deviceSn);
        return deviceOpt.isEmpty() ? HttpResultResponse.error("device not found.") : HttpResultResponse.success(deviceOpt.get());
    }

    /**
     * Obtain device information according to device sn.
     * @param workspaceId
     * @param deviceSn
     * @return
     */
    @GetMapping("/{workspace_id}/deviceInfo")
    public HttpResultResponse getDeviceInfo(@PathVariable("workspace_id") String workspaceId,
                                        @RequestParam("device_sn") String deviceSn) {
        Optional<DeviceDTO> deviceOpt = deviceService.getDeviceBySn(deviceSn);
        return deviceOpt.isEmpty() ? HttpResultResponse.error("device not found.") : HttpResultResponse.success(deviceOpt.get());
    }

    /**
     * Get the binding devices list in one workspace.
     * @param workspaceId
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/{workspace_id}/devices/bound")
    public HttpResultResponse<PaginationData<DeviceDTO>> getBoundDevicesWithDomain(
            @PathVariable("workspace_id") String workspaceId, Integer domain,
            @RequestParam(value = "device_name", required = false) String deviceName,
            @RequestParam(defaultValue = "1") Long page,
            @RequestParam(value = "page_size", defaultValue = "50") Long pageSize) {
        PaginationData<DeviceDTO> devices = deviceService.getBoundDevicesWithDomain(workspaceId, deviceName, page, pageSize, domain);

        return HttpResultResponse.success(devices);
    }

    /**
     * Removing the binding state of the device.
     * @param deviceSn
     * @return
     */
    @DeleteMapping("/{device_sn}/unbinding")
    public HttpResultResponse unbindingDevice(@PathVariable("device_sn") String deviceSn) {
        deviceService.unbindDevice(deviceSn);
        return HttpResultResponse.success();
    }

    /**
     * Update device information.
     * @param device
     * @param workspaceId
     * @param deviceSn
     * @return
     */
    @PutMapping("/{workspace_id}/devices/{device_sn}")
    public HttpResultResponse updateDevice(@RequestBody DeviceDTO device,
                                           @PathVariable("workspace_id") String workspaceId,
                                           @PathVariable("device_sn") String deviceSn) {
        device.setDeviceSn(deviceSn);
        boolean isUpd = deviceService.updateDevice(device);
        return isUpd ? HttpResultResponse.success() : HttpResultResponse.error();
    }

    /**
     * Delivers offline firmware upgrade tasks.
     * @param workspaceId
     * @param upgradeDTOS
     * @return
     */
    @PostMapping("/{workspace_id}/devices/ota")
    public HttpResultResponse createOtaJob(@PathVariable("workspace_id") String workspaceId,
                                           @RequestBody List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
        return deviceService.createDeviceOtaJob(workspaceId, upgradeDTOS);
    }

    /**
     * Set the property parameters of the drone.
     * @param workspaceId
     * @param dockSn
     * @param param
     * @return
     */
    @PutMapping("/{workspace_id}/devices/{device_sn}/property")
    public HttpResultResponse devicePropertySet(@PathVariable("workspace_id") String workspaceId,
                                                @PathVariable("device_sn") String dockSn,
                                                @RequestBody JsonNode param) {
        if (param.size() != 1) {
            return HttpResultResponse.error(CloudSDKErrorEnum.INVALID_PARAMETER);
        }

        int result = deviceService.devicePropertySet(workspaceId, dockSn, param);
        return PropertySetReplyResultEnum.SUCCESS.getResult() == result ?
                HttpResultResponse.success() : HttpResultResponse.error(result, String.valueOf(result));
    }

    /**
     * add the addAircraft to the workspace
     * @param aircraft
     * @return
     */
    @PostMapping("/{workspace_id}/addDrone")
    public HttpResultResponse addDrone(@RequestBody DeviceDTO aircraft, @PathVariable("workspace_id") String workspaceId) {
        aircraft.setWorkspaceId(workspaceId);
        boolean isAdd = deviceService.addDrone(aircraft);
        return isAdd ? HttpResultResponse.success() : HttpResultResponse.error();
    }

    /**
     * edit the addAircraft to the workspace
     * @param aircraft
     * @return
     */
    @PostMapping("/{workspace_id}/editDrone")
    public HttpResultResponse editDrone(@RequestBody DeviceDTO aircraft, @PathVariable("workspace_id") String workspaceId) {
        aircraft.setWorkspaceId(workspaceId);
        boolean isAdd = deviceService.editDrone(aircraft);
        return isAdd ? HttpResultResponse.success() : HttpResultResponse.error();
    }

    /**
     * add the addAirport to the workspace
     * @param airport
     * @return
     */
    @PostMapping("/{workspace_id}/addAirport")
    public HttpResultResponse addAirport(@RequestBody DeviceDTO airport, @PathVariable("workspace_id") String workspaceId) {
        airport.setWorkspaceId(workspaceId);
        boolean isAdd = deviceService.addAirport(airport);
        return isAdd ? HttpResultResponse.success() : HttpResultResponse.error();
    }
    /**
     * edit the addAirport to the workspace
     * @param airport
     * @return
     */
    @PostMapping("/{workspace_id}/editAirport")
    public HttpResultResponse editAirport(@RequestBody DeviceDTO airport, @PathVariable("workspace_id") String workspaceId) {
        airport.setWorkspaceId(workspaceId);
        boolean isAdd = deviceService.editAirport(airport);
        return isAdd ? HttpResultResponse.success() : HttpResultResponse.error();
    }


    /**
     * get device Dictionary
     * @param workspaceId
     * @return
     */
    @GetMapping("/{workspace_id}/deviceDictionary")
    public HttpResultResponse getDeviceDictionary(@PathVariable("workspace_id") String workspaceId,
                                                  @RequestParam(value = "domain", required = false) Integer domain) {

        List<DeviceDictionaryDTO> infoList = deviceDictionaryService.getDictionaryInfoList(domain);
        return CollectionUtils.isEmpty(infoList) ? HttpResultResponse.error("deviceDictionary not found.") : HttpResultResponse.success(infoList);
    }

    /**
     * Get the binding devices list in one workspace.
     * @param workspaceId
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/{workspace_id}/devices/list")
    public HttpResultResponse<PaginationData<DeviceDTO>> getDevicesByParam(
            DeviceSearchParam param,
            @PathVariable("workspace_id") String workspaceId,
            @RequestParam(defaultValue = "1") Long page,
            @RequestParam(value = "page_size", defaultValue = "50") Long pageSize) {
        PaginationData<DeviceDTO> devices = deviceService.getDevicesByParam(param, workspaceId, page, pageSize);

        return HttpResultResponse.success(devices);
    }

    /**
     * Removing the binding state of the device.
     * @param deviceSn
     * @return
     */
    @DeleteMapping("/{device_sn}/delete")
    public HttpResultResponse deleteDevice(@PathVariable("device_sn") String deviceSn) {
        deviceService.deleteDevice(deviceSn);
        return HttpResultResponse.success();
    }
    /**
     * Get the binding devices list in one workspace.
     * @param workspaceId
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/{workspace_id}/devices/noWorkspaceList")
    public HttpResultResponse<PaginationData<DeviceDTO>> getNoWorkspaceDevices(
            @PathVariable("workspace_id") String workspaceId,
            @RequestParam(value = "domain", required = false) Integer domain,
            @RequestParam(value = "device_name", required = false) String deviceName,
            @RequestParam(defaultValue = "1") Long page,
            @RequestParam(value = "page_size", defaultValue = "50") Long pageSize) {
        PaginationData<DeviceDTO> devices = deviceService.getNoWorkspaceDevices(workspaceId, deviceName, page, pageSize, domain);

        return HttpResultResponse.success(devices);
    }

    /**
     * Removing the device.
     * @param workspaceId
     * @param id
     * @return
     */
    @DeleteMapping("/{workspace_id}/deleteById")
    public HttpResultResponse deleteDeviceById(@PathVariable("workspace_id") String workspaceId,
                                               @RequestParam(name = "id") Integer id) {
        deviceService.deleteDeviceById(workspaceId, id);
        return HttpResultResponse.success();
    }

    /**
     * Get the binding devices list in one workspace.
     * @param workspaceId
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping("/{workspace_id}/devices/DockAndDroneList")
    public HttpResultResponse<PaginationData<DeviceDTO>> getDockAndDrone(
            @PathVariable("workspace_id") String workspaceId,
            @RequestParam(defaultValue = "1") Long page,
            @RequestParam(name = "page_size", defaultValue = "50") Long pageSize) {
        PaginationData<DeviceDTO> devices = deviceService.getDockAndDrone(workspaceId, page, pageSize);

        return HttpResultResponse.success(devices);
    }

    /**
     * share device to the org
     * @param device
     * @return
     */
    @PostMapping("/{workspace_id}/share")
    public HttpResultResponse shareDevice(@RequestBody DeviceDTO device, @PathVariable("workspace_id") String workspaceId) {
        device.setWorkspaceId(workspaceId);
        deviceService.shareDevice(device);
        return HttpResultResponse.success();
    }
    /**
     * cancel share device to the org
     * @param device
     * @return
     */
    @PostMapping("/{workspace_id}/cancelShare")
    public HttpResultResponse cancelShareDevice(@RequestBody DeviceDTO device, @PathVariable("workspace_id") String workspaceId) {
        device.setWorkspaceId(workspaceId);
        deviceService.cancelShareDevice(device);
        return HttpResultResponse.success();
    }

    /**
     * recover device online
     * @param device
     * @return
     */
    @PostMapping("/{workspace_id}/recoverOnline")
    public HttpResultResponse recoverOnline(@RequestBody DeviceDTO device, @PathVariable("workspace_id") String workspaceId) {

        deviceService.recoverDeviceOnline(device.getDeviceSn());
        return HttpResultResponse.success();
    }

}