<?php

namespace App\Services\Admin\YeWu;

use App\Http\Controllers\API\Third\CSharpController;
use App\Services\SendMessgeService;
use DateInterval;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use DateTime;
use Illuminate\Support\Facades\Log;
use Tools;

class PlanListService
{
    public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $appointment_date)
    {
        date_default_timezone_set('PRC');

        $allEmergency = true;
        $allDevice = [];//所有医嘱检查项目绑定的设备id
        $commPatientType = [];//所有医嘱共同的病人类型
        $zhanweiCount=0;//勾选的检查项目共计占多少名额
        foreach ($entrustids as $key => $entrustid) {
//            $info = DB::table('s_list')->where(['reg_num' => $regnum, 'entrust_id' => $entrustid, 'episodeid' => $episodeid, 'is_nullify' => 0])->first();
            $info = DB::table('s_list')->where(['entrust_id' => $entrustid, 'is_nullify' => 0])->first();
            if (!$info) return \Yz::echoError1('没有找到对应医嘱信息:'.$entrustid);

            if (!isset($info->his_is_emergency) || $info->his_is_emergency != 1) {
                $allEmergency = false;
            }

            $itemInfo = DB::table('s_check_item')->where(['item_name' => $info->entrust, 'status' => 1, "is_del" => 0])->get();
            if (count($itemInfo) == 0) return \Yz::echoError1('没有找到可用的检查项目信息');
            $itemInfo = $itemInfo[0];
            $zhanweiCount+=isset($itemInfo->use_seats)?$itemInfo->use_seats:0;
            $qudaos = explode(',', $itemInfo->reservation_method);
            //只判断主渠道，如果主渠道支持，则子渠道默认也支持，即使项目没绑定子渠道
            if (!in_array($appointment_type, $qudaos)) return \Yz::echoError1('此检查项目不支持在当前渠道预约');



            //获取检查项目绑定的服务组(设备),判断状态正常的
            $devices = DB::table('s_check_item_device')
                ->leftJoin("s_devices", "s_check_item_device.device_id", "=", "s_devices.id")
                ->where(['s_check_item_device.item_id' => $itemInfo->id])
                ->where(['s_devices.status' => 1, 'is_del' => 0])->pluck('s_devices.id')->toArray();
            $allDevice[] = $devices;

            if (!in_array($info->patient_type, $commPatientType)) {
                // 如果不在数组中，则添加它
                array_push($commPatientType, $info->patient_type);
            }
        }

        $commonDevice = []; //多个检查项目共同的设备id
        foreach ($allDevice as $set) {
            if (count($commonDevice) == 0) {
                // 如果$intersection为空，直接将第一个子数组的元素放入
                $commonDevice = $set;
            } else {
                // 使用array_intersect()函数求当前子数组与已有交集的交集
                $commonDevice = array_intersect($commonDevice, $set);
            }
        }
        // dd($commonDevice);

        //获取主表检查项目绑定的科室id
        $department_id = DB::table('s_department')->where(['department_number' => $info->RISRAcceptDeptCode])->first();
        if (!$department_id) return \Yz::echoError1('获取医嘱检查项目科室信息失败');

        //查询号源渠道是否有合并
        $appointment_types=[$appointment_type];
        $appointment_type_link = DB::table('s_appointment_type_ratio')->where(['department_id'=>$department_id->id,'appointment_type_id' => $appointment_type])->first();
        if (!empty($appointment_type_link->link)) {
            $appointment_types=json_decode($appointment_type_link->link, true);
            $appointment_types=array_merge($appointment_types, [$appointment_type]);
        }


        if(count($commonDevice)==0) return \Yz::echoError1("无可用号源");
        $placeholders = implode(',', array_fill(0, count($commonDevice), '?'));
        $appointment_types_placeholders = implode(',', array_fill(0, count($appointment_types), '?'));

        //如果日期为字符串 则转为数组
        $appointment_date_arr=[];
        if(is_array($appointment_date)){
            $appointment_date_arr=$appointment_date;
            $appointment_date=implode(',', $appointment_date);
        }else{
            $appointment_date_arr=[$appointment_date];
        }
        $appointment_dates_placeholders = implode(',', array_fill(0, count($appointment_date_arr), '?'));


        $canshu = array_merge($commonDevice, [$department_id->id], $appointment_date_arr, $appointment_types);
        $plan = DB::select("SELECT
	a.*,
	dd.devices,
	b.department_resources_name,
	c.roster_detail_id,
	c.count,
	c.used_count,
	c.locked_count
FROM
	s_source_roster_detail AS a
	LEFT JOIN s_department_resources AS b ON a.resources_id = b.id
	LEFT JOIN s_source_roster_detail_count AS c ON a.id = c.roster_detail_id
	 JOIN (
	SELECT
		roster_detail_id,
		GROUP_CONCAT( e.device_name SEPARATOR ', ' ) AS devices
	FROM
		s_source_roster_detail_device AS d
		LEFT JOIN s_devices AS e ON d.device_id = e.id
	WHERE
		d.device_id IN ($placeholders)
	GROUP BY
		d.roster_detail_id
	) AS dd ON a.id = dd.roster_detail_id
WHERE
	a.department_id = ?
	AND a.date IN ($appointment_dates_placeholders)
	AND a.STATUS = 1
	AND a.is_del = 0
	AND b.is_del = 0
	AND c.appointment_type_id IN ($appointment_types_placeholders)", $canshu);

        $mergedPlan = [];
        foreach ($plan as $key => $p) {
            // 将占位数量加到已用数量中
            $p->used_count = $p->used_count + ($p->locked_count ?? 0);

            // 如果 roster_detail_id 已经存在，则合并 count 数量
            if (isset($mergedPlan[$p->roster_detail_id])) {
                // 累加 count 数量到已存在的记录中
                $mergedPlan[$p->roster_detail_id]->count += $p->count;
                $mergedPlan[$p->roster_detail_id]->used_count += $p->used_count;
            } else {
                // 初始化新的合并数据
                $mergedPlan[$p->roster_detail_id] = $p;
            }
        }

// 将合并后的数据重新组织为数组
        $plan = array_values($mergedPlan);
        //遍历列表 把超过当前时间的放在后面
        $pl1 = [];
        $pl2 = [];
        $pp = [];
        $nowtime = date('Y-m-d H:i:s');
        foreach ($plan as $key => $p) {
//            //病人类型不符合的过滤掉
            $planPatientType = explode(",", $p->patient_type);
            if (!empty(array_diff($commPatientType, $planPatientType))) {
                continue;
            }
            //过期的排在后面
            $time = $p->date . ' ' . $p->end_time;
            if ($time > $nowtime) {
                $p->plan_enable=true;
                $pl1[] = $p;
            } else {
                $p->plan_enable=false;
                $pl2[] = $p;
            }
        }

        usort($pl1, function($a, $b) {
            $timeA = $a->date . ' ' . ($a->start_time ?? $a->end_time); // 兼容性处理
            $timeB = $b->date . ' ' . ($b->start_time ?? $b->end_time);
            return $timeA <=> $timeB;
        });

// 取出时间最早的那一个（未过期）
        $earliestPlan = !empty($pl1) ? $pl1[0]->id : null;  //最早的号源id

        $pp = array_merge($pl1, $pl2);


        return \Yz::Return(true, '查询完成', [
            'today_date' => date("Y-m-d"),
            'appointment_date' => $appointment_date,
            'weekname' => Tools::GetWeekName($appointment_date),
            'mainInfo' => $info,
            'plan_list' => $pp,
            'zhanWeiCount'=>$zhanweiCount,
            'earliestPlan'=>$earliestPlan,
            'is_emergency' => $allEmergency,
        ]);
    }

    //开始预约占用名额
    public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_emergency=0,$do_user=null)
    {
        date_default_timezone_set('PRC');
        $nowdatetime = date("Y-m-d H:i:s");

        if ($is_emergency == 1 && !empty($do_user)) {//如果是加急，校验用户是否有加急权限
            $do_user_info=DB::table('users')->where('id',$do_user)->first();
            if(!$do_user_info){
                return \Yz::echoError1('无效的用户ID，无法进行加急预约');
            }else{
                $special_privileges=[];
                $decoded=json_decode($do_user_info->special_privileges,true);
                if(is_array($decoded)){
                    $special_privileges=$decoded;
                }
                if(!in_array('emergency', $special_privileges)){
                    return \Yz::echoError1('无权进行加急预约');
                }
            }
        }else{
            $is_emergency=0;
        }

        $planInfo = DB::table('s_source_roster_detail')->where(['id' => $planid, 'status' => 1, 'is_del' => 0])->first();
        if (!$planInfo) return \Yz::echoError1('当前时段不可用');
        if ($nowdatetime > $planInfo->date . ' ' . $planInfo->end_reservation_time) return \Yz::echoError1('已经超过预约截止时间');

        $zhanweiCount=0;//各个检查项目需要占用检查名额的总和
        $huchiList=[];//互斥item_id对应关系
        $oldMainInfos = [];//临时存储原来的主表信息，用于改约
        //遍历多个s_list表id,前端多选，一次预约多个检查项目
        foreach ($mainlistids as $key_m => $mainlistid) {
            $mainInfo = DB::table('s_list as a')
                ->select('a.*', 'b.period_begin_time', 'b.period_end_time')
                ->leftJoin('s_period as b', 'a.reservation_time', '=', 'b.id')
                ->where(['a.id' => $mainlistid])->first();
            $oldMainInfos[] = $mainInfo;
            if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
            //判断状态
            $msg_t = "";
            if ($mainInfo->list_status == 0) {
                $msg_t = "当前状态为待预约";
            }
            if ($mainInfo->list_status == 1) {
                $msg_t = "已经在" . $mainInfo->reservation_date . '的' . $mainInfo->period_begin_time . '-' . $mainInfo->period_end_time . '预约成功，不能再次预约';
            }
            if ($mainInfo->list_status == 2) {
                $msg_t = "当前状态为已登记";
            }
            if ($mainInfo->list_status == 3) {
                $msg_t = "当前状态为已完成";
            }
            if ($do_type == 1 && $mainInfo->list_status <> 0) return \Yz::echoError1($mainInfo->entrust . ' ' . $msg_t . ',禁止预约');
            if ($do_type == 2 && $mainInfo->list_status <> 1) return \Yz::echoError1($mainInfo->entrust . ' ' . $msg_t . ',不允许改约操作');
            if ($do_type == 2 && $mainInfo->roster_id == $planid) return \Yz::echoError1($mainInfo->entrust . ' '  . ',改约时间与之前相同，无需改约');


            //判断病人类型
            $plan_patient_type=explode(",", $planInfo->patient_type);
            if(!in_array($mainInfo->patient_type, $plan_patient_type))  return \Yz::echoError1('当前计划不支持此病人类型');

            //判断互斥（暂时根据reg_num判断身份）
            //查询想要预约的项目 其自身code
            $item = DB::table('s_check_item')->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])->first();
            if (!$item) return \Yz::echoError1('此检查项目不可用');
            $zhanweiCount+=$item->use_seats;
            //医嘱开具后，预约时间需在设定的等待期之后,单位分钟
            $entrust_time = $mainInfo->entrust_date . ' ' . $mainInfo->entrust_time;  //医嘱时间
            $date = new DateTime($entrust_time);
            $date->modify("+" . $item->check_begin_time . " minutes");
            $enableCheckTime = $date;//到此时间后可进行预约
            $plan_dateTime = $planInfo->date . ' ' . $planInfo->end_time;
            $plan_dateTime = new DateTime($plan_dateTime);
            if ($plan_dateTime < $enableCheckTime and $item->check_begin_time>0) return \Yz::echoError1($item->item_name . " 已设置只能预约医嘱开具后" . $item->check_begin_time . "分钟后的时间，请预约" . $enableCheckTime->format("Y-m-d H:i:s") . "之后的时间");

            //检测是否空腹
            $configs = DB::table('configs')->where('label', '开启空腹')->first();
            if ($item->limosis == 1 and $planInfo->end_reservation_time > '12:00:00' and $configs->value == 1) return \Yz::echoError1($item->item_name . ' 项目必须空腹，只能预约上午，请重新选择时间');
            //查询当前检查项目是否存在互斥
            $cha_hc = DB::table('s_huchi')->where('is_del', 0)
                ->where(function ($q) use ($item) {
                    $q->where(['code1' => $item->item_code])->orWhere('code2', $item->item_code);
                })->get();
            foreach ($cha_hc as $hc) {
                $huchiList[]=[$hc->code1,$hc->code2];
            }
            if (count($cha_hc) > 0) {

                //查询用户预约中的医嘱
                $status_1 = DB::table('s_list')
                    ->select('s_check_item.item_code', 's_list.entrust', 's_list.reservation_date', 's_list.reservation_time')
                    ->leftJoin('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
                    ->where(['s_list.reg_num' => $mainInfo->reg_num, 's_list.list_status' => 1, 's_list.is_del' => 0, 's_list.is_nullify' => 0])
                    //排除自身，自己不能互斥自己
                    ->whereNotIn('item_name', [$mainInfo->entrust])
                    ->get();
                if (count($status_1) > 0) {
                    foreach ($status_1 as $key => $value) {
                        foreach ($cha_hc as $k => $v) {
                            if ($v->code1 == $value->item_code or $v->code2 == $value->item_code) {
                                if ($v->time == 0) {
                                    //如果是永久互斥，直接拒绝
                                    return \Yz::Return(false, '当前预约项目与' . $value->entrust . '互斥，暂不可预约', ['name' => $value->entrust]);
                                }
                                if ($v->time > 0) {
                                    //如果设置互斥时间，则判断预约时间是否超过  正在预约的最后时间段+互斥时间
                                    $period = DB::table('s_period')->where(['id' => $value->reservation_time])->first();
                                    $endTime = $period->period_end_time;
                                    $periodEndDateTime = $value->reservation_date . ' ' . $endTime;
                                    $date = new DateTime($periodEndDateTime);
                                    // 添加互斥时间/小时
                                    $date->add(new \DateInterval('PT' . $v->time . 'H')); // PTXH 表示X小时的时间间隔
                                    $HuChi_EndDateTime = $date->format('Y-m-d H:i:s');//已经预约的项目结束互斥时间
                                    $YuYueDateTime = substr($planInfo->date, 0, 10) . ' ' . $planInfo->begin_time;
                                    if ($HuChi_EndDateTime > $YuYueDateTime) {
                                        return \Yz::Return(false, '当前预约项目与' . $value->entrust . '互斥，暂不可预约,请预约' . $HuChi_EndDateTime . '后的日期', ['name' => $value->entrust]);
                                    }

                                }

                            }
                        }
                    }
                }
            }

        }

        //查询号源渠道是否有合并
        $appointment_types=[$appointment_type];
        $appointment_type_link = DB::table('s_appointment_type_ratio')->where(['department_id'=>$planInfo->department_id,'appointment_type_id' => $appointment_type])->first();
        if (!empty($appointment_type_link->link)) {
            $appointment_types=json_decode($appointment_type_link->link, true);
            $appointment_types=array_merge($appointment_types, [$appointment_type]);
            sort($appointment_types);
        }

        $roster_detail_counts = DB::table('s_source_roster_detail_count')
            ->where(['roster_detail_id' => $planid])
            ->whereIn('appointment_type_id', $appointment_types)
            ->orderBy('appointment_type_id','asc')
            ->get();
        $planZongCount=0;//合并后的各个渠道总名额
        $planZongUsedCount=0;//合并后的各个渠道已预约的名额
        $planZongLockedCount=0;//合并后的各个渠道占位名额
        $plan_qudao_tempCount=[];//拆分各个渠道需要占用的名额
        $weifenpeiCount=$zhanweiCount;//未分配的名额
        foreach ($roster_detail_counts as $roster_detail_count) {
            $planZongCount+=$roster_detail_count->count;
            $planZongUsedCount+=$roster_detail_count->used_count;
            $planZongLockedCount+=($roster_detail_count->locked_count ?? 0);
            $keyongCount=$roster_detail_count->count - $roster_detail_count->used_count - ($roster_detail_count->locked_count ?? 0);
            if($weifenpeiCount-$keyongCount>=0){
                $plan_qudao_tempCount[]=$keyongCount;
                $weifenpeiCount-=$keyongCount;
            }else{
                $plan_qudao_tempCount[]=$weifenpeiCount;
                $weifenpeiCount=0;
            }

        }
        if ($planZongCount < ($planZongUsedCount + $planZongLockedCount + $zhanweiCount)){
            if($is_emergency!==1){
                return \Yz::echoError1('当前预约时间名额不足');
            }else{                                                                 //如果是紧急预约，则把未分配的 强制加到当前预约渠道
                foreach ($roster_detail_counts as $key=> $roster_detail_count) {
                    if($roster_detail_count->appointment_type_id==$appointment_type){
                        $plan_qudao_tempCount[$key]=$weifenpeiCount;
                    }
                }
            }
        }



        //判断某人这些待预约项目里，是否存在互斥
        $userGroup=[];
        foreach ($oldMainInfos as $key1 => $value1) {
            $reg_num = $value1->reg_num;
            if (!isset($userGroup[$reg_num])) {
                $userGroup[$reg_num] = [];
            }
            $userGroup[$reg_num][]=[
                'reg_num' => $value1->reg_num,
                'user_name' => $value1->user_name,
                'entrust_code' => $value1->entrust_code,
                'entrust' => $value1->entrust,
            ];
        }
       // $huchiList

        foreach ($userGroup as $personEntry) {
                $ids = array_column($personEntry, 'entrust_code');
                if ($this->isMutuallyExclusive($ids, $huchiList)) {
                    return \Yz::echoError1($personEntry[0]['user_name'].'勾选的项目存在互斥，不可同时预约');
                }
        }
        DB::beginTransaction();
        try {
            //更新计划明细表使用数量
            $up_plan_count_all_success =true;
            $appointment_use_plan_detail_arr=[];//预约各个号源占用号源详情
            foreach ($roster_detail_counts as $key => $planCount) {
                if($plan_qudao_tempCount[$key]==0) continue;

                $query = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id]);
                // 【核心修改】只有非紧急预约时，才检查名额是否充足
                if ($is_emergency!==1) {
                    $query->whereRaw('count >= (used_count + IFNULL(locked_count, 0) + ?)', [$plan_qudao_tempCount[$key]]);
                }
                $u = $query->increment('used_count', $plan_qudao_tempCount[$key]);

                if(!$u){
                    $up_plan_count_all_success=false;
                    break;
                }
                $appointment_use_plan_detail_arr[]=[
                    "roster_detail_count_id"=>$planCount->id,
                    "count"=>$plan_qudao_tempCount[$key],
                ];
            }

            if ($up_plan_count_all_success) {
                foreach ($roster_detail_counts as $key => $planCount) {
                    $cha = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->first();
                    if ($is_emergency!==1) {
                        if ($cha->count < $cha->used_count + ($cha->locked_count ?? 0)) {
                            DB::rollBack();
                            return \Yz::echoError1('操作失败1');
                        }
                    }

                }
            }else{
                DB::rollBack();
                return \Yz::echoError1('操作失败');
            }

           //排队号
            $xvhao=0;
           $xvhao= $this->generateQueueNumber($planInfo->id);
                    //更新主表信息
                    $u_data = [
                        'list_status' => 1,
                        'reservation_date' => $planInfo->date,
                        'reservation_time' => $planInfo->period_id,
                        'reservation_sources' => $planInfo->resources_id,
                        'services_group' => $planInfo->device_id,
                        'roster_id' => $planInfo->id,
                        'department_id' => $planInfo->department_id,
                        'xuhao' => $xvhao,
                        'appointment_type_id' => $appointment_type,
                        'qudao_appointment_type_id' => $appointment_type,
                        'appointment_use_plan_detail'=>$appointment_use_plan_detail_arr
                    ];
            $list_all_success =true;
            $offset = 0;
            $u_mainList=false;
            foreach($plan_qudao_tempCount as $key=>$length){
                if($length==0) continue;
                $u_data['appointment_type_id']= $appointment_types[$key];

                // 获取当前批次的记录 ID
                $currentBatchIds = array_slice($mainlistids, $offset, $length);//这块逻辑得优化，之前是1个项目占位1个，现在有可能1个项目占位多个

                foreach ($currentBatchIds as $id) {
                    // 为当前记录生成唯一的排队号
                    $xuhao = $this->generateQueueNumber($planInfo->id);
                    // 更新当前记录的数据（包括 xuhao）
                    $u_data['xuhao'] = $xuhao;
                    $u_mainList = DB::table('s_list')
                        ->where('id', $id)
                        ->update($u_data);

                    if (!$u_mainList) {
                        $list_all_success = false;
                        break 2; // 如果更新失败，跳出外层循环
                    }
                }

                $offset += $length;
            }
            if (!$list_all_success) {
                DB::rollBack();
                return \Yz::echoError1('预约失败');
            }

                    $note = "预约";
                    foreach ($oldMainInfos as $key => $oldMainInfo) {

                        if ($do_type == 2) {
                            //  if(count($mainlistids)>1)   return \Yz::echoError1('请选择1条医嘱改约，暂不支持批量');
                            $note = "改约";
                            //如果是改约，则恢复原来的数量
                            $useDetailJson = $oldMainInfo->appointment_use_plan_detail;
                            if (empty($useDetailJson)) {
                                return \Yz::echoError1('取消失败：缺少占位明细数据，无法精确回退，请联系管理员');
                            }
                            $useDetails = json_decode($useDetailJson, true);
                            if (!is_array($useDetails)) {
                                return \Yz::echoError1('取消失败：占位明细数据格式错误');
                            }
                            foreach ($useDetails as $detail) {
                                $rosterDetailCountId = $detail['roster_detail_count_id'] ?? null;
                                $countToRelease = (int)($detail['count'] ?? 0);

                                if (!$rosterDetailCountId || $countToRelease <= 0) {
                                    continue;
                                }
                                $affected = DB::table('s_source_roster_detail_count')
                                    ->where(['id' => $rosterDetailCountId])
                                    ->lockForUpdate()
                                    ->where('used_count', '>=', $countToRelease) // 防御性编程：确保不会减成负数
                                    ->decrement('used_count', $countToRelease);
                                if ($affected == 0) {
                                    // 如果 affected 为 0，可能是记录不存在，或者 used_count 不足
                                    $checkRecord = DB::table('s_source_roster_detail_count')->where(['id' => $rosterDetailCountId])->first();
                                    if (!$checkRecord) {
                                        Log::error("改约-号源记录缺失", [
                                            'MainListId' => $oldMainInfo->id,
                                            'count_id' => $rosterDetailCountId
                                        ]);
                                    }
                                    if ($checkRecord->used_count < $countToRelease) {
                                        // 【关键修改】：余额不足，但不阻断取消
                                        $actualRelease = $checkRecord->used_count; // 最多只能退这么多

                                        if ($actualRelease > 0) {
                                            // 把剩余的余额全部退完，强制设为 0 (或者 decrement actualRelease)
                                            DB::table('s_source_roster_detail_count')
                                                ->where(['id' => $rosterDetailCountId])
                                                ->update(['used_count' => 0]); // 直接置零，防止浮点数或并发问题
                                        }

                                        // 记录严重报警日志
                                        $msg = "数据不一致警告：订单 {$oldMainInfo->id} 试图退还 {$countToRelease} 个名额，但渠道 {$rosterDetailCountId} 仅剩 {$checkRecord->used_count} 个。";
                                        Log::error($msg);
                                    }
                                }
                            }

                        }

                        $i_log = DB::table('s_list_log')->insert([
                            'list_id' => $oldMainInfo->id,
                            'reg_num' => $oldMainInfo->reg_num,
                            'old_status' => $oldMainInfo->list_status,
                            'new_status' => 1,
                            'create_user' => $do_user,
                            'note' => $note,
                            'data' => json_encode($u_data)
                        ]);
                    }
                    if ($u_mainList) {
                        DB::commit();
                        if(config('app.globals.预约完成短信通知')==1){
                            $this->SendMsg($oldMainInfos,$do_type);
                        }
                        return \Yz::Return(true, '预约成功', ['planid' => $planid, 'mainlistids' => $mainlistids]);
                    } else {
                        DB::rollBack();
                        return \Yz::echoError1('预约失败');
                    }





        } catch (\Exception $e) {
            DB::rollBack();
            return \Yz::echoError1('预约异常' . $e->getMessage());
        }


    }
    public function AutoYuYue($regnum,$entrustids,$episodeid,$appointment_type)
    {
        $dateRange=config('app.globals.可用号源查询范围');
//        $regnum = request('regnum');
//        $entrustids = request('entrustid');
//        $episodeid = request('episodeid');
//        $appointment_type = request('appointment_type'); //预约类型
        $TodayDateTime = date("Y-m-d H:i:s");


        $startDate = new DateTime();
        // 设定结束日期为当前日期加7天
        $endDate = new DateTime();
        $endDate->modify('+' . $dateRange . ' day');
        // 循环遍历每一天
        $currentDate = $startDate;
        $enable_plan=false;
        while ($currentDate <= $endDate) {
            $nowdate = $currentDate->format('Y-m-d');
            $s = $this->GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $nowdate);

            if ($s['status']) {
                $list = $s['data']['plan_list'];
                if (count($list) > 0) {
                    foreach ($list as $k => $v) {
                        if($v->count-$v->used_count>0 and $TodayDateTime< $v->date.' '.$v->end_reservation_time){
                            $enable_plan=$v;
                            break;
                        }
                    }
                    if(!!$enable_plan){
                        break;
                    }
                }
            }

            // 每次循环增加一天
            $currentDate->modify('+1 day');
        }
        if(!!$enable_plan){
            $mainlistids=DB::table('s_list')->whereIn('entrust_id',$entrustids)->pluck('id')->toArray();
            $yuyue=$this->YuYue($enable_plan->id, $appointment_type, $mainlistids, 1);
            if($yuyue['status']==false){
                return \Yz::echoError1($yuyue['msg']);
            }
            if($yuyue['status']===true){
                return \Yz::Return(true,"预约成功",['entrust_id'=>$entrustids,'date'=>$enable_plan->date,'begin_time'=>$enable_plan->begin_time,'end_time'=>$enable_plan->end_time]);
            }

        }else{
            return \Yz::echoError1('最近'.$dateRange.'日无可用号源');
        }
    }

    public function CancelYuYue($MainListId, $reg_num,$do_user=null)
    {
        date_default_timezone_set('PRC');
        $nowdatetime = date("Y-m-d H:i:s");

        // 开启数据库事务
        DB::beginTransaction();
        try {
            // 1. 查询并锁定主预约记录（防并发）
            $mainInfo = DB::table('s_list')
                ->where(['id' => $MainListId, 'reg_num' => $reg_num])
                ->lockForUpdate()
                ->first();

            if (!$mainInfo) {
                return \Yz::echoError1('医嘱不存在');
            }

            // 2. 检查当前状态是否允许取消（仅状态为1可取消）
            if ($mainInfo->list_status != 1) {
                return \Yz::echoError1('该记录无法取消，当前状态：' . $mainInfo->list_status);
            }
            $useDetailJson = $mainInfo->appointment_use_plan_detail;
            if (empty($useDetailJson)) {
                return \Yz::echoError1('取消失败：缺少占位明细数据，无法精确回退，请联系管理员');
            }
            $useDetails = json_decode($useDetailJson, true);
            if (!is_array($useDetails)) {
                return \Yz::echoError1('取消失败：占位明细数据格式错误');
            }
            foreach ($useDetails as $detail) {
                $rosterDetailCountId = $detail['roster_detail_count_id'] ?? null;
                $countToRelease = (int)($detail['count'] ?? 0);

                if (!$rosterDetailCountId || $countToRelease <= 0) {
                    continue;
                }
                $affected = DB::table('s_source_roster_detail_count')
                    ->where(['id' => $rosterDetailCountId])
                    ->lockForUpdate()
                    ->where('used_count', '>=', $countToRelease) // 防御性编程：确保不会减成负数
                    ->decrement('used_count', $countToRelease);
                if ($affected == 0) {
                    // 如果 affected 为 0，可能是记录不存在，或者 used_count 不足
                    $checkRecord = DB::table('s_source_roster_detail_count')->where(['id' => $rosterDetailCountId])->first();
                    if (!$checkRecord) {
                        Log::error("取消预约-记录缺失", [
                            'MainListId' => $MainListId,
                            'count_id' => $rosterDetailCountId
                        ]);
                    }
                    if ($checkRecord->used_count < $countToRelease) {
                        // 【关键修改】：余额不足，但不阻断取消
                        $actualRelease = $checkRecord->used_count; // 最多只能退这么多

                        if ($actualRelease > 0) {
                            // 把剩余的余额全部退完，强制设为 0 (或者 decrement actualRelease)
                            DB::table('s_source_roster_detail_count')
                                ->where(['id' => $rosterDetailCountId])
                                ->update(['used_count' => 0]); // 直接置零，防止浮点数或并发问题
                        }

                        // 记录严重报警日志
                        $msg = "数据不一致警告：订单 {$MainListId} 试图退还 {$countToRelease} 个名额，但渠道 {$rosterDetailCountId} 仅剩 {$checkRecord->used_count} 个。";
                        Log::error($msg);
                    }
                }
            }

            // 8. 更新主表状态为“已取消”（0）
            $u_data = [
                'list_status'           => 0,
                'reservation_date'      => null,
                'reservation_time'      => null,
                'reservation_sources'   => null,
                'services_group'        => null,
                'roster_id'             => null,
                'xuhao'                 => null,
                'department_id'         => null,
                'appointment_type_id'   => null,
                'canel_time'            => $nowdatetime,
            ];

            $u_mainList = DB::table('s_list')->where(['id' => $MainListId])->update($u_data);

            // 9. 写入操作日志
            $i_log = DB::table('s_list_log')->insert([
                'list_id'       => $mainInfo->id,
                'reg_num'       => $mainInfo->reg_num,
                'old_status'    => $mainInfo->list_status,
                'new_status'    => 0,
                'create_user'   => $do_user,
                'note'          => '取消预约',
                'data'          => json_encode($u_data, JSON_UNESCAPED_UNICODE),
                'created_at'    => $nowdatetime,
            ]);

            // 10. 提交事务
            DB::commit();

            return \Yz::Return(true, '取消成功', []);

        } catch (\Exception $e) {
            DB::rollBack();
            // 记录错误日志（建议使用 Laravel 日志系统）
           Log::error("取消预约失败 - ID: {$MainListId}, reg_num: {$reg_num}, 错误: " . $e->getMessage());
            return \Yz::echoError1('取消失败：系统异常，请稍后重试');
        }
    }
    //短信提醒
    public function SendMsg($infos,$dotype=1)
    {

        $s=new SendMessgeService();
        foreach ($infos as $key => $info) {
            $mainInfo = DB::table('s_list as a')
                ->select('a.*', 'b.period_begin_time', 'b.period_end_time')
                ->leftJoin('s_period as b', 'a.reservation_time', '=', 'b.id')
                ->where(['a.id' => $info->id])->first();
           $s->sendMessage($info->user_phone,'测试短信,项目:'.$mainInfo->entrust.',时间：'.$mainInfo->reservation_date.' '.substr($mainInfo->period_begin_time,0,5).'-'.substr($mainInfo->period_end_time,0,5));
        }
    }

    //判断是否在互斥组内
    function isMutuallyExclusive($ids, $huchi) {
        foreach ($huchi as $pair) {
            if (in_array($pair[0], $ids) && in_array($pair[1], $ids)) {
                return true;
            }
        }
        return false;
    }
    //获取排队号，思路：获取主表内使用这个plan_id的医嘱，获取已生成排队号最大的一个数，加1。如果中间有断号，则选择断号中最小的一个
    function generateQueueNumber($planId)
    {
        DB::transaction(function () use ($planId, &$queueNumbers) {
            // 使用悲观锁锁定相关行，确保同一时间只有一个进程操作
            $queueNumbers = DB::table('s_list')
                ->where(['roster_id' => $planId, 'is_del' => 0, 'is_nullify' => 0])
                ->lockForUpdate() // 关键修改：添加行级锁
                ->pluck('xuhao')
                ->filter()
                ->map(fn($num) => (int)$num)
                ->sort();
        });

        if ($queueNumbers->isEmpty()) {
            return 1;
        }

        $maxQueueNumber = $queueNumbers->max();
        $minAvailableNumber = null;

        for ($i = 1; $i <= $maxQueueNumber; $i++) {
            if (!$queueNumbers->contains($i)) {
                $minAvailableNumber = $i;
                break;
            }
        }

        return $minAvailableNumber ?? $maxQueueNumber + 1;
    }
}
