package com.fs.provider.service.impl;

import com.fs.common.config.LoginContextManager;
import com.fs.common.exception.ServiceException;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.SecurityUtils;
import com.fs.company.domain.Company;
import com.fs.company.domain.CompanyDept;
import com.fs.company.domain.CompanyUser;
import com.fs.company.service.ICompanyDeptService;
import com.fs.company.service.ICompanyService;
import com.fs.company.service.ICompanyUserService;
import com.fs.doctor.domain.Doctor;
import com.fs.doctor.domain.DoctorBalanceLog;
import com.fs.doctor.domain.DoctorCompanyUser;
import com.fs.doctor.service.IDoctorBalanceLogService;
import com.fs.doctor.service.IDoctorCompanyUserService;
import com.fs.doctor.service.IDoctorService;
import com.fs.provider.domain.ServiceGenConfig;
import com.fs.provider.domain.ServiceOrder;
import com.fs.provider.domain.ServiceOrderTaskRel;
import com.fs.provider.enums.*;
import com.fs.provider.mapper.ServiceOrderMapper;
import com.fs.provider.service.IServiceOrderService;
import com.fs.provider.service.IServiceOrderTaskRelService;
import com.fs.provider.vo.ServiceOrderAuditReqVO;
import com.fs.provider.vo.ServiceOrderAuditRespVO;
import com.fs.provider.vo.ServiceOrderInfoVO;
import com.fs.provider.vo.ServiceOrderStatisticsReqVO;
import com.fs.provider.vo.ServiceOrderStatisticsVO;
import com.fs.task.domain.ServiceGenResult;
import com.fs.task.domain.TaskInfo;
import com.fs.task.enums.ChangeReasonEnum;
import com.fs.task.enums.ServiceConfirmStatusEnum;
import com.fs.task.enums.TaskFinishStatusEnum;
import com.fs.task.enums.TaskStatusEnum;
import com.fs.task.service.ITaskInfoService;
import com.fs.task.vo.GetTaskCompleteStatsVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 服务单信息Service业务层处理
 *
 * @author fs
 * @date 2026-01-26
 */
@Service
public class ServiceOrderServiceImpl implements IServiceOrderService {
    @Autowired
    private ServiceOrderMapper serviceOrderMapper;
    @Autowired
    private ITaskInfoService taskInfoService;
    @Autowired
    private ICompanyService companyService;
    @Autowired
    private ICompanyDeptService companyDeptService;
    @Autowired
    private ICompanyUserService companyUserService;
    @Autowired
    private IDoctorCompanyUserService doctorCompanyUserService;
    @Autowired
    private IServiceOrderTaskRelService iServiceOrderTaskRelService;
    @Autowired
    private IDoctorService doctorService;
    @Autowired
    private IDoctorBalanceLogService doctorBalanceLogService;


    /**
     * 查询服务单信息
     *
     * @param id 服务单信息主键
     * @return 服务单信息
     */
    @Override
    public ServiceOrderInfoVO selectServiceOrderById(Long id) {
        // 1) 查服务单
        ServiceOrder serviceOrder = serviceOrderMapper.selectServiceOrderById(id);
        if (serviceOrder == null) {
            return null; // 或 throw new ServiceException("服务单不存在");
        }

        // 2) 查关联关系
        List<ServiceOrderTaskRel> relList =
                iServiceOrderTaskRelService.selectByServiceOrderId(serviceOrder.getId());
        if (relList == null || relList.isEmpty()) {
            ServiceOrderInfoVO vo = new ServiceOrderInfoVO();
            vo.setServiceOrder(serviceOrder);
            vo.setTaskInfos(java.util.Collections.emptyList());
            return vo;
        }

        // 3) 收集 taskId（去重 + 过滤 null）
        List<Long> taskIds = relList.stream()
                .map(ServiceOrderTaskRel::getTaskId)
                .filter(java.util.Objects::nonNull)
                .distinct()
                .collect(java.util.stream.Collectors.toList());

        if (taskIds.isEmpty()) {
            ServiceOrderInfoVO vo = new ServiceOrderInfoVO();
            vo.setServiceOrder(serviceOrder);
            vo.setTaskInfos(java.util.Collections.emptyList());
            return vo;
        }

        // 4) 批量查任务（避免 N+1）
        List<TaskInfo> taskList = taskInfoService.selectTaskInfoByIds(taskIds);

        // 5) 组装：按 relList 顺序输出（更符合“明细”直觉）
        java.util.Map<Long, TaskInfo> taskMap = taskList.stream()
                .collect(java.util.stream.Collectors.toMap(TaskInfo::getId, t -> t, (a, b) -> a));

        List<TaskInfo> orderedTasks = relList.stream()
                .map(ServiceOrderTaskRel::getTaskId)
                .filter(java.util.Objects::nonNull)
                .map(taskMap::get)
                .filter(java.util.Objects::nonNull)
                .collect(java.util.stream.Collectors.toList());

        // 6) 返回 VO
        ServiceOrderInfoVO vo = new ServiceOrderInfoVO();
        vo.setServiceOrder(serviceOrder);
        vo.setTaskInfos(orderedTasks);
        return vo;
    }


