<?php

namespace app\server;

use app\model\Orders;
use Exception;
use support\Log;
use support\Redis;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 同程订单处理
 */
class Tongcheng {
    private $os = '';
    protected $cookie;
    private $gate = 'https://ebk.17u.cn';
    public $totalPage = 6;
    private $tryTimes = 0;

    public function __construct($os = 6)
    {
        $this->cookie = $this->_cookie();
        $this->os = $os;
    }

    /**
     * @throws ModelNotFoundException
     * @throws DataNotFoundException
     * @throws DbException
     * @throws Exception
     */
    public function get($page, $start = null, $end = null, $orderId = '')
    {
        if (empty($start) || empty($end)) {
            $start = date('Y-m-d 00:00:00');
            $end = date('Y-m-d 23:59:59');
        }

        if ($orderId) {
            $start = $end = null;
        }

        $_list = [];
        $list = $this->_certificateList($start, $end, $page, $orderId);
        if (empty($list->data->list) || $list->code != 1000) {
            $this->totalPage = 1;
            return $_list;
        }
        Log::info($start . '--' . $end . " 同程 page:{$page} total_count:" . $list->data->totalCount . " page_count:" . $list->data->totalPage);

        foreach ($list->data->list as $order) {
            Log::info("同程 订单号:{$order->orderId} \n\n");

//            $orderDetail = $this->_orderDetail($order->order_id, $order->status);
//            if (empty($orderDetail)) {
//                Log::info("同程 订单详情拉取失败:{$order->order_id}");
//                throw new Exception("同程拉单{$order->order_id}详情获取失败");
//            }

            $order->orderAmount = $order->orderAmount * 100;
            $item = new Orders();
            $item->os = $this->os;
            $item->sn = $order->orderId;
            $item->product_id = $order->lineId;
            $item->product_name = $order->title;
            $item->category_id = $order->agentFinderId;
            $item->category_desc = $order->agentFinderNickname;
            $item->create_at = strtotime($order->createTime) * 1000;
            $item->mobile = $order->mobile;
            $item->travel_date = null;
            $item->total_price = $order->orderAmount;
            $item->quantity = $order->productCount;
            $item->unit_price = $order->orderAmount/$order->productCount;
            $item->actual_price = $order->orderAmount;
            $item->order_status = $order->orderStatus; // 订单状态(100 - 待付款,150-用户取消,200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成,400-已关闭)
            $item->appointment_status = in_array($order->orderStatus, [210, 310, 300]) ? 1 : 0; // 是否已预约

            $item->asset_status = $order->status ?? 0; // 核销状态
            $item->asset_price = $order->orderStatus == 300 ? $order->orderAmount : 0; // 核销金额
            //抖音的核销金额需要查核销订单

            $_list[] = $item;
        }

        return $_list; //返回半成品
    }

    /**
     * @throws Exception
     */
    public function _certificateList($start, $end, $page, $orderId)
    {
        $params = [
            'begin' => $start,// 开始时间,格式:2024-09-01 00:00:00
            'end' => $end,// 结束时间 格式:2024-09-01 00:00:00
            'orderStatus' => "",// 订单状态
            'current' => $page, // 当前数量
            'size' => 50, // 显示数量
            'orderId' => $orderId, // 订单号
        ];
        $this->_getRetriesLock();

        $list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
        if (empty($list) || $list->code != 1000) {
            $this->_getRetriesLock();
            $list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
            if (empty($list) || $list->code != 1000) {
                Log::error('===查询时间:' . $start . '--' . $end . '====certificate_list: ' . json_encode($list));
                throw new Exception("同程拉单失败,Err:" . json_encode($list));
            }
        }
        return $list;
    }

    public function _getRetriesLock(): bool
    {
        $pattern = 'php webman spider:tc';
        $maxProcesses = 8;
        $this->_killMiddleProcesses($pattern, $maxProcesses);


        $maxRetries = 5;
        $retries = 0;
        while ($retries < $maxRetries) {
            $back = Redis::set('SpiderTc:CertificateList:lock', time(), 'EX', 1, 'NX');
            if ($back) {
                break;
            }
            $retries++;
            sleep(1);
        }
        return true;
    }

