package com.ycwl.basic.controller.pc;

import com.ycwl.basic.integration.device.dto.config.*;
import com.ycwl.basic.integration.common.response.PageResponse;
import com.ycwl.basic.integration.device.dto.device.*;
import com.ycwl.basic.integration.device.dto.status.DeviceStatusDTO;
import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.service.DeviceStatusIntegrationService;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.device.resp.DeviceSourceStatsVO;
import com.ycwl.basic.model.pc.device.resp.DeviceSourceTimelineVO;
import com.ycwl.basic.utils.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 设备管理 V2 版本控制器 - 基于 zt-device 集成服务
 * 
 * @author Claude Code
 * @date 2025-09-01
 */
@Slf4j
@RestController
@RequestMapping("/api/device/v2")
@RequiredArgsConstructor
public class DeviceV2Controller {

    private final DeviceIntegrationService deviceIntegrationService;
    private final DeviceConfigIntegrationService deviceConfigIntegrationService;
    private final DeviceStatusIntegrationService deviceStatusIntegrationService;
    private final SourceMapper sourceMapper;

    // ========== 设备基础 CRUD 操作 ==========

    /**
     * 设备V2核心信息分页列表
     */
    @GetMapping("/")
    public ApiResponse<PageResponse<DeviceV2DTO>> listDevices(@RequestParam(defaultValue = "1") Integer page,
                                                        @RequestParam(defaultValue = "10") Integer pageSize,
                                                        @RequestParam(required = false) String name,
                                                        @RequestParam(required = false) String no,
                                                        @RequestParam(required = false) String type,
                                                        @RequestParam(required = false) Integer isActive,
                                                        @RequestParam(required = false) Long scenicId) {
        log.info("分页查询设备核心信息列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", 
                page, pageSize, name, no, type, isActive, scenicId);
        
        // 参数验证：限制pageSize最大值为100
        if (pageSize > 100) {
            pageSize = 100;
        }

        try {
            PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId, null);
            return ApiResponse.success(response);
        } catch (Exception e) {
            log.error("分页查询设备核心信息列表失败", e);
            return ApiResponse.fail("分页查询设备列表失败: " + e.getMessage());
        }
    }

    /**
     * 根据ID获取设备信息
     */
    @GetMapping("/{id}")
    public ApiResponse<DeviceV2DTO> getDevice(@PathVariable Long id) {
        try {
            DeviceV2DTO device = deviceIntegrationService.getDevice(id);
            return ApiResponse.success(device);
        } catch (Exception e) {
            log.error("获取设备信息失败, id: {}", id, e);
            return ApiResponse.fail("获取设备信息失败: " + e.getMessage());
        }
    }

    /**
     * 根据设备编号获取设备信息
     */
    @GetMapping("/no/{no}")
    public ApiResponse<DeviceV2DTO> getDeviceByNo(@PathVariable String no) {
        try {
            DeviceV2DTO device = deviceIntegrationService.getDeviceByNo(no);
            return ApiResponse.success(device);
        } catch (Exception e) {
            log.error("根据设备编号获取设备信息失败, no: {}", no, e);
            return ApiResponse.fail("根据设备编号获取设备信息失败: " + e.getMessage());
        }
    }

    /**
     * 根据设备ID获取设备在线状态
     */
    @GetMapping("/{id}/status")
    public ApiResponse<DeviceStatusDTO> getDeviceOnlineStatus(@PathVariable Long id) {
        log.info("获取设备在线状态, deviceId: {}", id);
        try {
            // 首先获取设备信息以获得设备编号
            DeviceV2DTO device = deviceIntegrationService.getDevice(id);
            if (device == null) {
                return ApiResponse.fail("设备不存在");
            }
            
            // 使用设备编号查询在线状态
            DeviceStatusDTO onlineStatus = deviceStatusIntegrationService.getDeviceStatus(device.getNo());
            return ApiResponse.success(onlineStatus);
        } catch (Exception e) {
            log.error("获取设备在线状态失败, deviceId: {}", id, e);
            return ApiResponse.fail("获取设备在线状态失败: " + e.getMessage());
        }
    }

    /**
     * 创建设备
     */
    @PostMapping("/")
    public ApiResponse<DeviceV2DTO> createDevice(@Valid @RequestBody CreateDeviceRequest request) {
        log.info("创建设备, name: {}, no: {}, type: {}, sort: {}", 
                request.getName(), request.getNo(), request.getType(), request.getSort());
        try {
            DeviceV2DTO device = deviceIntegrationService.createDevice(request);
            return ApiResponse.success(device);
        } catch (Exception e) {
            log.error("创建设备失败", e);
            return ApiResponse.fail("创建设备失败: " + e.getMessage());
        }
    }

    /**
     * 创建IPC摄像头设备（快捷方法）
     */
    @PostMapping("/ipc")
    public ApiResponse<DeviceV2DTO> createIpcDevice(@RequestBody Map<String, Object> request) {
        String name = (String) request.get("name");
        String deviceNo = (String) request.get("no");
        Long scenicId = Long.valueOf(request.get("scenicId").toString());
        Integer sort = request.get("sort") != null ? Integer.valueOf(request.get("sort").toString()) : null;
        
        log.info("创建IPC摄像头设备, name: {}, no: {}, scenicId: {}, sort: {}", name, deviceNo, scenicId, sort);
        try {
            DeviceV2DTO device;
            if (sort != null) {
                device = deviceIntegrationService.createIpcDeviceWithSort(name, deviceNo, scenicId, sort);
            } else {
                device = deviceIntegrationService.createIpcDevice(name, deviceNo, scenicId);
            }
            return ApiResponse.success(device);
        } catch (Exception e) {
            log.error("创建IPC摄像头设备失败", e);
            return ApiResponse.fail("创建IPC摄像头设备失败: " + e.getMessage());
        }
    }

    /**
     * 创建自定义设备（快捷方法）
     */
    @PostMapping("/custom")
    public ApiResponse<DeviceV2DTO> createCustomDevice(@RequestBody Map<String, Object> request) {
        String name = (String) request.get("name");
        String deviceNo = (String) request.get("no");
        Long scenicId = Long.valueOf(request.get("scenicId").toString());
        Integer sort = request.get("sort") != null ? Integer.valueOf(request.get("sort").toString()) : null;
        
        log.info("创建自定义设备, name: {}, no: {}, scenicId: {}, sort: {}", name, deviceNo, scenicId, sort);
        try {
            DeviceV2DTO device;
            if (sort != null) {
                device = deviceIntegrationService.createCustomDeviceWithSort(name, deviceNo, scenicId, sort);
            } else {
                device = deviceIntegrationService.createCustomDevice(name, deviceNo, scenicId);
            }
            return ApiResponse.success(device);
        } catch (Exception e) {
            log.error("创建自定义设备失败", e);
            return ApiResponse.fail("创建自定义设备失败: " + e.getMessage());
        }
    }

    /**
     * 更新设备信息
     */
    @PutMapping("/{id}")
    public ApiResponse<String> updateDevice(@PathVariable Long id, @Valid @RequestBody UpdateDeviceRequest request) {
        log.info("更新设备信息, id: {}", id);
        try {
            deviceIntegrationService.updateDevice(id, request);
            return ApiResponse.success("设备信息更新成功");
        } catch (Exception e) {
            log.error("更新设备信息失败, id: {}", id, e);
            return ApiResponse.fail("更新设备信息失败: " + e.getMessage());
        }
    }

    /**
     * 更新设备排序
     */
    @PutMapping("/{id}/sort")
    public ApiResponse<String> updateDeviceSort(@PathVariable Long id, @RequestBody Map<String, Integer> request) {
        Integer sort = request.get("sort");
        log.info("更新设备排序, id: {}, sort: {}", id, sort);
        try {
            deviceIntegrationService.updateDeviceSort(id, sort);
            return ApiResponse.success("设备排序更新成功");
        } catch (Exception e) {
            log.error("更新设备排序失败, id: {}, sort: {}", id, sort, e);
            return ApiResponse.fail("更新设备排序失败: " + e.getMessage());
        }
    }

    /**
     * 启用设备
     */
    @PutMapping("/{id}/enable")
    public ApiResponse<String> enableDevice(@PathVariable Long id) {
        log.info("启用设备, id: {}", id);
        try {
            deviceIntegrationService.enableDevice(id);
            return ApiResponse.success("设备启用成功");
        } catch (Exception e) {
            log.error("启用设备失败, id: {}", id, e);
            return ApiResponse.fail("启用设备失败: " + e.getMessage());
        }
    }

    /**
     * 禁用设备
     */
    @PutMapping("/{id}/disable")
    public ApiResponse<String> disableDevice(@PathVariable Long id) {
        log.info("禁用设备, id: {}", id);
        try {
            deviceIntegrationService.disableDevice(id);
            return ApiResponse.success("设备禁用成功");
        } catch (Exception e) {
            log.error("禁用设备失败, id: {}", id, e);
            return ApiResponse.fail("禁用设备失败: " + e.getMessage());
        }
    }

    /**
     * 删除设备
     */
    @DeleteMapping("/{id}")
    public ApiResponse<String> deleteDevice(@PathVariable Long id) {
        log.info("删除设备, id: {}", id);
        try {
            deviceIntegrationService.deleteDevice(id);
            return ApiResponse.success("设备删除成功");
        } catch (Exception e) {
            log.error("删除设备失败, id: {}", id, e);
            return ApiResponse.fail("删除设备失败: " + e.getMessage());
        }
    }

    // ========== 设备配置管理操作 ==========

    /**
     * 获取设备配置列表
     */
    @GetMapping("/{id}/config")
    public ApiResponse<List<DeviceConfigV2DTO>> getDeviceConfigs(@PathVariable Long id) {
        try {
            List<DeviceConfigV2DTO> configs = deviceConfigIntegrationService.getDeviceConfigs(id);
            return ApiResponse.success(configs);
        } catch (Exception e) {
            log.error("获取设备配置列表失败, deviceId: {}", id, e);
            return ApiResponse.fail("获取设备配置列表失败: " + e.getMessage());
        }
    }

    /**
     * 根据配置键获取配置
     */
    @GetMapping("/{id}/config/{configKey}")
    public ApiResponse<DeviceConfigV2DTO> getDeviceConfigByKey(@PathVariable Long id, 
                                                              @PathVariable String configKey) {
        try {
            DeviceConfigV2DTO config = deviceConfigIntegrationService.getDeviceConfigByKey(id, configKey);
            return ApiResponse.success(config);
        } catch (Exception e) {
            log.error("根据键获取设备配置失败, deviceId: {}, configKey: {}", id, configKey, e);
            return ApiResponse.fail("根据键获取设备配置失败: " + e.getMessage());
        }
    }

    /**
     * 根据设备编号获取配置列表
     */
    @GetMapping("/no/{no}/config")
    public ApiResponse<List<DeviceConfigV2DTO>> getDeviceConfigsByNo(@PathVariable String no) {
        log.info("根据设备编号获取配置列表, deviceNo: {}", no);
        try {
            List<DeviceConfigV2DTO> configs = deviceConfigIntegrationService.getDeviceConfigsByNo(no);
            return ApiResponse.success(configs);
        } catch (Exception e) {
            log.error("根据设备编号获取配置列表失败, deviceNo: {}", no, e);
            return ApiResponse.fail("根据设备编号获取配置列表失败: " + e.getMessage());
        }
    }

    /**
     * 创建设备配置
     */
    @PostMapping("/{id}/config")
    public ApiResponse<DeviceConfigV2DTO> createDeviceConfig(@PathVariable Long id, 
                                                           @Valid @RequestBody CreateDeviceConfigRequest request) {
        log.info("创建设备配置, deviceId: {}, configKey: {}", id, request.getConfigKey());
        try {
            DeviceConfigV2DTO config = deviceConfigIntegrationService.createDeviceConfig(id, request);
            return ApiResponse.success(config);
        } catch (Exception e) {
            log.error("创建设备配置失败, deviceId: {}, configKey: {}", id, request.getConfigKey(), e);
            return ApiResponse.fail("创建设备配置失败: " + e.getMessage());
        }
    }

    /**
     * 批量创建/更新设备配置
     */
    @PostMapping("/{id}/config/batch")
    public ApiResponse<BatchUpdateResponse> batchUpdateDeviceConfig(@PathVariable Long id, 
                                                                   @Valid @RequestBody BatchDeviceConfigRequest request) {
        log.info("批量更新设备配置, deviceId: {}, configs count: {}", id, request.getConfigs().size());
        try {
            BatchUpdateResponse result = deviceConfigIntegrationService.batchUpdateDeviceConfig(id, request);
            return ApiResponse.success(result);
        } catch (Exception e) {
            log.error("批量更新设备配置失败, deviceId: {}", id, e);
            return ApiResponse.fail("批量更新设备配置失败: " + e.getMessage());
        }
    }


    /**
     * 更新设备配置
     */
    @PutMapping("/{id}/config/{configId}")
    public ApiResponse<String> updateDeviceConfig(@PathVariable Long id, @PathVariable Long configId,
                                                 @Valid @RequestBody UpdateDeviceConfigRequest request) {
        log.info("更新设备配置, deviceId: {}, configId: {}", id, configId);
        try {
            deviceConfigIntegrationService.updateDeviceConfig(id, configId, request);
            return ApiResponse.success("设备配置更新成功");
        } catch (Exception e) {
            log.error("更新设备配置失败, deviceId: {}, configId: {}", id, configId, e);
            return ApiResponse.fail("更新设备配置失败: " + e.getMessage());
        }
    }


    /**
     * 删除设备配置
     */
    @DeleteMapping("/{id}/config/{configId}")
    public ApiResponse<String> deleteDeviceConfig(@PathVariable Long id, @PathVariable Long configId) {
        log.info("删除设备配置, deviceId: {}, configId: {}", id, configId);
        try {
            deviceConfigIntegrationService.deleteDeviceConfig(id, configId);
            return ApiResponse.success("设备配置删除成功");
        } catch (Exception e) {
            log.error("删除设备配置失败, deviceId: {}, configId: {}", id, configId, e);
            return ApiResponse.fail("删除设备配置失败: " + e.getMessage());
        }
    }

    // ========== 景区设备管理操作 ==========

    /**
     * 获取景区所有设备列表
     */
    @GetMapping("/scenic/{scenicId}")
    public ApiResponse<PageResponse<DeviceV2DTO>> getScenicAllDevices(@PathVariable Long scenicId,
                                                               @RequestParam(required = false) String name,
                                                               @RequestParam(required = false) String type,
                                                               @RequestParam(required = false) String no,
                                                               @RequestParam(defaultValue = "1") Integer page,
                                                               @RequestParam(defaultValue = "10") Integer pageSize) {
        log.info("获取景区所有设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize);
        try {
            PageResponse<DeviceV2DTO> response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, null, scenicId, null);
            return ApiResponse.success(response);
        } catch (Exception e) {
            log.error("获取景区所有设备列表失败, scenicId: {}", scenicId, e);
            return ApiResponse.fail("获取景区所有设备列表失败: " + e.getMessage());
        }
    }

    // ========== 设备拍摄统计 ==========

    /**
     * 设备拍摄统计：拍摄总数、拍摄人数、售出张数、赠送张数、售出人数
     */
    @GetMapping("/{id}/source-stats")
    public ApiResponse<DeviceSourceStatsVO> getDeviceSourceStats(
            @PathVariable Long id,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
        try {
            java.util.Calendar cal = java.util.Calendar.getInstance();
            // startDate：归到当天 00:00:00（未传则默认今天）
            if (startDate != null) {
                cal.setTime(startDate);
            }
            cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
            cal.set(java.util.Calendar.MINUTE, 0);
            cal.set(java.util.Calendar.SECOND, 0);
            cal.set(java.util.Calendar.MILLISECOND, 0);
            startDate = cal.getTime();
            // endDate：归到当天 23:59:59（未传则取 startDate 同一天）
            if (endDate != null) {
                cal.setTime(endDate);
            }
            cal.set(java.util.Calendar.HOUR_OF_DAY, 23);
            cal.set(java.util.Calendar.MINUTE, 59);
            cal.set(java.util.Calendar.SECOND, 59);
            cal.set(java.util.Calendar.MILLISECOND, 999);
            endDate = cal.getTime();
            DeviceSourceStatsVO stats = sourceMapper.getDeviceSourceStats(id, startDate, endDate);
            return ApiResponse.success(stats);
        } catch (Exception e) {
            log.error("获取设备拍摄统计失败, deviceId: {}", id, e);
            return ApiResponse.fail("获取设备拍摄统计失败: " + e.getMessage());
        }
    }

    /**
     * 设备拍摄时间线：按 5 分钟分桶统计 type=2 的拍摄数量，空桶补 0
     */
    @GetMapping("/{id}/source-timeline")
    public ApiResponse<List<DeviceSourceTimelineVO>> getDeviceSourceTimeline(
            @PathVariable Long id,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
        try {
            java.util.Calendar cal = java.util.Calendar.getInstance();
            // startDate：归到当天 08:00:00（未传则默认今天）
            if (startDate != null) {
                cal.setTime(startDate);
            }
            cal.set(java.util.Calendar.HOUR_OF_DAY, 8);
            cal.set(java.util.Calendar.MINUTE, 0);
            cal.set(java.util.Calendar.SECOND, 0);
            cal.set(java.util.Calendar.MILLISECOND, 0);
            startDate = cal.getTime();
            // endDate：归到当天 19:59:59（未传则取 startDate 同一天）
            if (endDate != null) {
                cal.setTime(endDate);
            }
            cal.set(java.util.Calendar.HOUR_OF_DAY, 19);
            cal.set(java.util.Calendar.MINUTE, 59);
            cal.set(java.util.Calendar.SECOND, 59);
            cal.set(java.util.Calendar.MILLISECOND, 999);
            endDate = cal.getTime();

            // 查询有数据的桶
            List<DeviceSourceTimelineVO> rawData = sourceMapper.getDeviceSourceTimeline(id, startDate, endDate);

            // 将有数据的桶放入 Map，key 为对齐到 5 分钟的毫秒时间戳
            Map<Long, Integer> dataMap = new HashMap<>();
            for (DeviceSourceTimelineVO item : rawData) {
                long aligned = (item.getTime().getTime() / 300_000) * 300_000;
                dataMap.put(aligned, item.getCount());
            }

            // 生成完整时间轴并补零
            long startMs = (startDate.getTime() / 300_000) * 300_000;
            long endMs = endDate.getTime();
            List<DeviceSourceTimelineVO> timeline = new ArrayList<>();
            for (long ts = startMs; ts <= endMs; ts += 300_000) {
                timeline.add(new DeviceSourceTimelineVO(new Date(ts), dataMap.getOrDefault(ts, 0)));
            }

            return ApiResponse.success(timeline);
        } catch (Exception e) {
            log.error("获取设备拍摄时间线失败, deviceId: {}", id, e);
            return ApiResponse.fail("获取设备拍摄时间线失败: " + e.getMessage());
        }
    }
}