    @Override
    public List<ServiceOrder> queryStatis(GetTaskCompleteStatsVO statisVO) {
        return serviceOrderMapper.queryStatis(statisVO);
    }

    /**
     * 服务单统计汇总（按部门分组）
     *
     * @param reqVO 查询条件
     * @return 统计结果列表
     */
    @Override
    public List<ServiceOrderStatisticsVO> getServiceOrderStatistics(ServiceOrderStatisticsReqVO reqVO) {
        return serviceOrderMapper.selectServiceOrderStatistics(reqVO);
    }

    /**
     * 查询服务单信息列表
     *
     * @param serviceOrder 服务单信息
     * @return 服务单信息
     */
    @Override
    public List<ServiceOrder> selectServiceOrderList(ServiceOrder serviceOrder) {
        return serviceOrderMapper.selectServiceOrderList(serviceOrder);
    }

    /**
     * 新增服务单信息
     *
     * @param serviceOrder 服务单信息
     * @return 结果
     */
    @Override
    public int insertServiceOrder(ServiceOrder serviceOrder) {
        serviceOrder.setCreateTime(DateUtils.getNowDate());
        return serviceOrderMapper.insertServiceOrder(serviceOrder);
    }

    /**
     * 修改服务单信息
     *
     * @param serviceOrder 服务单信息
     * @return 结果
     */
    @Override
    public int updateServiceOrder(ServiceOrder serviceOrder) {
        serviceOrder.setUpdateTime(DateUtils.getNowDate());
        return serviceOrderMapper.updateServiceOrder(serviceOrder);
    }

    /**
     * 批量删除服务单信息
     *
     * @param ids 需要删除的服务单信息主键
     * @return 结果
     */
    @Override
    public int deleteServiceOrderByIds(Long[] ids) {
        return serviceOrderMapper.deleteServiceOrderByIds(ids);
    }

    /**
     * 删除服务单信息信息
     *
     * @param id 服务单信息主键
     * @return 结果
     */
    @Override
    public int deleteServiceOrderById(Long id) {
        return serviceOrderMapper.deleteServiceOrderById(id);
    }

