package com.ruoyi.info.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.info.hospital.domain.Hospital;
import com.ruoyi.info.hospital.domain.HospitalDepartment;
import com.ruoyi.info.hospital.domain.vo.HospitalDepartmentVo;
import com.ruoyi.info.hospital.domain.vo.HospitalStatisticsVo;
import com.ruoyi.info.hospital.domain.vo.HospitalVo;
import com.ruoyi.info.hospital.service.IHospitalDepartmentService;
import com.ruoyi.info.hospital.service.IHospitalService;
import com.ruoyi.info.management.domain.vo.ManagementTeacherVo;
import com.ruoyi.info.management.service.IManagementTeacherService;
import com.ruoyi.info.nursing.domain.NursingWorker;
import com.ruoyi.info.nursing.domain.vo.NursingWorkerVo;
import com.ruoyi.info.nursing.service.INursingWorkerService;
import com.ruoyi.info.order.domain.Order;
import com.ruoyi.info.order.domain.bo.OrderBo;
import com.ruoyi.info.order.domain.bo.OrderReviewsBo;
import com.ruoyi.info.order.domain.bo.OrderWorkerChangeRecordBo;
import com.ruoyi.info.order.domain.vo.OrderReviewsVo;
import com.ruoyi.info.order.domain.vo.OrderVo;
import com.ruoyi.info.order.domain.vo.OrderWorkerChangeRecordVo;
import com.ruoyi.info.order.domain.vo.OrderWorkerSumVo;
import com.ruoyi.info.order.enums.CancellationMethod;
import com.ruoyi.info.order.enums.OrderStatus;
import com.ruoyi.info.order.exception.OrderExceptionEnum;
import com.ruoyi.info.order.mapper.OrderMapper;
import com.ruoyi.info.order.service.IOrderReviewsService;
import com.ruoyi.info.order.service.IOrderService;
import com.ruoyi.info.order.service.IOrderWorkerChangeRecordService;
import com.ruoyi.info.patient.domain.Patient;
import com.ruoyi.info.patient.domain.vo.PatientVo;
import com.ruoyi.info.patient.service.IPatientService;
import com.ruoyi.info.service.domain.ServiceProduct;
import com.ruoyi.info.service.domain.vo.ServiceProductVo;
import com.ruoyi.info.service.service.IServiceProductService;
import com.ruoyi.system.enums.SequencePrefixEnum;
import com.ruoyi.system.service.ISysSequenceService;
import com.ruoyi.user.domain.User;
import com.ruoyi.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 订单Service业务层处理
 *
 * @author ruoyi
 * @date 2025-09-20
 */
@RequiredArgsConstructor
@Service
public class OrderServiceImpl implements IOrderService {

    private final OrderMapper baseMapper;
    private final ISysSequenceService sysSequenceService;
    private final IServiceProductService serviceProductService;
    private final IHospitalService hospitalService;
    private final IHospitalDepartmentService hospitalDepartmentService;
    private final IPatientService patientService;
    private final IUserService userService;
    private final INursingWorkerService nursingWorkerService;
    private final IOrderWorkerChangeRecordService orderWorkerChangeRecordService;
    private final IManagementTeacherService managementTeacherService;
    private final IOrderReviewsService orderReviewsService;

    /**
     * 查询订单分页
     *
     * @param bo 订单
     * @return 订单
     */
    @Override
    public TableDataInfo<OrderVo> queryPageList(OrderBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Order> lqw = buildQueryWrapper(bo);
        Page<OrderVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.setRecords(convertList(result.getRecords()));
        return TableDataInfo.build(result);
    }

