<?php

namespace App\Http\Controllers\V1\Ai;

use App\Auth;
use App\Http\Controllers\V1\Controller;
use App\libs\helpers\Helper;
use App\libs\helpers\LogHelper;
use App\libs\helpers\Response;
use App\Models\Config;
use App\Models\Keyword;
use App\Models\TaskList;
use App\Models\User;
use App\Models\UserRole;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Exceptions\ApiException;
use Overtrue\Pinyin\Pinyin;

class AiController extends Controller
{
    public $code = '_Ai';

    /**
     * 用户提交任务
     */
    public function submitTask(Request $request): \Illuminate\Http\JsonResponse
    {
        try {
            (int) $plot = Config::query()->where('key', 'plot')->value('value');
            if (!$plot) {
                return Response::fail('系统错误，请联系管理员#');
            }
            if (Auth::$user->diamond < $plot) {
                return Response::fail('钻石不够了，请先充值');
            }
            $roleId = $request->post('roleId', 0);
            if ($roleId) {
                $role = UserRole::query()->find($roleId);
                if (!$role) {
                    return Response::fail('没有该角色');
                }
            } else {
                $role = UserRole::query()->create([
                    'user_id' => Auth::$userId,
                    'name'    => $request->post('name', ''),
                    'sex'     => $request->post('sex', ''),
                    'age'     => $request->post('age', ''),
                    'star'    => $request->post('star', ''),
                    'level'   => $request->post('level', ''),
//                    'is_piny'   => $request->post('is_piny', 1),
                ]);
                if (!$role) {
                    return Response::fail('提交失败，请稍后再试！');
                }
            }
            User::query()->where('id', Auth::$userId)->decrement('diamond', $plot);
            $task = TaskList::query()->create([
                'user_id'         => Auth::$userId,
                'role_id'         => $role->id,
                'image'           => $request->post('image', ''),
                'surplus_diamond' => Auth::$user->diamond - $plot,
                'nickname'        => 'AI绘本生成',
                'plot'            => $plot,
                'is_piny'   => $request->post('pinYin', 1),
            ]);
            if (!$task) {
                return Response::fail('任务提交失败');
            }

            return Response::success(['id' => $task->id], '提交成功，请稍等');
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 获取任务详情.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function getTaskDetail(Request $request)
    {
        try {
            $id = $request->get('id', 0);

            return Response::success(TaskList::query()->where('user_id', Auth::$userId)->find($id));
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 获取字数.
     *
     * @return int|mixed
     */
    private function getBuildCountString($level = 1)
    {
        $string = Config::query()->where('key', 'class_count')->first()->toArray();
        foreach ($string['value'] ?? [] as $value) {
            if ($level == $value['lv']) {
                return $value['count'];
            }
        }

        return 200;
    }

    /**
     * 生成故事.
     */
    public function buildStory(Request $request): \Illuminate\Http\JsonResponse
    {
        try {
            $task = TaskList::query()->with('role')->where('state', 0)->inRandomOrder()->first();
            if (!$task) {
                return Response::fail('暂无任务');
            }
            $key = [];
            //            $keyword = Keyword::query()->pluck('keyword');
            //            foreach ($keyword as $value) {
            //                $key[] = $value;
            //            }
            //            $keyword     = implode(',', $key);
            $keyword     = Config::query()->where('key', 'prompt_gushi')->value('value');
            $task->state = 1;
            $task->save();
            Log::warning('这个是当前的次数：' . $this->getBuildCountString($task->level));
            $prompt     = "一个{$task->role->sex}，叫{$task->role->name}，{$task->role->age}岁。{$keyword}，要求不低于{$this->getBuildCountString($task->role->level)}字。备注：不要加什么特殊符号只需要正常的逗号句号叹号这些。";
            $messages[] = ['role' => 'user', 'content' => $prompt];
            $data       = [
                'messages' => $messages,
            ];
            $postData           = json_encode($data);
            $complete           = $this->host($postData);
            $task->init_content = $complete['result'];
            $task->save();

            return Response::success($complete);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 生成标题.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function buildTitle(Request $request)
    {
        try {
            $task = TaskList::query()->with('role')->where('state', 1)->inRandomOrder()->first();
            if (!$task) {
                return Response::fail('暂无任务');
            }
            $task->state = 2;
            $task->save();
            $prompt     = $task->init_content . '。将这段童话故事生成一个标题,标题不能有特殊符号，只需要纯文字标题即可，不需要其他任何文字，标题文字控制在10个字以内。不能超过10个字';
            $messages[] = ['role' => 'user', 'content' => $prompt];
            $data       = [
                'messages' => $messages,
            ];
            $postData = json_encode($data);
            $complete = $this->host($postData);
            // $task->state = 2;
            $task->title = $complete['result'];
            $task->save();

            return Response::success($complete);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 生成关键词.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function buildKeyword(Request $request)
    {
        try {
            $task = TaskList::query()->with('role')->where('state', 2)->inRandomOrder()->first();
            if (!$task) {
                return Response::fail('暂无任务');
            }
            $keyword    = Config::query()->where('key', 'prompt_keyword')->value('value');
            $prompt     = $task->init_content . $keyword;
            $messages[] = ['role' => 'user', 'content' => $prompt];
            $data       = [
                'messages' => $messages,
            ];
            $task->state = 3;
            $task->save();
            $postData = json_encode($data);
            $complete = $this->host($postData);
            // $task->state   = 3;
            $task->keyword = $complete['result'];
            $task->save();

            return Response::success($complete);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 翻译英文.
     */
    private function toEnglish($prompt)
    {
        $keyword    = Config::query()->where('key', 'prompt_style')->value('value');
        $prompt     = $prompt . $keyword;
        $promptTo   = '我希望你能担任英语翻译、拼写校对和修辞改进的角色。我会将翻译的结果用于如stable diffusion、midjourney等绘画场景生成图片，语言要求尽量优美。我会用任何语言和你交流，你会识别语言，将其翻译为英语并仅回答翻译的最终结果,不要写解释。我的第一句话是：' . $prompt . '。请立刻翻译，不要回复其它内容。';
        $messages[] = ['role' => 'user', 'content' => $promptTo];
        $data       = [
            'messages' => $messages,
        ];
        $postData = json_encode($data);
        $complete = $this->host($postData);

        return $complete['result'];
    }

    /**
     * 提交sd生成插图.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function buildSd(Request $request)
    {
        try {
            $task = TaskList::query()->with('role')->where('state', 3)->inRandomOrder()->first();
            if (!$task) {
                return Response::fail('暂无任务');
            }
            $task->state = 4;
            $task->save();
            $keyword = $this->toEnglish($task->keyword);
            $param   = ['name'        => '甜瓜(动漫风格)',
                'init_image'          => '',
                'prompt'              => $keyword,
                'width'               => '512',
                'height'              => '512',
                'guidance_scale'      => '7',
                'samples'             => '1',
                'model_id'            => '3',
                'scheduler'           => 'DDPMScheduler',
                'type'                => 'text2img',
                'num_inference_steps' => '30',
                'keywords'            => $keyword,
            ];

            $result = (new Helper())->opensd($param);
            $result = json_decode($result, true);
            Log::warning('这个是SD回调信息：' . json_encode($result, 256));
            if (isset($result['data']['id'])) {
                $task->sd_id = $result['data']['id'];
            } else {
                $task->state = 3;
            }

            $task->save();

            return Response::success($result['data']);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 查询生成进度.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function getOpensdDetail(Request $request)
    {
        $task = TaskList::query()->where('state', 4)->inRandomOrder()->first();
        if (!$task) {
            return $this->error('暂无任务');
        }
        $res = (new Helper())->opensdDetail($task->sd_id);
        $res = @json_decode($res, true);
        if (200 != $res['code']) {
            return Response::fail($res['msg']);
        }
        if ('fail' == $res['data']['state']) {
            $task->state = 3;
            $task->desc  = $res['data']['fail_reason'];
        }
        $task->save();
        if ('success' == $res['data']['state']) {
            $path           = $this->saveImage($res['data']['gen_img']);
            $task->sd_image = $path;
            $task->state    = 5;
            $task->save();
        }

        return $this->success('操作成功', $res['data']);
    }

    /**
     * 获取品牌排版.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function buildPinyin(Request $request)
    {
        try {
            $task = TaskList::query()->where('state', 5)->inRandomOrder()->first();
            if (!$task) {
                return $this->error('暂无任务');
            }
            if (empty($file_name)) {
                $file_name = md5(time()) . '.png';
            }
            $path  = public_path() . '/images/' . $file_name;
            $shell = 'wkhtmltoimage https://hb.swdz.com/api/ai/Pinyin?id=' . $task->id . ' ' . $path;
            exec($shell, $result, $status);
            if ($status) {
                $this->exit_out('生成图片失败', ['生成图片失败' => [$shell, $result, $status]]);
            }
            $domain               = request()->getScheme() . '://' . request()->getHost();
            $pdfPath              = $domain . '/images/' . $file_name;
            $task->image_path     = $pdfPath;
            $result               = $this->extracted($task);
            $task->pinyin_content = $result;
            $task->state          = 6;
            $task->save();

            return Response::success($result);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    /**
     * 下载PDF.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function downloadPdf(Request $request)
    {
        try {
            $id   = $request->input('id', 0);
            $task = TaskList::query()->find($id);
            if (!$task) {
                return Response::fail('没有该任务');
            }
            if (!empty($task->pdf_path)) {
                return Response::success(['url' => $task->pdf_path]);
            }
            if (empty($file_name)) {
                $file_name = md5(time()) . '.pdf';
            }
            $path  = public_path() . '/pdf/' . $file_name;
            $shell = 'wkhtmltopdf https://hb.swdz.com/api/ai/Pinyin?id=' . $task->id . ' ' . $path;
            exec($shell, $result, $status);
            if ($status) {
                $this->exit_out('生成PDF失败', ['生成PDF失败' => [$shell, $result, $status]]);
            }
            $domain         = request()->getScheme() . '://' . request()->getHost();
            $pdfPath        = $domain . '/pdf/' . $file_name;
            $task->pdf_path = $pdfPath;
            $task->save();

            return Response::success(['url' => $pdfPath]);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    private function splitChineseCharacters($inputString, $type = 0)
    {
        if (0 == $type) {
            $inputString = str_replace("\n", '', $inputString);
        }
        $inputString = str_replace('“', '', $inputString);
        $inputString = str_replace('”', '', $inputString);
        //        $inputString = preg_replace('/[^\w\s-]+/u', '', $inputString);
        $length = mb_strlen($inputString, 'utf-8');
        $result = [];
        for ($i = 0; $i < $length; $i++) {
            $result[] = mb_substr($inputString, $i, 1, 'utf-8');
        }

        return $result;
        //        return $inputString;
    }

    public function Pinyin(Request $request)
    {
        try {
            $id     = $request->input('id');
            $task   = TaskList::query()->find($id);
            $result = $this->extracted($task);

            return view('pdf', ['data' => $result, 'img' => $task->image, 'title' => $task->title]);
        } catch (\Exception $exception) {
            LogHelper::exceptionLog($exception, $this->code);

            return Response::fail($exception->getMessage());
        }
    }

    public function containsPunctuation($str)
    {
        // 定义要检测的符号
        $punctuation = '/[，。！、]/u'; // 中文逗号、中文句号、中文感叹号

        // 使用 preg_match 函数进行匹配
        return 1 === preg_match($punctuation, $str);
    }

    public function generate_pdf($html_path = '', $file_name = '')
    {
        if (empty($file_name)) {
            $file_name = md5(time()) . '.pdf';
        }
        $path = public_path() . '/pdf/' . $file_name;
        var_dump($path);

        exit;
        $shell = 'wkhtmltopdf --outline --minimum-font-size 9 ' . $html_path . ' ' . $path;
        exec($shell, $result, $status);
        if ($status) {
            $this->exit_out('生成PDF失败', ['生成PDF失败' => [$shell, $result, $status]]);
        }

        $domain = request()->getScheme() . '://' . request()->getHost();

        return $domain . '/pdf/' . $file_name;
    }

    public function exit_out($msg, $exceptionData = false, $code = 1, $data = [])
    {
        $out = ['code' => $code, 'msg' => $msg, 'data' => $data];

        if (false !== $exceptionData) {
            $this->trace([$msg => $exceptionData], 'error');
        }

        $json = json_encode($out, JSON_UNESCAPED_UNICODE);

        throw new ApiException($json);
    }

    public function trace($log = '', $level = 'info')
    {
        Log::log($level, $log);
    }

    /**
     * 保存图片.
     *
     * @return \Illuminate\Http\JsonResponse|string
     */
    private function saveImage($image_url)
    {
        $imageContent = file_get_contents($image_url);
        $imageDir     = $_SERVER['DOCUMENT_ROOT'] . '/static/images/' . date('Ymd') . '/';
        $imageName    = uniqid() . time() . '_image.png';
        $imagePath    = $imageDir . $imageName;
        if (!is_dir($imageDir)) {
            mkdir($imageDir, 0777, true);
        }
        if (false !== $imageContent) {
            $savedImages = file_put_contents($imagePath, $imageContent);
            if (false !== $savedImages) {
                return $_SERVER['HTTP_HOST'] . '/static/images/' . date('Ymd') . '/' . $imageName;
            }

            return false;
        }

        return false;
    }

    /**
     * 执行请求
     */
    private function host($postData)
    {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => getenv('BAIDU_ERNIE_BOT40_URL') . '?access_token=' . Helper::getAccessToken(),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $postData,
        ]);
        $res = curl_exec($ch);
        curl_close($ch);
        Log::warning('请求头：' .$postData);
        Log::warning('请求返回值：' .$res);
        return json_decode(trim($res), true);
    }

    public function extracted($result, $type = 0, $sdImage = ''): string
    {
        if (0 == $type) {
            $inputString = $result->init_content;
            $sdImage     = $result->sd_image;
        } else {
            $inputString = $result;
        }
        $inputString    = str_replace('“', '', $inputString);
        $inputString    = str_replace('”', '', $inputString);
        $inputString    = str_replace('——', '', $inputString);
        $inputString    = str_replace('—', '', $inputString);
        $inputStringFor = $this->splitChineseCharacters($inputString, 1);
        $arr            = [];
        $i              = 0;
        foreach ($inputStringFor as $key => $value) {
            if ("\n" == $value) {
                $arr[] = $key - $i;
                $i++;
            }
        }
        $splitCharacters = $this->splitChineseCharacters($inputString);
        $pinyin          = Pinyin::Sentence($inputString)->toArray();
        $string          = '';
        $count           = 0;
        foreach ($pinyin as $value) {
            $count += mb_strlen($value);
        }
        $img         = '<img style="width: 100%;height:auto;float: right;margin-right: 10px;margin-top: 10px; margin-bottom: 5px" src="https://' . $sdImage . '"/>';
        $stringCount = 0;
        foreach ($pinyin as $key => $value) {
            if ($this->containsPunctuation($value)) {
                $value = '&nbsp;';
            }
            $stringCount += mb_strlen($value);
            if (in_array($count - $stringCount, [158, 159, 160, 161, 162, 163]) && !strstr($string, '<img')) {
                $string = $string . $img;
            }
            if (in_array($key + 1, $arr)) {
                if ($result->is_piny){
                    $string = $string . "<span><sup>{$value}</sup>{$splitCharacters[$key]}</span><br style='clear: both'><br style='clear: both'>";
                }else{
                    $string = $string . "<span>{$splitCharacters[$key]}</span><br style='clear: both'><br style='clear: both'>";
                }

            } else {
                $style = '';
                // if (in_array($key, $arr) || 0 == $key) {
                //     $style = 'style="margin-left: 5rem"';
                // }
                if ($result->is_piny){
                    $string = $string . '<span ' . $style . "><sup>{$value}</sup>{$splitCharacters[$key]}</span>";
                }else{
                    $string = $string . '<span ' . $style . ">{$splitCharacters[$key]}</span>";
                }
            }
        }
        return $string;
    }
}
