package com.fuyuanshen.equipment.controller;


import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.core.utils.file.FileUtil;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.customer.mapper.CustomerMapper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.DeviceType;
import com.fuyuanshen.equipment.domain.dto.DeviceExcelImportDTO;
import com.fuyuanshen.equipment.domain.dto.ImportResult;
import com.fuyuanshen.equipment.domain.form.DeviceForm;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.excel.DeviceImportParams;
import com.fuyuanshen.equipment.excel.HeadValidateListener;
import com.fuyuanshen.equipment.excel.UploadDeviceDataListener;
import com.fuyuanshen.equipment.mapper.DeviceMapper;
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
import com.fuyuanshen.equipment.service.DeviceService;
import com.fuyuanshen.equipment.service.DeviceTypeService;
import com.fuyuanshen.equipment.service.impl.DeviceExportService;
import com.fuyuanshen.system.service.ISysOssService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.undertow.util.BadRequestException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Description:
 * @Author: WY
 * @Date: 2025/5/16
 **/
@Slf4j
@Tag(name = "web:设备管理", description = "web:设备管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/device")
public class DeviceController extends BaseController {

    private final ISysOssService ossService;
    private final DeviceService deviceService;
    private final DeviceMapper deviceMapper;
    private final CustomerMapper customerMapper;
    private final DeviceTypeService deviceTypeService;
    private final DeviceTypeMapper deviceTypeMapper;

    private final DeviceExportService exportService;


    @Operation(summary = "分页查询设备列表", security = {@SecurityRequirement(name = "bearer-key")})
    @GetMapping
    public TableDataInfo<Device> queryDevice(DeviceQueryCriteria criteria) throws IOException {
        Page<Device> page = new Page<>(criteria.getPageNum(), criteria.getPageSize());
        return deviceService.queryAll(criteria, page);
    }

    @GetMapping(value = "/pageTerminal")
    public TableDataInfo<Device> deviceFenecSelect(DeviceQueryCriteria criteria) throws IOException {
        Page<Device> page = new Page<>(criteria.getPageNum(), criteria.getPageSize());
        return deviceService.queryAllTerminal(criteria, page);
    }


