<?php

namespace app\api\controller;

use app\api\QfShop;
use think\facade\Request;
use think\facade\Cache;
use app\model\Source as SourceModel;

class Chatbot extends QfShop
{
    // 应用管理  回调地址：https://XXXX/api/chatbot 填在微信官方 即可
    // 1、应用绑定-网页H5(获取配置)-开放API(申请权限、编辑填写回调地址保存)
    // 2、开放API的三个参数填在下方
    // 3、服务发布
    // 以上三步完成 还不行  就是无缘
    // 无法使用：ping chatbot.weixin.qq.com   延迟太高不行 或者 证书问题
    private $appId = '';
    private $token = '';
    private $encodingAESKey = '';


    // 回复内容在下方，如有需要自行修改
    private $wName = 'XX搜索';

    private $key;

    public function __construct()
    {
        $this->key = base64_decode($this->encodingAESKey . "=");
    }

    public function index()
    {
        $encrypted = input('encrypted');

        //解决全局搜时会多次接收相同消息导致多次请求的bug，原因未知
        if (!empty($encrypted)) {
            if (Cache::get($encrypted) == 1) {
                return;
            }
            Cache::set($encrypted, 1, 600);
        }

        $msg = $this->decryptMessage($encrypted);


        $msgtype = $msg['content']['msgtype'] ?? '';
        $message = $msg['content']['msg'] ?? '';
        if ($msgtype !== 'text' || empty($message)) {
            if (Cache::get($msg['userid']) != 1) {
                $messages = "欢迎来到 " . $this->wName . "！🍿🎬 这里是影迷的梦幻天堂，准备好享受每一部影视的精彩时刻吧！\n\n";
                $messages .= "🔍 使用指南 🔍\n\n";
                $messages .= "1. 搜剧命令\n";
                $messages .= "回复 “搜剧+剧名”，免费获取最全的影视资源。\n";
                $messages .= "示例：<a href='weixin://bizmsgmenu?msgmenucontent=搜剧我被美女包围了&msgmenuid=搜剧我被美女包围了'>搜剧我被美女包围了</a>\n\n";
                $messages .= "2. 全网搜\n";
                $messages .= "回复 “全网搜+关键词”，快速找到全网资源！\n";
                $messages .= "示例：<a href='weixin://bizmsgmenu?msgmenucontent=全网搜学剪辑&msgmenuid=全网搜学剪辑'>全网搜学剪辑</a>\n\n";
                $messages .= "赶快准备好你的爆米花，和我们一起开启下一场视觉盛宴吧！🎥";

                $this->sendMessage($msg, $messages);
            }
            Cache::set($msg['userid'], 1, 604800);
        }
        // 检查用户消息内容中开头第一个字是否包含“搜”关键字
        if (strpos($message, '搜') === 0 || strpos($message, '全网搜') === 0) {

            if (strncmp($message, '全网搜', 1) === 0) {
                $list = [];
                // 去除“全网搜”关键字，提取用户输入的剧名
                $newString = preg_replace('/^全网搜/u', '', $message);
            } else {
                // 去除“搜剧”关键字，提取用户输入的剧名
                $newString = preg_replace('/^搜剧|^搜/u', '', $message);

                // 实例化资源模型，并搜索匹配的剧名
                $map['page_size'] = 5;
                $map['title'] = $newString;
                $SourceModel = new SourceModel();
                $result = $SourceModel->getList($map);
                $list = $result['items'] ?? [];
            }



            if (empty($list)) {
                //系统没有资源去全网搜 
                $this->sendMessage($msg, "正在深入搜索，请稍等...");

                $list = $this->Qsearch($newString);
            }

            $content = "🔍 " . $newString . "丨搜索结果";
            $is_times = 0;
            if (!empty($list)) {
                foreach ($list as $item) {
                    $content = $content . "\n　\n";
                    if (!empty($item['is_time']) && $item['is_time'] == 1) {
                        $content = $content . "\n🌐️ " . $item['title'] . "\n<a href='" . $item['url'] . "'>" . $item['url'] . "</a>";
                        $is_times++;
                    } else {
                        $content = $content . "\n" . $item['title'] . "\n<a href='" . $item['url'] . "'>" . $item['url'] . "</a>";
                    }
                }
                $content = $content . "\n　\n";
                if ($is_times > 0) {
                    $content = $content . "🌐️ 资源来源网络，30分钟后删除";
                } else if (!empty($newString)) {
                    $content = $content . "不是短剧？请尝试：<a href='weixin://bizmsgmenu?msgmenucontent=全网搜" . $newString . "&msgmenuid=全网搜" . $newString . "'>全网搜" . $newString . "</a>";
                }
                // $content = $content . "\n ------------------------------------------------";
                $content = $content . "\n 欢迎观看！如果喜欢可以喊你的朋友一起来哦";
            } else {
                // 如果没有找到匹配的剧名，提示用户减少关键词尝试搜索
                $content = $content . "\n";
                $content = $content . "\n 未找到，可换个关键词尝试哦~";
                $content = $content . "\n ⚠️宁少写，不多写、错写~";
            }
            $this->sendMessage($msg, $content);
        }
    }