    public function _killMiddleProcesses($pattern, $maxProcesses)
    {
        // 检查操作系统是否为 Linux
        if (PHP_OS !== 'Linux') {
            return false;
        }

        // 获取当前进程的 PID
        $currentPid = getmypid();

        // 获取进程列表
        $command = "ps aux | grep '$pattern' | grep -v grep | grep -v '$currentPid' | awk '{print $2,$10}'";
        $output = [];
        exec($command, $output);

        $processList = [];
        foreach ($output as $line) {
            list($pid, $runtime) = explode(' ', $line);
            $runtimeParts = explode(':', $runtime);
            $hours = intval($runtimeParts[0]);
            $minutes = intval($runtimeParts[1]);
            $totalMinutes = $hours * 60 + $minutes;
            $processList[] = ['pid' => $pid, 'runtime' => $totalMinutes];
        }

        // 按运行时间排序
        usort($processList, function ($a, $b) {
            return $a['runtime'] <=> $b['runtime'];
        });

        // 过滤掉当前 PID 和运行时间最短的 PID
        if (!empty($processList)) {
            array_shift($processList); // 移除运行时间最短的
        }
        $processList = array_filter($processList, function ($process) use ($currentPid) {
            return $process['pid'] != $currentPid;
        });

        $processCount = count($processList);

        // 如果进程数量超过最大值,则终止中间部分的进程
        if ($processCount > $maxProcesses) {
            $processesToKill = $processCount - $maxProcesses;
            $processesKilled = 0;

            // 杀死运行时间最短的进程
            foreach ($processList as $process) {
                if ($processesKilled >= $processesToKill) {
                    break;
                }

                exec("kill -9 {$process['pid']}");
                $processesKilled++;

                Log::info("Killed process with PID: {$process['pid']}\n");
            }

            if ($processesKilled === 0) {
                Log::info("No processes to kill.\n");
            }
        } else {
            Log::info("Process count is not over the limit.\n");
        }

        return true;
    }


    public function _orderDetail($orderId = null, $status = null)
    {
        $orderDetail = $this->_curl("/life/trip/v2/travel_agency/book/detail", [
            'order_id' => $orderId,
            'book_order_id' => '',
            'status' => $status,
        ]);
        return $orderDetail->data ?? null;
    }

    public function _cookie($data = '')
    {
        $key = 'Tongcheng:cookie-' . $this->os;
        if ($data) Redis::set($key, $data);
        return Redis::get($key);
    }

    public function _curl($url, $params, $method = 'GET')
    {
        // 请求次数统计
        $key   = sprintf("Tongcheng:ReqiestCount:%s", date('Y-m-d'));
        $requestCount = Redis::incrBy($key, 1);
        if ($requestCount == 1) {
            Redis::expire($key, 604800); // 7天
        }
        $cookiePath = sprintf(runtime_path() . '%s_tc_cookie.txt', $this->os);

        $http = $this->gate . $url;
        if ($method == 'GET') {
            $http = $http . '?' . http_build_query($params);
        }

        $ch = curl_init($http);

        $header = [
            'Content-type: application/json'
        ];
        if ($method == 'GET' || $method == 'POST') {
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        } else {
            curl_setopt($ch, CURLOPT_HEADER, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiePath);
        }
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie());
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiePath);
        if ($method == 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
        }
        $body = curl_exec($ch);
        curl_close($ch);
        if (!in_array($method, ['GET', 'POST'])) {
            $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
            $header = substr($body, 0, $header_size);
            $in = explode("\n", $body);
            foreach ($in as $i) {
                if (stripos($i, 'x-ware-csrf-token') !== false) {
                    $inn = explode(',', $i);
                    return $inn[1];
                }
            }
            return null;
        }

        $res = json_decode($body);
        if (!isset($res->code) || $res->code != 1000) {
            Log::info( "同城 body:{$body} \n\n");
            if ($this->tryTimes > 1) {
                (new ThirdApiService())->weComNotice($this->os);
            }
            $this->tryTimes++;
        }
        return $res;
    }
}