    // @Log("新增设备")
    @Operation(summary = "新增设备")
    @PostMapping(value = "/add")
    public R<Void> addDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
        try {
            deviceService.addDevice(deviceForm);
        } catch (Exception e) {
            log.error("addDevice error: " + e.getMessage());
            return R.fail(e.getMessage());
        }
        return R.ok();
    }


    // @Log("修改设备")
    @Operation(summary = "修改设备")
    @PutMapping(value = "/update")
    public R<Void> updateDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
        try {
            deviceService.update(deviceForm);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("updateDevice error: " + e.getMessage());
            return R.fail(e.getMessage());
        }
        return R.ok();
    }


    @Operation(summary = "设备详情")
    @GetMapping(value = "/detail/{id}")
    public R<Device> getDevice(@PathVariable Long id) {
        Device device = deviceService.getById(id);
        return R.ok(device);
    }


    // @Log("删除设备")
    @Operation(summary = "删除设备")
    @DeleteMapping(value = "/delete")
    public R<Void> deleteDevice(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) {
        deviceService.deleteAll(ids);
        return R.ok();
    }


    @Operation(summary = "设备定位")
    @GetMapping(value = "/locateDevice")
    public R<List<Device>> locateDevice(DeviceQueryCriteria criteria) throws IOException {
        List<Device> devices = deviceService.queryAllDevices(criteria);
        return R.ok(devices);
    }


    // @Log("分配客户")
    // @Operation(summary = "分配客户")
    // @PutMapping(value = "/assignCustomer")
    // public R<Void> assignCustomer(@Validated @RequestBody CustomerVo customerVo) {
    //     deviceService.assignCustomer(customerVo);
    //     return R.ok();
    // }


    // @Log("撤回设备")
    // @Operation(summary = "撤回分配设备")
    // @PostMapping(value = "/withdraw")
    // public R<Void> withdrawDevice(@RequestBody List<Long> ids) {
    //     try {
    //         deviceService.withdrawDevice(ids);
    //     } catch (Exception e) {
    //         log.error("updateDevice error: " + e.getMessage());
    //         return R.fail(e.getMessage());
    //     }
    //     return R.ok();
    // }

    //
    // /**
    //  * @param id
    //  * @return
    //  * @ModelAttribute 主要用于将请求参数绑定到 Java 对象上，它会从 HTTP 请求的查询参数（Query Parameters）
    //  * 或表单数据（Form Data）中提取值，并自动填充到指定的对象属性中。
    //  */
    // // @Log("解绑设备")
    // @Operation(summary = "WEB端解绑设备")
    // @GetMapping(value = "/unbind")
    // public R<Void> unbindDevice(@Validated Long id) {
    //     return toAjax(deviceService.webUnBindDevice(id));
    // }


    @Operation(summary = "导出数据设备")
    @GetMapping(value = "/download1")
    public R<Void> exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException {
        List<Device> devices = deviceService.queryAll(criteria);
        exportService.export(devices, response);
        return R.ok();
    }


    /**
     * 导出设备数据（包含完整设备类型信息）
     *
     * @param response HttpServletResponse对象
     * @param criteria 查询条件
     * @return R<Void>
     */
    @Operation(summary = "导出设备数据（包含完整设备类型信息）")
    @GetMapping(value = "/download")
    public R<Void> exportDeviceWithFullTypeInfo(HttpServletResponse response, DeviceQueryCriteria criteria) {
        // 获取所有符合条件的设备
        List<Device> devices = deviceService.queryAll(criteria);
        // 获取所有设备类型信息
        List<DeviceType> deviceTypes = deviceTypeService.queryDeviceTypes();
        // 导出数据（包含完整设备类型信息）
        exportService.exportWithTypeInfo(devices, deviceTypes, response);
        return R.ok();
    }


    /**
     * 导入设备数据
     *
     * @param file
     * @return
     * @throws BadRequestException
     */
    @Operation(summary = "导入设备数据")
    @PostMapping(value = "/import1", consumes = "multipart/form-data")
    public R<ImportResult> importData1(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) throws BadRequestException {

        String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
        if (!("xlsx".equalsIgnoreCase(suffix))) {
            throw new BadRequestException("只能上传Excel——xlsx格式文件");
        }

        ImportResult result = new ImportResult();
        try {
            LoginUser loginUser = LoginHelper.getLoginUser();
            DeviceImportParams params = DeviceImportParams.builder().ossService(ossService)
                    .deviceService(deviceService).tenantId(loginUser.getTenantId())
                    .file(file).filePath("").deviceMapper(deviceMapper).deviceTypeService(deviceTypeService)
                    .deviceTypeMapper(deviceTypeMapper).userId(loginUser.getUserId())
                    .customerMapper(customerMapper).build();
            // 创建监听器
            UploadDeviceDataListener listener = new UploadDeviceDataListener(params);
            // 读取Excel
            EasyExcel.read(file.getInputStream(), DeviceExcelImportDTO.class, listener).sheet().doRead();
            // 获取导入结果
            result = listener.getImportResult();
            // 设置响应消息
            String message = String.format("成功导入 %d 条数据，失败 %d 条", result.getSuccessCount(), result.getFailureCount());
            // 返回带有正确泛型的响应
            return R.ok(message, result);
        } catch (Exception e) {
            log.error("导入设备数据出错: {}", e.getMessage(), e);
            // 在异常情况下，设置默认结果
            String errorMessage = String.format("导入失败: %s。成功 %d 条，失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount());
            // 使用新方法确保类型正确
            return R.fail(errorMessage, result);
        }
    }


    /**
     * 导入设备数据
     *
     * @param file 文件
     * @return R<ImportResult>
     */
    @Operation(summary = "导入设备数据")
    @PostMapping(value = "/import", consumes = "multipart/form-data")
    public R<ImportResult> importData(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) throws BadRequestException {

        String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
        if (!("xlsx".equalsIgnoreCase(suffix))) {
            throw new BadRequestException("只能上传Excel——xlsx格式文件");
        }

        // 检查文件大小，限制为100MB
        if (file.getSize() > 100 * 10 * 1024 * 1024) {
            throw new BadRequestException("文件大小不能超过100MB");
        }

        // 校验模板
        validateExcelTemplate(file);

        ImportResult result = new ImportResult();
        try {
            LoginUser loginUser = LoginHelper.getLoginUser();
            DeviceImportParams params = DeviceImportParams.builder().ossService(ossService)
                    .deviceService(deviceService).tenantId(loginUser.getTenantId())
                    .file(file).filePath("").deviceMapper(deviceMapper).deviceTypeService(deviceTypeService)
                    .deviceTypeMapper(deviceTypeMapper).userId(loginUser.getUserId())
                    .build();
            // 创建监听器
            UploadDeviceDataListener listener = new UploadDeviceDataListener(params);
            // 读取Excel
            EasyExcel.read(file.getInputStream(), DeviceExcelImportDTO.class, listener).sheet().doRead();
            // 获取导入结果
            result = listener.getImportResult();
            // 设置响应消息
            String message = String.format("成功导入 %d 条数据，失败 %d 条", result.getSuccessCount(), result.getFailureCount());
            // 返回带有正确泛型的响应
            return R.ok(message, result);
        } catch (Exception e) {
            log.error("导入设备数据出错: {}", e.getMessage(), e);
            // 在异常情况下，设置默认结果
            String errorMessage = String.format("导入失败: %s。成功 %d 条，失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount());
            // 使用新方法确保类型正确
            return R.fail(errorMessage, result);
        }
    }


    /**
     * 校验Excel模板是否正确
     *
     * @param file MultipartFile对象
     * @throws BadRequestException 当模板不正确时抛出异常
     */
    private void validateExcelTemplate(MultipartFile file) throws BadRequestException {
        try {
            // 创建一个只读取表头的监听器
            HeadValidateListener headValidateListener = new HeadValidateListener();

            // 使用EasyExcel读取表头
            EasyExcel.read(file.getInputStream(), headValidateListener)
                    .sheet()
                    .headRowNumber(0)
                    .doRead();

            // 获取读取到的表头信息
            List<String> actualHeaders = headValidateListener.getHeadNames();

            // 定义必需的表头
            Set<String> requiredHeaders = new HashSet<>(Arrays.asList(
                    "设备名称", "设备类型名称", "设备图片", "设备MAC", "蓝牙名称", "设备IMEI",
                    "备注", "是否支持蓝牙", "定位方式", "通讯方式",
                    "型号字典用于APP页面跳转", "型号字典用于PC页面跳转"
            ));

            // 检查必需的表头是否都存在
            Set<String> actualHeaderSet = new HashSet<>(actualHeaders);
            if (!actualHeaderSet.containsAll(requiredHeaders)) {
                requiredHeaders.removeAll(actualHeaderSet);
                throw new BadRequestException("Excel模板缺少必需的列: " + String.join(", ", requiredHeaders));
            }

            // 检查第三列（索引为2）是否为"设备图片"
            if (actualHeaders.size() > 2 && !"设备图片".equals(actualHeaders.get(2))) {
                throw new BadRequestException("Excel模板不正确，第三列必须是'设备图片'列");
            }
        } catch (BadRequestException e) {
            throw e; // 直接重新抛出
        } catch (Exception e) {
            log.error("校验Excel模板时发生错误: {}", e.getMessage(), e);
            throw new BadRequestException("校验Excel模板时发生错误: " + e.getMessage());
        }
    }


}