    private function Qsearch($newString)
    {
        $bController = app(\app\api\controller\Other::class);
        $result = $bController->all_search($newString);

        return $result;
    }

    // 解密消息
    private function decryptMessage($encrypted)
    {
        $result = $this->decrypt($encrypted, $this->appId);
        if ($result[0] !== 0) {
            return [];
        }
        return json_decode(json_encode(simplexml_load_string($result[1])), true);
    }

    // 发送消息
    private function sendMessage($msg, $message)
    {
        $data = $this->createXmlMessage($msg, $message);
        $result = $this->encrypt($data, $this->appId);

        if ($result[0] !== 0) {
            return;
        }

        $this->sendPostRequest("https://chatbot.weixin.qq.com/openapi/sendmsg/" . $this->token, [
            'encrypt' => $result[1],
        ]);
    }

    // 创建 XML 消息
    private function createXmlMessage($msg, $message)
    {
        return '<xml>
            <appid><![CDATA[' . $msg['appid'] . ']]></appid>
            <openid><![CDATA[' . $msg['userid'] . ']]></openid>
            <msg><![CDATA[' . $message . ']]></msg>
            <channel>' . $msg['channel'] . '</channel>
        </xml>';
    }

    private function sendPostRequest($url, $data)
    {
        $options = [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
            ],
            CURLOPT_POSTFIELDS => json_encode($data),
        ];

        $ch = curl_init();
        curl_setopt_array($ch, $options);

