package shop.alien.storeplatform.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import shop.alien.entity.result.R;
import shop.alien.entity.store.StoreImg;
import shop.alien.entity.store.excelVo.util.ExcelImage;
import shop.alien.mapper.StoreImgMapper;
import shop.alien.storeplatform.entity.StorePlatformBathFacility;
import shop.alien.storeplatform.entity.StorePlatformStoreMenu;
import shop.alien.storeplatform.feign.AlienStoreFeign;
import shop.alien.storeplatform.mapper.StorePlatformBathFacilityServiceMapper;
import shop.alien.storeplatform.service.StorePlatformBathFacilityService;
import shop.alien.storeplatform.vo.StorePlatformBathFacilityImportVo;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商户平台-洗浴设施及服务服务实现类
 *
 * @author system
 * @since 2025-01-XX
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class StorePlatformBathFacilityServiceImpl extends ServiceImpl<StorePlatformBathFacilityServiceMapper, StorePlatformBathFacility> implements StorePlatformBathFacilityService {

    private final StorePlatformBathFacilityServiceMapper facilityMapper;

    private final AlienStoreFeign alienStoreFeign;

    private final StoreImgMapper storeImgMapper;

    @Override
    public StorePlatformBathFacility getById(Integer id) {
        log.info("StorePlatformBathFacilityServiceImpl.getById id={}", id);
        if (id == null) {
            throw new RuntimeException("设施ID不能为空");
        }
        StorePlatformBathFacility facility = super.getById(id);
        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
                .eq(StoreImg::getStoreId, facility.getStoreId()).eq(StoreImg::getImgType, 29).in(StoreImg::getBusinessId, facility.getId()));

        if (CollectionUtil.isNotEmpty(imgList)) {
            facility.setImgUrl(imgList.get(0).getImgUrl());
        }
        return facility;
    }

    @Override
    public List<StorePlatformBathFacility> getListByStoreId(Integer storeId) {
        log.info("StorePlatformBathFacilityServiceImpl.getListByStoreId storeId={}", storeId);
        if (storeId == null) {
            throw new RuntimeException("门店ID不能为空");
        }
        LambdaQueryWrapper<StorePlatformBathFacility> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StorePlatformBathFacility::getStoreId, storeId)
                .eq(StorePlatformBathFacility::getDeleteFlag, 0)
                .orderByAsc(StorePlatformBathFacility::getFacilityCategory)
                .orderByAsc(StorePlatformBathFacility::getId);

        List<StorePlatformBathFacility> list = this.list(queryWrapper);

        // 查询图片
        List<Integer> ids = list.stream().map(StorePlatformBathFacility::getId).collect(Collectors.toList());
        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
                .eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 29).in(StoreImg::getBusinessId, ids));

        if (CollectionUtil.isNotEmpty(imgList)) {
            list.forEach(facility -> {
                imgList.stream()
                        .filter(img -> img.getBusinessId().equals(facility.getId()))
                        .findFirst()
                        .ifPresent(img -> facility.setImgUrl(img.getImgUrl()));
            });
        }
        return list;
    }

    @Override
    public List<StorePlatformBathFacility> getListByStoreIdAndCategory(Integer storeId, Integer facilityCategory) {
        log.info("StorePlatformBathFacilityServiceImpl.getListByStoreIdAndCategory storeId={}, facilityCategory={}", storeId, facilityCategory);
        if (storeId == null) {
            throw new RuntimeException("门店ID不能为空");
        }
        LambdaQueryWrapper<StorePlatformBathFacility> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StorePlatformBathFacility::getStoreId, storeId)
                .eq(StorePlatformBathFacility::getDeleteFlag, 0);
        if (facilityCategory != null) {
            queryWrapper.eq(StorePlatformBathFacility::getFacilityCategory, facilityCategory);
        }
        queryWrapper.orderByAsc(StorePlatformBathFacility::getFacilityCategory)
                .orderByAsc(StorePlatformBathFacility::getId);

        List<StorePlatformBathFacility> list = this.list(queryWrapper);

        // 查询图片
        List<Integer> ids = list.stream().map(StorePlatformBathFacility::getId).collect(Collectors.toList());
        List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>()
                .eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 29).in(StoreImg::getBusinessId, ids));

        if (CollectionUtil.isNotEmpty(imgList)) {
            list.forEach(facility -> {
                imgList.stream()
                        .filter(img -> img.getBusinessId().equals(facility.getId()))
                        .findFirst()
                        .ifPresent(img -> facility.setImgUrl(img.getImgUrl()));
            });
        }
        return list;
    }

    @Override
    public R<StorePlatformBathFacility> saveFacility(StorePlatformBathFacility facility) {
        log.info("StorePlatformBathFacilityServiceImpl.saveFacility facility={}", facility);
        if (facility == null) {
            return R.fail("设施信息不能为空");
        }
        if (facility.getStoreId() == null) {
            return R.fail("门店ID不能为空");
        }
        if (StringUtils.isEmpty(facility.getFacilityName())) {
            return R.fail("名称不能为空");
        }
        if (facility.getFacilityCategory() == null) {
            return R.fail("区域分类不能为空");
        }
        // 如果使用时间类型为选择时间，则必须填写开始和结束时间
        if (facility.getUsageTimeType() != null && facility.getUsageTimeType() == 1) {
            if (StringUtils.isEmpty(facility.getUsageStartTime()) || StringUtils.isEmpty(facility.getUsageEndTime())) {
                return R.fail("使用时间类型为选择时间时，开始时间和结束时间不能为空");
            }
        }

        boolean flag = this.save(facility);
        if (!flag) {
            return R.fail("新增设施失败");
        }
        return R.data(facility);
    }

    @Override
    public R<StorePlatformBathFacility> updateFacility(StorePlatformBathFacility facility) {
        log.info("StorePlatformBathFacilityServiceImpl.updateFacility facility={}", facility);
        if (facility == null || facility.getId() == null) {
            return R.fail("设施信息或设施ID不能为空");
        }
        if (StringUtils.isEmpty(facility.getFacilityName())) {
            return R.fail("名称不能为空");
        }
        if (facility.getFacilityCategory() == null) {
            return R.fail("区域分类不能为空");
        }
        // 如果使用时间类型为选择时间，则必须填写开始和结束时间
        if (facility.getUsageTimeType() != null && facility.getUsageTimeType() == 1) {
            if (StringUtils.isEmpty(facility.getUsageStartTime()) || StringUtils.isEmpty(facility.getUsageEndTime())) {
                return R.fail("使用时间类型为选择时间时，开始时间和结束时间不能为空");
            }
        }

        boolean flag = this.updateById(facility);
        if (!flag) {
            return R.fail("修改设施失败");
        }
        return R.data(facility);
    }

    @Override
    public R<StorePlatformBathFacility> saveOrUpdateFacility(StorePlatformBathFacility facility) {
        log.info("StorePlatformBathFacilityServiceImpl.saveOrUpdateFacility facility={}", facility);
        if (facility == null) {
            return R.fail("设施信息不能为空");
        }

        if (facility.getId() != null) {
            // 修改
            return updateFacility(facility);
        } else {
            // 新增
            return saveFacility(facility);
        }
    }

    @Override
    public R<String> deleteFacility(Integer id) {
        log.info("StorePlatformBathFacilityServiceImpl.deleteFacility id={}", id);
        if (id == null) {
            return R.fail("设施ID不能为空");
        }

        boolean flag = this.removeById(id);
        if (!flag) {
            return R.fail("删除设施失败");
        }
        return R.success("删除设施成功");
    }

    @Override
    public R<String> deleteFacilityBatch(List<Integer> ids) {
        log.info("StorePlatformBathFacilityServiceImpl.deleteFacilityBatch ids={}", ids);
        if (CollectionUtil.isEmpty(ids)) {
            return R.fail("设施ID列表不能为空");
        }

        boolean flag = this.removeByIds(ids);
        if (!flag) {
            return R.fail("批量删除设施失败");
        }
        return R.success("批量删除设施成功");
    }

    @Override
    public R<String> importFacilityFromExcel(MultipartFile file, Integer storeId) {
        log.info("StorePlatformBathFacilityServiceImpl.importFacilityFromExcel storeId={}", storeId);

        if (file == null || file.isEmpty()) {
            return R.fail("上传文件为空");
        }

        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
            return R.fail("文件格式不正确，请上传Excel文件");
        }

        if (storeId == null) {
            return R.fail("门店ID不能为空");
        }

        List<String> errorMessages = new ArrayList<>();
        int successCount = 0;
        int totalCount = 0;

        try (InputStream inputStream = file.getInputStream();
             XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);

            // 获取表头（假设表头在第5行，索引为5）
            Row headerRow = sheet.getRow(5);
            if (headerRow == null) {
                return R.fail("Excel文件格式不正确，缺少表头");
            }

            // 构建字段映射（表头名称 -> 列索引）
            Map<String, Integer> headerMap = new HashMap<>();
            Field[] fields = StorePlatformBathFacilityImportVo.class.getDeclaredFields();
            for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                Cell cell = headerRow.getCell(i);
                if (cell != null) {
                    String headerName = getCellValueAsString(cell);
                    if (StringUtils.isNotEmpty(headerName)) {
                        headerMap.put(headerName.trim(), i);
                    }
                }
            }

            // 获取图片映射（行索引 -> 图片字节数组）
            Map<Integer, byte[]> imageMap = extractImagesFromSheet(sheet);

            // 读取数据行（从第6行开始，索引为6）
            for (int rowIndex = 6; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) {
                    continue;
                }

                // 检查是否为空行
                boolean isEmptyRow = true;
                for (int i = 0; i < row.getLastCellNum(); i++) {
                    Cell cell = row.getCell(i);
                    if (cell != null && cell.getCellType() != CellType.BLANK) {
                        String cellValue = getCellValueAsString(cell);
                        if (StringUtils.isNotEmpty(cellValue)) {
                            isEmptyRow = false;
                            break;
                        }
                    }
                }
                if (isEmptyRow) {
                    continue;
                }

                totalCount++;
                StorePlatformBathFacilityImportVo excelVo = new StorePlatformBathFacilityImportVo();

                // 读取每个字段
                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    Integer colIndex = null;

                    // 根据字段名查找对应的表头
                    for (Map.Entry<String, Integer> entry : headerMap.entrySet()) {
                        String headerName = entry.getKey();
                        if (isFieldMatch(fieldName, headerName)) {
                            colIndex = entry.getValue();
                            break;
                        }
                    }

                    if (colIndex == null) {
                        continue;
                    }

                    Cell cell = row.getCell(colIndex);
                    if (cell == null && !field.isAnnotationPresent(ExcelImage.class)) {
                        continue;
                    }

                    try {
                        if (field.isAnnotationPresent(ExcelImage.class)) {
                            // 处理图片字段
                            byte[] imageBytes = imageMap.get(rowIndex);
                            if (imageBytes != null && imageBytes.length > 0) {
                                String imageName = "bathFacility_" + storeId + "_" + System.currentTimeMillis() + "_" + rowIndex + ".jpg";
                                MultipartFile multipartFile = new ByteArrayMultipartFile(imageBytes, imageName);
                                JSONObject jsonObject = alienStoreFeign.uploadFile(multipartFile);
                                if (200 == jsonObject.getIntValue("code")) {
                                    field.set(excelVo, jsonObject.getJSONArray("data").get(0));
                                } else {
                                    field.set(excelVo, "");
                                }
                            }
                        } else {
                            // 处理普通字段
                            String cellValue = getCellValueAsString(cell);
                            if (StringUtils.isNotEmpty(cellValue)) {
                                setFieldValue(excelVo, field, cellValue.trim());
                            }
                        }
                    } catch (Exception e) {
                        log.warn("读取字段{}失败：{}", fieldName, e.getMessage());
                    }
                }

                // 处理导入数据
                try {
                    validateAndSaveFacility(excelVo, storeId, rowIndex + 1);
                    successCount++;
                } catch (Exception e) {
                    errorMessages.add(String.format("第%d行：%s", rowIndex + 1, e.getMessage()));
                    log.error("导入第{}行数据失败", rowIndex + 1, e);
                }
            }
        } catch (Exception e) {
            log.error("导入Excel失败", e);
            return R.fail("导入失败：" + e.getMessage());
        }

        // 构建返回消息
        StringBuilder message = new StringBuilder();
        message.append(String.format("导入完成：成功%d条，失败%d条", successCount, totalCount - successCount));
        if (!errorMessages.isEmpty()) {
            message.append("\n失败详情：\n");
            for (int i = 0; i < Math.min(errorMessages.size(), 10); i++) {
                message.append(errorMessages.get(i)).append("\n");
            }
            if (errorMessages.size() > 10) {
                message.append("...还有").append(errorMessages.size() - 10).append("条错误信息");
            }
        }

        return R.success(message.toString());
    }

    /**
     * 判断字段名是否匹配表头
     */
    private boolean isFieldMatch(String fieldName, String headerName) {
        Map<String, String> fieldMapping = new HashMap<>();
        fieldMapping.put("facilityCategory", "区域(洗浴区/汗蒸区/休闲区/餐饮区)");
        fieldMapping.put("facilityName", "名称");
        fieldMapping.put("img", "图片");
        fieldMapping.put("chargingStandard", "收费标准（元）");
        fieldMapping.put("usageTimeType", "开放时间(全天/自定义时间)");
        fieldMapping.put("usageStartTime", "自定义开始时间");
        fieldMapping.put("usageEndTime", "自定义结束时间");
        fieldMapping.put("displayInStoreDetail", "状态（展示/隐藏）");

        String expectedHeader = fieldMapping.get(fieldName);
        return expectedHeader != null && expectedHeader.equals(headerName);
    }

    /**
     * 设置字段值
     */
    private void setFieldValue(StorePlatformBathFacilityImportVo excelVo, Field field, String cellValue) throws Exception {
        Class<?> fieldType = field.getType();
        String fieldName = field.getName();

        if (fieldType == Integer.class) {
            if ("facilityCategory".equals(fieldName)) {
                // 处理区域分类：洗浴区->1, 汗蒸区->2, 休闲区->3, 餐饮区->4
                String trimmedValue = cellValue.trim();
                if ("洗浴区".equals(trimmedValue)) {
                    field.set(excelVo, 1);
                } else if ("汗蒸区".equals(trimmedValue)) {
                    field.set(excelVo, 2);
                } else if ("休闲区".equals(trimmedValue)) {
                    field.set(excelVo, 3);
                } else if ("餐饮区".equals(trimmedValue)) {
                    field.set(excelVo, 4);
                } else {
                    throw new RuntimeException("区域分类格式错误，请输入'洗浴区'、'汗蒸区'、'休闲区'或'餐饮区'");
                }
            } else if ("usageTimeType".equals(fieldName)) {
                // 处理开放时间：全天->0, 自定义时间->1
                String trimmedValue = cellValue.trim();
                if ("全天".equals(trimmedValue)) {
                    field.set(excelVo, 0);
                } else if ("自定义时间".equals(trimmedValue)) {
                    field.set(excelVo, 1);
                } else {
                    throw new RuntimeException("开放时间格式错误，请输入'全天'或'自定义时间'");
                }
            } else if ("displayInStoreDetail".equals(fieldName)) {
                // 处理状态：展示->1, 隐藏->0
                String trimmedValue = cellValue.trim();
                if ("展示".equals(trimmedValue)) {
                    field.set(excelVo, 1);
                } else if ("隐藏".equals(trimmedValue)) {
                    field.set(excelVo, 0);
                } else {
                    throw new RuntimeException("状态字段格式错误，请输入'展示'或'隐藏'");
                }
            } else {
                // 其他Integer字段直接解析
                try {
                    field.set(excelVo, Integer.parseInt(cellValue));
                } catch (NumberFormatException e) {
                    throw new RuntimeException(fieldName + "字段格式错误，请输入数字");
                }
            }
        } else {
            // String类型
            field.set(excelVo, cellValue);
        }
    }

    /**
     * 校验并保存设施
     */
    private void validateAndSaveFacility(StorePlatformBathFacilityImportVo excelVo, Integer storeId, int rowNum) {
        // 校验必填字段
        if (StringUtils.isEmpty(excelVo.getFacilityName())) {
            throw new RuntimeException("名称不能为空");
        }
        if (excelVo.getFacilityCategory() == null) {
            throw new RuntimeException("区域分类不能为空");
        }

        // 校验开放时间和自定义时间段
        Integer usageTimeType = excelVo.getUsageTimeType() != null ? excelVo.getUsageTimeType() : 0;
        String usageStartTime = excelVo.getUsageStartTime();
        String usageEndTime = excelVo.getUsageEndTime();

        if (usageTimeType == 0) {
            // 全天：自定义开始时间和结束时间应该为空
            if (StringUtils.isNotEmpty(usageStartTime) || StringUtils.isNotEmpty(usageEndTime)) {
                throw new RuntimeException("开放时间为'全天'时，自定义开始时间和结束时间不能填写");
            }
        } else if (usageTimeType == 1) {
            // 自定义时间：自定义开始时间和结束时间必须填写
            if (StringUtils.isEmpty(usageStartTime)) {
                throw new RuntimeException("开放时间为'自定义时间'时，自定义开始时间不能为空");
            }
            if (StringUtils.isEmpty(usageEndTime)) {
                throw new RuntimeException("开放时间为'自定义时间'时，自定义结束时间不能为空");
            }
            // 校验时间格式：HH:mm
            if (!isValidTimeFormat(usageStartTime)) {
                throw new RuntimeException("自定义开始时间格式错误，请输入'HH:mm'格式，如'16:00'");
            }
            if (!isValidTimeFormat(usageEndTime)) {
                throw new RuntimeException("自定义结束时间格式错误，请输入'HH:mm'格式，如'18:00'");
            }
        }

        // 创建StorePlatformBathFacility对象
        StorePlatformBathFacility facility = new StorePlatformBathFacility();
        facility.setStoreId(storeId);
        facility.setFacilityCategory(excelVo.getFacilityCategory());
        facility.setFacilityName(excelVo.getFacilityName());
        facility.setChargingStandard(excelVo.getChargingStandard());
        facility.setUsageTimeType(usageTimeType);
        facility.setDisplayInStoreDetail(excelVo.getDisplayInStoreDetail() != null ? excelVo.getDisplayInStoreDetail() : 0);

        // 设置开始和结束时间
        if (usageTimeType == 1) {
            facility.setUsageStartTime(usageStartTime);
            facility.setUsageEndTime(usageEndTime);
        } else {
            facility.setUsageStartTime(null);
            facility.setUsageEndTime(null);
        }

        // 保存设施
        boolean flag = this.save(facility);

        // 处理图片
        if (StringUtils.isNotEmpty(excelVo.getImg())) {
            StoreImg storeImg = new StoreImg();
            storeImg.setStoreId(storeId);
            storeImg.setImgType(29); // 菜单图片类型
            storeImg.setImgUrl(excelVo.getImg());
            storeImg.setBusinessId(facility.getId());
            storeImgMapper.insert(storeImg);
        }
        if (!flag) {
            throw new RuntimeException("保存设施失败");
        }
    }

    /**
     * 校验时间格式是否为 HH:mm
     */
    private boolean isValidTimeFormat(String time) {
        if (StringUtils.isEmpty(time)) {
            return false;
        }
        // 格式：HH:mm (00:00-23:59)
        String timePattern = "^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$";
        return time.matches(timePattern);
    }

    /**
     * 获取单元格值（字符串格式）
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return null;
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 处理数字，避免科学计数法
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue) {
                        return String.valueOf((long) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return null;
        }
    }

    /**
     * 从Sheet中提取图片
     */
    private Map<Integer, byte[]> extractImagesFromSheet(Sheet sheet) {
        Map<Integer, byte[]> imageMap = new HashMap<>();
        if (sheet instanceof XSSFSheet) {
            XSSFSheet xssfSheet = (XSSFSheet) sheet;
            XSSFDrawing drawing = xssfSheet.getDrawingPatriarch();
            if (drawing != null) {
                List<XSSFShape> shapes = drawing.getShapes();
                for (XSSFShape shape : shapes) {
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
                        XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
                        int rowIndex = anchor.getRow1();
                        try {
                            // 直接使用 getData() 方法获取图片字节数组
                            byte[] imageBytes = picture.getPictureData().getData();
                            imageMap.put(rowIndex, imageBytes);
                        } catch (Exception e) {
                            log.warn("提取第{}行图片失败：{}", rowIndex, e.getMessage());
                        }
                    }
                }
            }
        }
        return imageMap;
    }

    /**
     * 临时MultipartFile实现类，用于上传字节数组
     */
    private static class ByteArrayMultipartFile implements MultipartFile {
        private final byte[] content;
        private final String fileName;

        public ByteArrayMultipartFile(byte[] content, String fileName) {
            this.content = content;
            this.fileName = fileName;
        }

        @Override
        public String getName() {
            return "file";
        }

        @Override
        public String getOriginalFilename() {
            return fileName;
        }

        @Override
        public String getContentType() {
            return "image/jpeg";
        }

        @Override
        public boolean isEmpty() {
            return content == null || content.length == 0;
        }

        @Override
        public long getSize() {
            return content.length;
        }

        @Override
        public byte[] getBytes() throws IOException {
            return content;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(content);
        }

        @Override
        public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
            java.nio.file.Files.write(dest.toPath(), content);
        }
    }

}
