package com.jeeplus.hotelorder.dish.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jeeplus.hotelorder.dish.domain.*;
import com.jeeplus.hotelorder.dish.mapper.*;
import com.jeeplus.hotelorder.dish.service.dto.HotelDishDTO;
import com.jeeplus.hotelorder.order.domain.HotelOrder;
import com.jeeplus.hotelorder.order.mapper.HotelOrderMapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class HotelDishService extends ServiceImpl<HotelDishMapper, HotelDish> {

    private static final Logger log = LoggerFactory.getLogger(HotelDishService.class);

    @Resource
    private HotelDishMapper hotelDishMapper;

    @Resource
    private HotelDishSpecMapper hotelDishSpecMapper;

    @Resource
    private HotelDishSpecOptionMapper hotelDishSpecOptionMapper;

    @Resource
    private HotelDishAdditionMapper hotelDishAdditionMapper;

    @Resource
    private HotelDishCategoryMapper hotelDishCategoryMapper;

    @Resource
    private HotelDishLogMapper hotelDishLogMapper;

    @Resource
    private HotelOrderMapper hotelOrderMapper;

    private static final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 管理后台菜品分页查询(含分类名称)
     */
    public IPage<HotelDishDTO> findAdminPage(Page<HotelDish> page, HotelDishDTO queryDTO) {
        IPage<HotelDish> result = hotelDishMapper.selectAdminPage(page, queryDTO.getCategoryId(), queryDTO.getStatus(), queryDTO.getName());
        return convertToDtoPage(result);
    }

    /**
     * 客户端菜品列表(只查在售且未售罄)
     */
    public IPage<HotelDishDTO> findClientPage(Page<HotelDish> page, HotelDishDTO queryDTO) {
        IPage<HotelDish> result = hotelDishMapper.selectClientList(page, queryDTO.getCategoryId(), queryDTO.getKeyword());
        return convertToDtoPage(result);
    }

    /**
     * Entity分页结果转DTO分页结果
     */
    private IPage<HotelDishDTO> convertToDtoPage(IPage<HotelDish> result) {
        IPage<HotelDishDTO> dtoPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal());
        List<HotelDishDTO> dtoList = result.getRecords().stream().map(this::entityToDto).collect(Collectors.toList());
        dtoPage.setRecords(dtoList);
        return dtoPage;
    }

    /**
     * Entity转DTO
     */
    private HotelDishDTO entityToDto(HotelDish entity) {
        HotelDishDTO dto = new HotelDishDTO();
        dto.setId(entity.getId());
        dto.setName(entity.getName());
        dto.setCategoryId(entity.getCategoryId());
        dto.setPrice(entity.getPrice());
        dto.setImage(entity.getImage());
        dto.setDescription(entity.getDescription());
        dto.setTags(entity.getTags());
        dto.setPrepTime(entity.getPrepTime());
        dto.setSales(entity.getSales());
        dto.setStatus(entity.getStatus());
        dto.setSoldOut(entity.getSoldOut());
        dto.setIsRecommended(entity.getIsRecommended());
        dto.setSortOrder(entity.getSortOrder());
        dto.setCategoryName(entity.getCategoryName());
        dto.setSpecGroups(entity.getSpecGroups());
        dto.setAdditions(entity.getAdditions());
        dto.setCreateTime(entity.getCreateTime());
        dto.setUpdateTime(entity.getUpdateTime());
        return dto;
    }

    /**
     * DTO转Entity
     */
    private HotelDish dtoToEntity(HotelDishDTO dto) {
        HotelDish entity = new HotelDish();
        entity.setId(dto.getId());
        entity.setName(dto.getName());
        entity.setCategoryId(dto.getCategoryId());
        entity.setPrice(dto.getPrice());
        entity.setImage(dto.getImage());
        entity.setDescription(dto.getDescription());
        entity.setTags(dto.getTags());
        entity.setPrepTime(dto.getPrepTime());
        entity.setSales(dto.getSales());
        entity.setStatus(dto.getStatus());
        entity.setSoldOut(dto.getSoldOut());
        entity.setIsRecommended(dto.getIsRecommended());
        entity.setSortOrder(dto.getSortOrder());
        return entity;
    }

    /**
     * 查询菜品详情
     */
    public HotelDishDTO getDetail(String id) {
        HotelDish dish = hotelDishMapper.selectById(id);
        if (dish != null) {
            fillDishDetail(dish);
        }
        return dish != null ? entityToDto(dish) : null;
    }

    /**
     * 填充菜品的规格组和加料信息
     */
    private void fillDishDetail(HotelDish dish) {
        QueryWrapper<HotelDishSpec> specQw = new QueryWrapper<>();
        specQw.eq("dish_id", dish.getId()).eq("del_flag", 0).orderByAsc("sort_order");
        List<HotelDishSpec> specs = hotelDishSpecMapper.selectList(specQw);
        for (HotelDishSpec spec : specs) {
            QueryWrapper<HotelDishSpecOption> optQw = new QueryWrapper<>();
            optQw.eq("spec_id", spec.getId()).eq("del_flag", 0).orderByAsc("sort_order");
            spec.setOptions(hotelDishSpecOptionMapper.selectList(optQw));
        }
        dish.setSpecGroups(specs);
        QueryWrapper<HotelDishAddition> addQw = new QueryWrapper<>();
        addQw.eq("dish_id", dish.getId()).eq("del_flag", 0).orderByAsc("sort_order");
        dish.setAdditions(hotelDishAdditionMapper.selectList(addQw));
    }

    /**
     * 新增/编辑菜品(管理后台)
     */
    public String saveDish(HotelDishDTO dto) {
        if (StringUtils.isBlank(dto.getId())) {
            HotelDish dish = dtoToEntity(dto);
            dish.setId(UUID.randomUUID().toString().replace("-", ""));
            dish.setDelFlag(0);
            if (dish.getStatus() == null) {
                dish.setStatus("ON_SALE");
            }
            if (dish.getSales() == null) {
                dish.setSales(0);
            }
            if (dish.getSoldOut() == null) {
                dish.setSoldOut(0);
            }
            hotelDishMapper.insert(dish);
            saveLog(dish.getId(), dish.getName(), "CREATE", null, toJson(dish), "新增菜品");
            log.info("新增菜品: {}", dish.getName());
        } else {
            HotelDish oldDish = hotelDishMapper.selectById(dto.getId());
            String oldJson = oldDish != null ? toJson(oldDish) : null;
            HotelDish dish = dtoToEntity(dto);
            hotelDishMapper.updateById(dish);
            saveLog(dish.getId(), dish.getName() != null ? dish.getName() : (oldDish != null ? oldDish.getName() : ""), "EDIT", oldJson, toJson(dish), "编辑菜品");
            log.info("编辑菜品: {}", dish.getName());
        }
        return "操作成功";
    }

    /**
     * 删除菜品(级联删除规格组和加料，需校验未完成订单)
     */
    public String deleteDish(String id) {
        HotelDish dish = hotelDishMapper.selectById(id);
        if (dish == null) {
            throw new RuntimeException("菜品不存在");
        }
        // 校验未完成订单
        checkUnfinishedOrders(id);
        // 软删除菜品
        dish.setDelFlag(1);
        hotelDishMapper.updateById(dish);
        // 级联软删除规格组
        QueryWrapper<HotelDishSpec> specQw = new QueryWrapper<>();
        specQw.eq("dish_id", id).eq("del_flag", 0);
        List<HotelDishSpec> specs = hotelDishSpecMapper.selectList(specQw);
        for (HotelDishSpec spec : specs) {
            spec.setDelFlag(1);
            hotelDishSpecMapper.updateById(spec);
            QueryWrapper<HotelDishSpecOption> optQw = new QueryWrapper<>();
            optQw.eq("spec_id", spec.getId()).eq("del_flag", 0);
            List<HotelDishSpecOption> options = hotelDishSpecOptionMapper.selectList(optQw);
            for (HotelDishSpecOption opt : options) {
                opt.setDelFlag(1);
                hotelDishSpecOptionMapper.updateById(opt);
            }
        }
        // 软删除加料
        QueryWrapper<HotelDishAddition> addQw = new QueryWrapper<>();
        addQw.eq("dish_id", id).eq("del_flag", 0);
        List<HotelDishAddition> additions = hotelDishAdditionMapper.selectList(addQw);
        for (HotelDishAddition add : additions) {
            add.setDelFlag(1);
            hotelDishAdditionMapper.updateById(add);
        }
        saveLog(id, dish.getName(), "DELETE", toJson(dish), null, "删除菜品");
        log.info("删除菜品: {}", dish.getName());
        return "操作成功";
    }

    /**
     * 标记售罄
     */
    public String markSoldOut(String id) {
        HotelDish dish = hotelDishMapper.selectById(id);
        if (dish != null) {
            dish.setSoldOut(1);
            hotelDishMapper.updateById(dish);
            saveLog(id, dish.getName(), "SOLD_OUT", null, null, "标记售罄");
        }
        return "操作成功";
    }

    /**
     * 恢复上架(取消售罄)
     */
    public String restoreDish(String id) {
        HotelDish dish = hotelDishMapper.selectById(id);
        if (dish != null) {
            dish.setSoldOut(0);
            dish.setStatus("ON_SALE");
            hotelDishMapper.updateById(dish);
            saveLog(id, dish.getName(), "RESTORE", null, null, "恢复上架");
        }
        return "操作成功";
    }

    /**
     * 更新菜品状态(上架/下架)
     */
    public String updateStatus(String id, String status) {
        HotelDish dish = hotelDishMapper.selectById(id);
        if (dish == null) {
            throw new RuntimeException("菜品不存在");
        }
        dish.setStatus(status);
        hotelDishMapper.updateById(dish);
        String opType = "ON_SALE".equals(status) ? "ON_SALE" : "OFF_SHELF";
        saveLog(id, dish.getName(), opType, null, null, "ON_SALE".equals(status) ? "上架" : "下架");
        log.info("菜品状态变更: {} -> {}", dish.getName(), status);
        return "操作成功";
    }

    /**
     * 批量操作
     */
    public String batchOperate(List<String> ids, String operation) {
        for (String id : ids) {
            switch (operation) {
                case "ON_SALE":
                    updateStatus(id, "ON_SALE");
                    break;
                case "OFF_SHELF":
                    updateStatus(id, "OFF_SHELF");
                    break;
                case "SOLD_OUT":
                    markSoldOut(id);
                    break;
                case "RESTORE":
                    restoreDish(id);
                    break;
                case "DELETE":
                    deleteDish(id);
                    break;
                default:
                    throw new RuntimeException("不支持的操作类型: " + operation);
            }
        }
        return "批量操作成功";
    }

    /**
     * 校验菜品是否有未完成订单
     */
    private void checkUnfinishedOrders(String dishId) {
        QueryWrapper<HotelOrder> qw = new QueryWrapper<>();
        qw.in("status", Arrays.asList("PREPARING", "READY", "DELIVERING", "ACCEPTED"))
                .eq("del_flag", 0);
        List<HotelOrder> orders = hotelOrderMapper.selectList(qw);
        if (!orders.isEmpty()) {
            throw new RuntimeException("该菜品存在未完成的订单，无法删除");
        }
    }

    /**
     * 保存操作日志
     */
    private void saveLog(String dishId, String dishName, String operationType, String oldValue, String newValue, String remark) {
        HotelDishLog logEntity = new HotelDishLog();
        logEntity.setId(UUID.randomUUID().toString().replace("-", ""));
        logEntity.setDishId(dishId);
        logEntity.setDishName(dishName);
        logEntity.setOperationType(operationType);
        logEntity.setOldValue(oldValue);
        logEntity.setNewValue(newValue);
        logEntity.setRemark(remark);
        logEntity.setDelFlag(0);
        hotelDishLogMapper.insert(logEntity);
    }

    /**
     * 简单转JSON(用于日志记录)
     */
    private String toJson(Object obj) {
        if (obj == null) return null;
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            return obj.toString();
        }
    }

    // ============ 规格和加料方法 ============

    public String saveSpec(HotelDishSpec spec) {
        if (StringUtils.isBlank(spec.getId())) {
            spec.setId(UUID.randomUUID().toString().replace("-", ""));
            spec.setDelFlag(0);
            hotelDishSpecMapper.insert(spec);
        } else {
            hotelDishSpecMapper.updateById(spec);
        }
        return "操作成功";
    }

    public String deleteSpec(String id) {
        HotelDishSpec spec = hotelDishSpecMapper.selectById(id);
        if (spec == null) {
            throw new RuntimeException("规格组不存在");
        }
        spec.setDelFlag(1);
        hotelDishSpecMapper.updateById(spec);
        QueryWrapper<HotelDishSpecOption> optQw = new QueryWrapper<>();
        optQw.eq("spec_id", id).eq("del_flag", 0);
        List<HotelDishSpecOption> options = hotelDishSpecOptionMapper.selectList(optQw);
        for (HotelDishSpecOption opt : options) {
            opt.setDelFlag(1);
            hotelDishSpecOptionMapper.updateById(opt);
        }
        return "操作成功";
    }

    public String saveSpecOption(HotelDishSpecOption option) {
        if (StringUtils.isBlank(option.getId())) {
            option.setId(UUID.randomUUID().toString().replace("-", ""));
            option.setDelFlag(0);
            hotelDishSpecOptionMapper.insert(option);
        } else {
            hotelDishSpecOptionMapper.updateById(option);
        }
        return "操作成功";
    }

    public String saveAddition(HotelDishAddition addition) {
        if (StringUtils.isBlank(addition.getId())) {
            addition.setId(UUID.randomUUID().toString().replace("-", ""));
            addition.setDelFlag(0);
            hotelDishAdditionMapper.insert(addition);
        } else {
            hotelDishAdditionMapper.updateById(addition);
        }
        return "操作成功";
    }

    public String deleteAddition(String id) {
        HotelDishAddition addition = hotelDishAdditionMapper.selectById(id);
        if (addition == null) {
            throw new RuntimeException("加料不存在");
        }
        addition.setDelFlag(1);
        hotelDishAdditionMapper.updateById(addition);
        return "操作成功";
    }

    /**
     * 销量排行
     */
    public List<HotelDishDTO> salesRanking(int limit) {
        List<HotelDish> list = hotelDishMapper.selectSalesRanking(limit);
        return list.stream().map(this::entityToDto).collect(Collectors.toList());
    }
}