        // 禁用 CA 证书验证
        // curl_setopt($ch, CURLOPT_CAINFO, null);

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            // 处理错误（可添加日志）
            return ['error' => curl_error($ch)];
        }

        curl_close($ch);
        return json_decode($response, true);
    }





    /**
     * 对密文进行解密
     * @param string $encrypted 需要解密的密文
     * @return string 解密得到的明文
     */
    private function decrypt($encrypted, $appid)
    {
        try {
            if (version_compare(PHP_VERSION, '7', '>=')) {
                $iv = substr($this->key, 0, 16);
                $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', substr($this->key, 0, 32), OPENSSL_ZERO_PADDING, $iv);
            } else {
                //使用BASE64对需要解密的字符串进行解码
                $ciphertext_dec = base64_decode($encrypted);
                $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
                $iv = substr($this->key, 0, 16);
                mcrypt_generic_init($module, $this->key, $iv);

                //解密
                $decrypted = mdecrypt_generic($module, $ciphertext_dec);
                mcrypt_generic_deinit($module);
                mcrypt_module_close($module);
            }
        } catch (Exception $e) {
            return [-40007, null];
        }


        try {
            //去除补位字符
            $result = $this->decode($decrypted);
            //去除16位随机字符串,网络字节序和AppId
            if (strlen($result) < 16)
                return "";
            $content = substr($result, 16, strlen($result));
            $len_list = unpack("N", substr($content, 0, 4));
            $xml_len = $len_list[1];
            $xml_content = substr($content, 4, $xml_len);
            $from_appid = substr($content, $xml_len + 4);
            if (version_compare(PHP_VERSION, '7', '>=')) {
                if (!$appid) {
                    //如果传入的appid是空的，则认为是订阅号，使用数据中提取出来的appid
                    $appid = $from_appid;
                }
            }
        } catch (Exception $e) {
            //print $e;
            return [-40008, null];
        }
        if ($from_appid != $appid)
            return [-40005, null];
        //不注释上边两行，避免传入appid是错误的情况
        if (version_compare(PHP_VERSION, '7', '>=')) {
            //增加appid，为了解决后面加密回复消息的时候没有appid的订阅号会无法回复
            return array(0, $xml_content, $from_appid);
        } else {
            return array(0, $xml_content);
        }
        return $encrypted;
    }

    /**
     * 对解密后的明文进行补位删除
     * @param decrypted 解密后的明文
     * @return 删除填充补位后的明文
     */
    private function decode($text)
    {

        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > 32) {
            $pad = 0;
        }
        return substr($text, 0, (strlen($text) - $pad));
    }


    /**
     * 对明文进行加密
     * @param string $text 需要加密的明文
     * @return string 加密后的密文
     */
    private function encrypt($text, $appid)
    {
        try {
            if (version_compare(PHP_VERSION, '7', '>=')) {
                //获得16位随机字符串，填充到明文之前
                $random = $this->getRandomStr();
                $text = $random . pack("N", strlen($text)) . $text . $appid;
                $iv = substr($this->key, 0, 16);
                $text = $this->encode($text);
                $encrypted = openssl_encrypt($text, 'AES-256-CBC', substr($this->key, 0, 32), OPENSSL_ZERO_PADDING, $iv);
            } else {
                //获得16位随机字符串，填充到明文之前
                $random = $this->getRandomStr();
                $text = $random . pack("N", strlen($text)) . $text . $appid;
                // 网络字节序
                $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
                $module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
                $iv = substr($this->key, 0, 16);
                //使用自定义的填充方式对明文进行补位填充
                $text = $this->encode($text);
                mcrypt_generic_init($module, $this->key, $iv);
                //加密
                $encrypted = mcrypt_generic($module, $text);
                mcrypt_generic_deinit($module);
                mcrypt_module_close($module);
                $encrypted = base64_encode($encrypted);
            }

            //print($encrypted);
            //使用BASE64对加密后的字符串进行编码
            return [0, $encrypted];
        } catch (Exception $e) {
            //print $e;
            return [-40006, null];
        }
    }
    /**
     * 对需要加密的明文进行填充补位
     * @param $text 需要进行填充补位操作的明文
     * @return 补齐明文字符串
     */
    private function encode($text)
    {
        $block_size = 32;
        $text_length = strlen($text);
        //计算需要填充的位数
        $amount_to_pad = 32 - ($text_length % 32);
        if ($amount_to_pad == 0) {
            $amount_to_pad = 32;
        }
        //获得补位所用的字符
        $pad_chr = chr($amount_to_pad);
        $tmp = "";
        for ($index = 0; $index < $amount_to_pad; $index++) {
            $tmp .= $pad_chr;
        }
        return $text . $tmp;
    }

    /**
     * 随机生成16位字符串
     * @return string 生成的字符串
     */
    private function getRandomStr()
    {

        $str = "";
        $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($str_pol) - 1;
        for ($i = 0; $i < 16; $i++) {
            $str .= $str_pol[mt_rand(0, $max)];
        }
        return $str;
    }


    private function writeLog($value)
    {
        // 获取当前目录
        $currentDir = __DIR__; // 当前控制器目录
        $logFile = $currentDir . '/log.txt'; // 日志文件名称，可以自定义

        // 生成时间戳
        $timestamp = date('Y-m-d H:i:s');

        // 判断 $value 是否为数组，如果是，则转换为 JSON 字符串
        if (is_array($value)) {
            $value = json_encode($value); // 转换为 JSON 字符串
        }

        $logEntry = "[$timestamp] 参数值: $value\n"; // 日志内容

        // 写入日志文件
        file_put_contents($logFile, $logEntry, FILE_APPEND);
    }
}