    @Transactional
    @Override
    public int generateByTaskId(Long taskId) {

        // ===== 1️⃣ 基础参数校验 =====
        if (taskId == null) {
            throw new ServiceException("任务ID不能为空");
        }

        // ===== 2️⃣ 任务校验 =====
        TaskInfo taskInfo = taskInfoService.selectTaskInfoById(taskId);
        if (taskInfo == null) {
            throw new ServiceException("任务不存在");
        }

        // 只允许“已完成”的任务生成服务单
        if (!TaskStatusEnum.FINISHED.getCode().equals(taskInfo.getTaskStatus())) {
            throw new ServiceException("当前任务状态不允许生成服务单");
        }

        // ===== 3️⃣ 防重复生成（业务级）=====
        boolean exists = iServiceOrderTaskRelService.existsByTaskId(taskId);
        if (exists) {
            throw new ServiceException("该任务已生成服务单，请勿重复操作");
        }

        // ===== 4️⃣ 金额校验 =====
        if (taskInfo.getTaskIntegral() == null || taskInfo.getTaskIntegral().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("任务金额异常，无法生成服务单");
        }

        // ===== 5️⃣ 公司 / 部门校验 =====
        Long companyId = taskInfo.getCompanyId();
        if (companyId == null) {
            throw new ServiceException("任务未绑定公司，无法生成服务单");
        }

        Company company = companyService.selectCompanyById(companyId);
        if (company == null) {
            throw new ServiceException("公司不存在");
        }

        CompanyDept companyDept = companyDeptService.selectCompanyDeptById(taskInfo.getDeptId());
        if (companyDept == null) {
            throw new ServiceException("归属部门不存在");
        }



        // ===== 6️⃣ 发起人校验（必须是公司用户）=====
        Long userId = LoginContextManager.getCurrentCompanyUserId();
        CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
        if (companyUser == null) {
            throw new ServiceException("当前用户不是公司人员，无法发起服务单");
        }

        Doctor doctor = doctorService.selectDoctorById(taskInfo.getDoctorId());
        if(Objects.isNull(doctor)){
            throw new ServiceException("当前任务医生不存在");
        }

        // ===== 7️⃣ 生成服务单 =====
        ServiceOrder serviceOrder = new ServiceOrder();
        serviceOrder.setServiceOrderNo("TMP" + System.currentTimeMillis());
        serviceOrder.setCompanyId(companyId);
        serviceOrder.setCompanyName(company.getCompanyName());
        serviceOrder.setDeptId(taskInfo.getDeptId());
        serviceOrder.setDeptName(companyDept.getDeptName());

        // ⚠️ 建议：这里未来改成存 code，而不是 desc
        serviceOrder.setSettlementMethod(SettlementMethodEnum.WITHDRAW.getCode());

        serviceOrder.setTaskAmount(taskInfo.getTaskIntegral());
        serviceOrder.setTotalAmount(taskInfo.getTaskIntegral());

        serviceOrder.setAuditStatus(ServiceOrderAuditStatus.NO_AUDIT.getCode().longValue());
        serviceOrder.setAuditTime(new Date());
        serviceOrder.setDoctorConfirm(DoctorConfirmEnum.UNCONFIRMED.getCode().longValue());
        serviceOrder.setSettlementStatus(SettlementStatusEnum.UNSETTLED.getCode());

        serviceOrder.setInitiatorUserId(companyUser.getUserId());
        serviceOrder.setInitiatorName(companyUser.getNickName());
        serviceOrder.setInitiatorPhone(companyUser.getPhonenumber());

        serviceOrder.setDoctorName(doctor.getDoctorName());
        serviceOrder.setDoctorId(doctor.getId()+"");
        int i = this.insertServiceOrder(serviceOrder);
        String serviceOrderNo = "JSD" + String.format("%014d", serviceOrder.getId());
        serviceOrder.setServiceOrderNo(serviceOrderNo);
        serviceOrder.setSettlementTime(new Date());
        this.updateServiceOrder(serviceOrder);

        // ===== 8️⃣ 生成关联关系 =====
        ServiceOrderTaskRel rel = new ServiceOrderTaskRel();
        rel.setServiceOrderId(serviceOrder.getId());
        rel.setTaskId(taskInfo.getId());
        iServiceOrderTaskRelService.insertServiceOrderTaskRel(rel);


        //生成服务单
        taskInfo.setServiceConfirmStatus(ServiceConfirmStatusEnum.GENERATED.getCode());
        taskInfoService.updateTaskInfo(taskInfo);
        return 1;
    }