    /**
     * 查询订单列表
     *
     * @param bo 订单
     * @return 订单
     */
    @Override
    public List<OrderVo> queryList(OrderBo bo) {
        LambdaQueryWrapper<Order> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Order> buildQueryWrapper(OrderBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Order> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getOrderNo()), Order::getOrderNo, bo.getOrderNo());
        lqw.eq(bo.getUserId() != null, Order::getUserId, bo.getUserId());
        lqw.eq(bo.getStatus() != null, Order::getStatus, bo.getStatus());
        lqw.eq(bo.getHospitalId() != null, Order::getHospitalId, bo.getHospitalId());
        lqw.eq(bo.getHospitalDepartmentId() != null, Order::getHospitalDepartmentId, bo.getHospitalDepartmentId());
        lqw.eq(StringUtils.isNotBlank(bo.getRoomNumber()), Order::getRoomNumber, bo.getRoomNumber());
        lqw.eq(StringUtils.isNotBlank(bo.getRemarks()), Order::getRemarks, bo.getRemarks());
        lqw.eq(bo.getPatientId() != null, Order::getPatientId, bo.getPatientId());
        lqw.eq(bo.getServiceId() != null, Order::getServiceId, bo.getServiceId());
        lqw.eq(bo.getExpectedTime() != null, Order::getExpectedTime, bo.getExpectedTime());
        lqw.eq(bo.getOrderNum() != null, Order::getOrderNum, bo.getOrderNum());
        lqw.eq(bo.getSellingPrice() != null, Order::getSellingPrice, bo.getSellingPrice());
        lqw.eq(bo.getTotalPrice() != null, Order::getTotalPrice, bo.getTotalPrice());
        lqw.eq(bo.getWorkerId() != null, Order::getWorkerId, bo.getWorkerId());
        lqw.in(CollUtil.isNotEmpty(bo.getHospitalDepartmentIds()), Order::getHospitalDepartmentId, bo.getHospitalDepartmentIds());
        //日期
        buildTime(bo);
        lqw.ge(bo.getStartTime() != null, Order::getCreateTime, bo.getStartTime());
        lqw.le(bo.getEndTime() != null, Order::getCreateTime, bo.getEndTime());
        lqw.orderByDesc(Order::getCreateTime);
        return lqw;
    }

    private List<OrderVo> convertList(List<OrderVo> list) {
        return list.stream().map(this::convert).collect(Collectors.toList());
    }

    private OrderVo convert(OrderVo vo) {
        if (ObjectUtil.isNull(vo)) {
            return vo;
        }
        //医院
        vo.setHospitalVo(JSONObject.parseObject(vo.getHospitalInfo(), HospitalVo.class));
        //科室
        HospitalDepartmentVo hospitalDepartmentVo = JSONObject.parseObject(vo.getHospitalDepartmentInfo(), HospitalDepartmentVo.class);
        if (ObjectUtil.isNotNull(hospitalDepartmentVo)) {
            vo.setHospitalDepartmentName(hospitalDepartmentVo.getName());
        }
        //就诊人
        vo.setPatientVo(JSONObject.parseObject(vo.getPatientInfo(), PatientVo.class));
        //服务
        ServiceProductVo serviceProductVo = JSONObject.parseObject(vo.getServiceInfo(), ServiceProductVo.class);
        if (ObjectUtil.isNotNull(serviceProductVo)) {
            vo.setServiceName(serviceProductVo.getName());
        }
        //用户
        User user = userService.getById(vo.getUserId(), false);
        if (ObjectUtil.isNotNull(user)) {
            vo.setUserName(user.getNickname());
            vo.setUserMobile(user.getMobile());
        }
        //护工
        if (ObjectUtil.isNotNull(vo.getWorkerId())) {
            OrderWorkerChangeRecordVo orderWorkerChangeRecordVo = orderWorkerChangeRecordService.queryByOrderAndWorker(vo.getId(), vo.getWorkerId());
            ManagementTeacherVo managementTeacherVo = managementTeacherService.queryDelById(orderWorkerChangeRecordVo.getOperatingTeacherId());
            if (ObjectUtil.isNotNull(managementTeacherVo)) {
                orderWorkerChangeRecordVo.setOperatingTeacherName(managementTeacherVo.getName());
                orderWorkerChangeRecordVo.setOperatingTeacherPhoneNumber(managementTeacherVo.getPhoneNumber());
            }
            vo.setOrderWorkerChangeRecord(orderWorkerChangeRecordVo);
        }
        //评价
        if (OrderStatus.done.equals(vo.getStatus())) {
            OrderReviewsVo orderReviewsVo = orderReviewsService.queryByOrderId(vo.getId());
            vo.setOrderReviews(orderReviewsVo);
        }
        return vo;
    }

    /**
     * 查询订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public OrderVo queryById(Long id){
        return convert(baseMapper.selectVoById(id));
    }

    /**
     * 详情订单
     *
     * @param id 订单主键
     * @return 订单
     */
    @Override
    public Order loadById(Long id, Boolean tw){
        Order info = this.baseMapper.selectById(id);
        if(ObjectUtil.isEmpty(info) && tw){
            throw new ServiceException(OrderExceptionEnum.Order_IS_NOT_EXISTS);
        }
        return info;
    }

    /**
     * 新增订单
     *
     * @param bo 订单
     * @return 结果
     */
    @Transactional
    @Override
    public Boolean insertByBo(OrderBo bo) {
        Order add = BeanUtil.toBean(bo, Order.class);
        add.setOrderNo(sysSequenceService.generateSequence(SequencePrefixEnum.PRE_ORDER, DateUtil.format(new Date(), "yyMMdd"), 6));
        add.setStatus(OrderStatus.wait_confirmed);
        //服务
        ServiceProduct serviceProduct = serviceProductService.loadById(add.getServiceId(), true);
        add.setServiceInfo(JSONObject.toJSONString(serviceProduct));
        add.setSellingPrice(serviceProduct.getSellingPrice());
        add.setTotalPrice(serviceProduct.getSellingPrice().multiply(new BigDecimal(add.getOrderNum())));
        add.setServiceUnit(serviceProduct.getServiceUnit());
        add.setServiceUnitDuration(serviceProduct.getServiceUnitDuration());
        //医院
        Hospital hospital = hospitalService.loadById(add.getHospitalId(), true);
        add.setHospitalInfo(JSONObject.toJSONString(hospital));
        //科室
        HospitalDepartment hospitalDepartment = hospitalDepartmentService.loadById(add.getHospitalDepartmentId(), true);
        add.setHospitalDepartmentInfo(JSONObject.toJSONString(hospitalDepartment));
        //就诊人
        Patient patient = patientService.loadById(add.getPatientId(), true);
        add.setPatientInfo(JSONObject.toJSONString(patient));
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            //更新订单数
            userService.addNum(add.getUserId());
        }
        return flag;
    }

    /**
     * 修改订单
     *
     * @param bo 订单
     * @return 结果
     */
    @Override
    public Boolean updateByBo(OrderBo bo) {
        Order order = baseMapper.selectById(bo.getId());
        Order update = BeanCopyUtils.copy(bo, order);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(Order entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除订单
     *
     * @param ids 需要删除的订单主键
     * @return 结果
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public boolean cancel(Long id, Long userId, CancellationMethod cancellationMethod) {
        Order order = loadById(id, true);
        if (CancellationMethod.user_canceled.equals(cancellationMethod)) {
            if (!order.getUserId().equals(userId)) {
                throw new ServiceException(OrderExceptionEnum.Order_IS_NOT_YOURS);
            }
        }
        if (!OrderStatus.wait_confirmed.equals(order.getStatus())) {
            throw new ServiceException(OrderExceptionEnum.Order_STATUS_ERROR);
        }
        order.setStatus(OrderStatus.canceled);
        order.setCancellationMethod(cancellationMethod);
        order.setCancellationTime(new Date());
        return baseMapper.updateById(order) > 0;
    }

    @Override
    public TableDataInfo<OrderVo> queryAllPageList(OrderBo bo, PageQuery pageQuery) {
        buildTime(bo);
        Page<OrderVo> result = baseMapper.queryAllPageList(bo, pageQuery.build());
        result.setRecords(convertAllList(result.getRecords(), false));
        return TableDataInfo.build(result);
    }

    @Override
    public List<OrderVo> queryAllList(OrderBo bo) {
        buildTime(bo);
        return convertAllList(baseMapper.queryAllList(bo), true);
    }

    private void buildTime(OrderBo bo) {
        if(bo.getStartTime() != null) {
            bo.setStartTime(DateUtil.beginOfDay(bo.getStartTime()));
        }
        if(bo.getEndTime() != null) {
            bo.setEndTime(DateUtil.endOfDay(bo.getEndTime()));
        }
    }

    @Override
    public Integer querySumForHome() {
        Long count = baseMapper.selectCount(new LambdaQueryWrapper<Order>());
        return count.intValue();
    }

    @Override
    public List<HospitalStatisticsVo> queryHospitalOrderStatistics() {
        //按医院分组 订单数top10
        List<HospitalStatisticsVo> hospitalStatistics = baseMapper.queryHospitalOrderStatistics();
        return hospitalStatistics.stream().map(h -> {
            h.setName(hospitalService.queryNameById(h.getHospitalId()));
            return h;
        }).collect(Collectors.toList());
    }

    @Transactional
    @Override
    public boolean assignWorker(OrderBo bo, Long teacherId) {
        Order order = loadById(bo.getId(), true);
        if (!OrderStatus.wait_confirmed.equals(order.getStatus()) && !OrderStatus.wait_service.equals(order.getStatus())
        && !OrderStatus.in_progress.equals(order.getStatus())) {
            throw new ServiceException(OrderExceptionEnum.Order_STATUS_IS_NOT_ASSIGN);
        }
        //判断护工
        NursingWorker nursingWorker = nursingWorkerService.loadById(bo.getWorkerId(), true);
        if (!nursingWorker.getHospitalId().equals(order.getHospitalId())) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_NOT_IN_HOSPITAL);
        }
        if (!nursingWorker.getEnableStatus().equals(UserConstants.NORMAL)) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_NOT_ENABLE);
        }
        order.setWorkerId(bo.getWorkerId());
        if (OrderStatus.wait_confirmed.equals(order.getStatus())) {
            order.setStatus(OrderStatus.wait_service);
        }
        //新增护工分配记录
        OrderWorkerChangeRecordBo orderWorkerChangeRecordBo = new OrderWorkerChangeRecordBo();
        orderWorkerChangeRecordBo.setOrderId(order.getId());
        orderWorkerChangeRecordBo.setWorkerId(nursingWorker.getId());
        orderWorkerChangeRecordBo.setWorkerName(nursingWorker.getName());
        orderWorkerChangeRecordBo.setWorkerPhoneNumber(nursingWorker.getPhoneNumber());
        orderWorkerChangeRecordBo.setSex(nursingWorker.getSex());
        orderWorkerChangeRecordBo.setOperatingTeacherId(teacherId);
        orderWorkerChangeRecordService.insertByBo(orderWorkerChangeRecordBo);
        return baseMapper.updateById(order) > 0;
    }

    @Transactional
    @Override
    public boolean startService(Long id, Long workerId) {
        Order order = loadById(id, true);
        if (!OrderStatus.wait_service.equals(order.getStatus())) {
            throw new ServiceException(OrderExceptionEnum.Order_STATUS_IS_NOT_START);
        }
        if (!order.getWorkerId().equals(workerId)) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_IS_NOT_YOURS);
        }
        order.setStatus(OrderStatus.in_progress);
        //更新开始时间
        OrderWorkerChangeRecordVo orderWorkerChangeRecordVo = orderWorkerChangeRecordService.queryByOrderAndWorker(id, workerId);
        if (ObjectUtil.isNull(orderWorkerChangeRecordVo)) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_IS_NOT_YOURS);
        }
        OrderWorkerChangeRecordBo orderWorkerChangeRecordBo = new OrderWorkerChangeRecordBo();
        orderWorkerChangeRecordBo.setId(orderWorkerChangeRecordVo.getId());
        orderWorkerChangeRecordBo.setWorkerStartTime(new Date());
        orderWorkerChangeRecordService.updateByBo(orderWorkerChangeRecordBo);
        return baseMapper.updateById(order) > 0;
    }

    @Transactional
    @Override
    public boolean finishService(Long id, Long workerId) {
        Order order = loadById(id, true);
        if (!OrderStatus.in_progress.equals(order.getStatus())) {
            throw new ServiceException(OrderExceptionEnum.Order_STATUS_IS_NOT_PROGRESS);
        }
        if (!order.getWorkerId().equals(workerId)) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_IS_NOT_YOURS);
        }
        order.setStatus(OrderStatus.wait_evaluated);
        //更新结束时间
        OrderWorkerChangeRecordVo orderWorkerChangeRecordVo = orderWorkerChangeRecordService.queryByOrderAndWorker(id, workerId);
        if (ObjectUtil.isNull(orderWorkerChangeRecordVo)) {
            throw new ServiceException(OrderExceptionEnum.Order_WORKER_IS_NOT_YOURS);
        }
        OrderWorkerChangeRecordBo orderWorkerChangeRecordBo = new OrderWorkerChangeRecordBo();
        orderWorkerChangeRecordBo.setId(orderWorkerChangeRecordVo.getId());
        orderWorkerChangeRecordBo.setWorkerEndTime(new Date());
        orderWorkerChangeRecordService.updateByBo(orderWorkerChangeRecordBo);
        return baseMapper.updateById(order) > 0;
    }

    @Override
    public String getManagerPhone(Long id, Long workerId) {
        OrderWorkerChangeRecordVo orderWorkerChangeRecordVo = orderWorkerChangeRecordService.queryByOrderAndWorker(id, workerId);
        if (ObjectUtil.isNotNull(orderWorkerChangeRecordVo)) {
            ManagementTeacherVo managementTeacherVo = managementTeacherService.queryDelById(orderWorkerChangeRecordVo.getOperatingTeacherId());
            return ObjectUtil.isNotNull(managementTeacherVo) ? managementTeacherVo.getPhoneNumber() : null;
        }
        return null;
    }

    @Override
    public String getWorkerPhone(Long id, Long teacherId) {
        Order order = loadById(id, true);
        if (ObjectUtil.isNotNull(order.getWorkerId())) {
            NursingWorkerVo nursingWorkerVo = nursingWorkerService.queryById(order.getWorkerId());
            return ObjectUtil.isNotNull(nursingWorkerVo) ? nursingWorkerVo.getPhoneNumber() : null;
        }
        return null;
    }

    @Transactional
    @Override
    public boolean evaluate(OrderReviewsBo bo) {
        Order order = loadById(bo.getOrderId(), true);
        if (!OrderStatus.wait_evaluated.equals(order.getStatus())) {
            throw new ServiceException(OrderExceptionEnum.Order_STATUS_IS_NOT_EVALUATED);
        }
        order.setStatus(OrderStatus.done);
        order.setIsReviewed(true);
        //新增评价
        orderReviewsService.insertByBo(bo);
        return baseMapper.updateById(order) > 0;
    }

    @Override
    public List<OrderWorkerSumVo> getOrderWorkerSum() {
        return baseMapper.selectOrderWorkerSum();
    }

    private List<OrderVo> convertAllList(List<OrderVo> list, boolean queryPatient) {
        return list.stream().map(o -> {
            HospitalVo hospitalVo = JSONObject.parseObject(o.getHospitalInfo(), HospitalVo.class);
            if (ObjectUtil.isNotNull(hospitalVo)) {
                o.setHospitalName(hospitalVo.getName());
                o.setHospitalAddress(hospitalVo.getAddress());
            }
            //科室
            HospitalDepartmentVo hospitalDepartmentVo = JSONObject.parseObject(o.getHospitalDepartmentInfo(), HospitalDepartmentVo.class);
            if (ObjectUtil.isNotNull(hospitalDepartmentVo)) {
                o.setHospitalDepartmentName(hospitalDepartmentVo.getName());
            }
            //服务
            ServiceProductVo serviceProductVo = JSONObject.parseObject(o.getServiceInfo(), ServiceProductVo.class);
            if (ObjectUtil.isNotNull(serviceProductVo)) {
                o.setServiceName(serviceProductVo.getName());
            }
            if(queryPatient) {
                PatientVo patientVo = JSONObject.parseObject(o.getPatientInfo(), PatientVo.class);
                if (ObjectUtil.isNotNull(patientVo)) {
                    o.setPatientName(patientVo.getName());
                    o.setPatientMobile(patientVo.getMobile());
                    o.setPatientGender(patientVo.getGender());
                    o.setPatientAge(patientVo.getAge());
                    o.setPatientRelationship(patientVo.getRelationship());
                }
            }
            return o;
        }).collect(Collectors.toList());
    }
}