    @Override
    public ServiceOrderAuditRespVO getAuditInfo(ServiceOrderAuditReqVO serviceOrderAuditReqVO) {

        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public void autoConfirmAndSettleIfNeeded(Long orderId) {

        // 0) 取服务单
        ServiceOrder order = serviceOrderMapper.selectServiceOrderById(orderId);
        if (order == null) {
            return;
        }

        // 1) 幂等抢占：先把订单状态原子更新到“已确认+已结算”
        //    只有抢到的人才能继续加积分、写流水
        int updated = serviceOrderMapper.markAutoConfirmed(orderId, LocalDateTime.now());
        if (updated == 0) {
            // 已被处理/状态不满足，直接结束
            return;
        }

        // 2) 查关联任务
        List<ServiceOrderTaskRel> relList = iServiceOrderTaskRelService.selectByServiceOrderId(order.getId());
        if (relList == null || relList.isEmpty()) {
            // 这里视业务：是否允许无任务也结算？
            // 目前我选择：无任务则直接结束（因为抢占已发生，会导致订单已结算但无积分流水）
            // 如果你不允许这种情况，应当在抢占前先校验 relList 非空
            return;
        }

        // 3) 逐任务发放积分 + 记流水
        for (ServiceOrderTaskRel rel : relList) {
            Long taskId = rel.getTaskId();
            if (taskId == null) {
                continue;
            }

            TaskInfo taskInfo = taskInfoService.selectTaskInfoById(taskId);
            if (taskInfo == null) {
                continue;
            }
            //任务结算完成
            taskInfo.setFinishStatus(TaskFinishStatusEnum.FINISHED.getCode().longValue());
            taskInfoService.updateTaskInfo(taskInfo);

            BigDecimal points = taskInfo.getTaskIntegral();
            if (points == null || points.compareTo(BigDecimal.ZERO) == 0) {
                // 0分不记账
                continue;
            }

            Long doctorId = taskInfo.getDoctorId();
            if (doctorId == null) {
                continue;
            }

            Doctor doctor = doctorService.selectDoctorById(doctorId);
            if (doctor == null) {
                continue;
            }

            Company company = companyService.selectCompanyById(taskInfo.getCompanyId());
            // company 允许为空的话就不 return，只是流水里公司信息留空
            // 如果公司必须存在，就改成：if (company == null) continue/throw

            // 3.1 加积分（建议内部是 update doctor set points=points+?）
            doctorService.addPoints(doctorId, points);

            // 3.2 写流水
            DoctorBalanceLog log = new DoctorBalanceLog();
            log.setDoctorId(doctor.getId());
            log.setDoctorName(doctor.getDoctorName());

            if (company != null) {
                log.setCompanyId(company.getCompanyId());
                log.setCompanyName(company.getCompanyName());
            }

            // ⚠️ 你这里写的是“业务类别为提现”，语义可能不对
            // 如果你暂时只有这个枚举先用也行，但建议换成“结算/服务单确认”之类
            log.setBusinessId(DoctorWalletBizTypeEnum.SERVICE_ORDER_SETTLEMENT.getCode());
            log.setBusinessType(DoctorWalletBizTypeEnum.SERVICE_ORDER_SETTLEMENT.getDesc());

            // 金额建议存正数，方向由 changeType 表示
            log.setChangeMoney(points.abs());

            BalanceChangeTypeEnum changeType =
                    points.compareTo(BigDecimal.ZERO) > 0
                            ? BalanceChangeTypeEnum.INCREASE
                            : BalanceChangeTypeEnum.DECREASE;
            log.setChangeType(changeType.getCode());

            log.setRelatedTaskId(taskInfo.getId());
            log.setChangeReason(ChangeReasonEnum.WITHDRAW.getCode());

            doctorBalanceLogService.insertDoctorBalanceLog(log);
        }


    }


    @Override
    public ServiceGenResult generateByConfig(ServiceGenConfig cfg) {
        ServiceGenResult result = new ServiceGenResult();

        try {
            if (cfg == null || cfg.getId() == null) {
                result.addError("cfg为空");
                return result;
            }

            // 1) 解析 taskTypes
            List<Long> taskTypeIds = parseTaskTypes(cfg.getTaskTypes());
            if (taskTypeIds.isEmpty()) {
                result.addError("配置未设置任务类型");
                return result;
            }

            // 2) 查待生成任务（你需要实现这个查询）
            //    注意：这里建议一次性把 doctorName 也查出来（join doctor），否则下面你还要查doctor表
            List<TaskInfo> tasks = taskInfoService.selectPendingTasksForGen(
                    cfg.getCompanyId(),
                    cfg.getDepartmentId(),
                    taskTypeIds
            );

            if (tasks == null) tasks = Collections.emptyList();
            result.setTaskTotal(tasks.size());

            if (tasks.isEmpty()) {
                result.setSuccess(true);
                result.setRemark("本次无待生成任务");
                return result;
            }

            // 3) 按医生分组（你说了：不能多个医生共用一个服务单）
            Map<Long, List<TaskInfo>> byDoctor = tasks.stream()
                    .filter(t -> t.getDoctorId() != null)
                    .collect(Collectors.groupingBy(TaskInfo::getDoctorId));

            // 4) 每个医生一张单
            int orderCreated = 0;
            int taskCreated = 0;

            for (Map.Entry<Long, List<TaskInfo>> entry : byDoctor.entrySet()) {
                Long doctorId = entry.getKey();
                List<TaskInfo> doctorTasks = entry.getValue();

                try {
                    // 4.1 先过滤掉已经生成过rel的任务（幂等保险）
                    List<TaskInfo> pending = new ArrayList<>();
                    for (TaskInfo t : doctorTasks) {
                        if (t == null || t.getId() == null) continue;

                        // 已有关联 => 说明之前已经生成过服务单（跳过）
                        boolean exists = iServiceOrderTaskRelService.existsByTaskId(t.getId());
                        if (!exists) {
                            pending.add(t);
                        }
                    }

                    if (pending.isEmpty()) {
                        continue; // 该医生没有可生成的任务
                    }

                    // 4.2 创建服务单（医生业务员）
                    ServiceOrder order = buildSystemServiceOrder(cfg, pending, doctorId);
                    this.insertServiceOrder(order);

                    String serviceOrderNo = "JSD" + String.format("%014d", order.getId());
                    order.setServiceOrderNo(serviceOrderNo);
                    this.updateServiceOrder(order);

                    orderCreated++;

                    // 4.3 挂任务 & 更新任务状态
                    for (TaskInfo t : pending) {
                        ServiceOrderTaskRel rel = new ServiceOrderTaskRel();
                        rel.setServiceOrderId(order.getId());
                        rel.setTaskId(t.getId());
                        iServiceOrderTaskRelService.insertServiceOrderTaskRel(rel);

                        // 标记任务已生成服务单（你原来 generateByTaskId 就这么做）
//                        t.setServiceConfirmStatus(ServiceConfirmStatusEnum.GENERATED.getCode());
                        taskInfoService.updateTaskInfo(t);

                        taskCreated++;
                    }

                    // 4.4 写 result 的 per-doctor 统计（可选）
                    ServiceGenResult.DoctorOrderStat stat = new ServiceGenResult.DoctorOrderStat();
                    stat.setDoctorId(doctorId);
                    stat.setTaskCount(pending.size());
                    stat.setServiceOrderId(order.getId());
                    stat.setServiceOrderNo(order.getServiceOrderNo());
                    result.getDoctorOrderStats().add(stat);

                } catch (Exception e) {
                    result.addError("doctorId=" + doctorId + " 生成失败：" + safeMsg(e));
                    // 这里不抛出，继续下一个医生（避免一个医生影响全局）
                }
            }

            result.setOrderCreated(orderCreated);
            result.setTaskCreated(taskCreated);
            result.setSuccess(result.getErrors().isEmpty());

            if (!result.isSuccess()) {
                result.setRemark(result.buildRemarkForLog(500));
            } else {
                result.setRemark("执行成功");
            }

            return result;

        } catch (Exception e) {
            // 整体级别异常（比如查询就崩）
            result.addError("cfgId=" + (cfg == null ? null : cfg.getId()) + " 执行异常：" + safeMsg(e));
            return result;
        }
    }

    @Override
    public Long selectServiceOrderStatCount(ServiceOrderStatisticsReqVO reqVO) {
        return serviceOrderMapper.selectServiceOrderStatCount(reqVO);
    }

    private List<Long> parseTaskTypes(String taskTypes) {
        if (taskTypes == null || taskTypes.trim().isEmpty()) return Collections.emptyList();
        return Arrays.stream(taskTypes.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(s -> {
                    try {
                        return Long.valueOf(s);
                    } catch (Exception e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
    }

    private String safeMsg(Exception e) {
        String m = e.getMessage();
        if (m == null) return e.getClass().getSimpleName();
        return m.length() > 200 ? m.substring(0, 200) : m;
    }

    /**
     * 用系统用户创建服务单（不走 SecurityUtils.getUserId）
     * 你可以把 initiatorUserId 固定成一个 sys_user 的ID，比如 1
     */
    private ServiceOrder buildSystemServiceOrder(ServiceGenConfig cfg, List<TaskInfo> tasks, Long doctorId) {


        Doctor doctor = doctorService.selectDoctorById(doctorId);
        DoctorCompanyUser doctorCompanyUser = doctorCompanyUserService.selectCompanyUserByDoctorId(doctor.getDoctorId());
        CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.valueOf(doctorCompanyUser.getCompanyUserId()));
        BigDecimal total = tasks.stream()
                .map(TaskInfo::getTaskIntegral)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        Company company = companyService.selectCompanyById(cfg.getCompanyId());
        CompanyDept dept = companyDeptService.selectCompanyDeptById(cfg.getDepartmentId());

        ServiceOrder order = new ServiceOrder();
        order.setServiceOrderNo("TMP" + System.currentTimeMillis());
        order.setCompanyId(cfg.getCompanyId());
        order.setCompanyName(company == null ? null : company.getCompanyName());
        order.setDeptId(cfg.getDepartmentId());
        order.setDeptName(dept == null ? null : dept.getDeptName());

        order.setSettlementMethod(SettlementMethodEnum.WITHDRAW.getCode());
        order.setTaskAmount(total);
        order.setTotalAmount(total);

        order.setAuditStatus(ServiceOrderAuditStatus.NO_AUDIT.getCode().longValue());
        order.setAuditTime(new Date());
        order.setDoctorConfirm(DoctorConfirmEnum.UNCONFIRMED.getCode().longValue());
        order.setSettlementStatus(SettlementStatusEnum.UNSETTLED.getCode());

        // 系统发起人
        order.setInitiatorUserId(companyUser.getUserId());
        order.setInitiatorName(companyUser.getNickName());
        order.setInitiatorPhone(companyUser.getPhonenumber());
        //     医生id
        order.setDoctorId(doctor.getId()+"");
        order.setDoctorName(doctor.getDoctorName());


        return order;
    }
}
