<?php

namespace App\Http\Controllers;

use App\Http\Api\ChannelApi;
use App\Http\Api\SentenceApi;
use App\Http\Api\ShareApi;
use App\Http\Api\StudioApi;
use App\Http\Resources\ArticleResource;
use App\Models\Article;
use App\Models\ArticleCollection;
use App\Models\Collection;
use App\Models\CustomBook;
use App\Models\CustomBookId;
use App\Models\Sentence;
use App\Services\AuthService;
use App\Tools\OpsLog;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ArticleController extends Controller
{
    public static function userCanRead($user_uid, Article $article)
    {
        if ($article->status === 30) {
            return true;
        }
        if (empty($user_uid)) {
            return false;
        }
        // 私有文章，判断是否为所有者
        if ($user_uid === $article->owner) {
            return true;
        }
        // 非所有者
        // 判断是否为文章协作者
        $power = ShareApi::getResPower($user_uid, $article->uid);
        if ($power >= 10) {
            return true;
        }
        // 无读取权限
        // 判断文集是否有读取权限
        $inCollection = ArticleCollection::where('article_id', $article->uid)
            ->select('collect_id')
            ->groupBy('collect_id')->get();
        if (! $inCollection) {
            return false;
        }
        // 查找与文章同主人的文集
        $collections = Collection::whereIn('uid', $inCollection)
            ->where('owner', $article->owner)
            ->select('uid')
            ->get();
        if (! $collections) {
            return false;
        }
        // 查找与文章同主人的文集是否是共享的
        $power = 0;
        foreach ($collections as $collection) {
            // code...
            $currPower = ShareApi::getResPower($user_uid, $collection->uid);
            if ($currPower >= 10) {
                return true;
            }
        }

        return false;
    }

    public static function userCanEditId($user_uid, $articleId)
    {
        $article = Article::find($articleId);
        if ($article) {
            return ArticleController::userCanEdit($user_uid, $article);
        } else {
            return false;
        }
    }

    public static function userCanEdit($user_uid, $article)
    {
        if (empty($user_uid)) {
            return false;
        }
        // 私有文章，判断是否为所有者
        if ($user_uid === $article->owner) {
            return true;
        }
        // 非所有者
        // 判断是否为文章协作者
        $power = ShareApi::getResPower($user_uid, $article->uid);
        if ($power >= 20) {
            return true;
        }
        // 无读取权限
        // 判断文集是否有读取权限
        $inCollection = ArticleCollection::where('article_id', $article->uid)
            ->select('collect_id')
            ->groupBy('collect_id')->get();
        if (! $inCollection) {
            return false;
        }
        // 查找与文章同主人的文集
        $collections = Collection::whereIn('uid', $inCollection)
            ->where('owner', $article->owner)
            ->select('uid')
            ->get();
        if (! $collections) {
            return false;
        }
        // 查找与文章同主人的文集是否是共享的
        $power = 0;
        foreach ($collections as $collection) {
            // code...
            $currPower = ShareApi::getResPower($user_uid, $collection->uid);
            if ($currPower >= 20) {
                return true;
            }
        }

        return false;
    }

    public static function userCanManage($user_uid, $studioName)
    {
        if (empty($user_uid)) {
            return false;
        }
        // 判断是否为所有者
        if ($user_uid === StudioApi::getIdByName($studioName)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index(Request $request)
    {
        //
        $field = [
            'uid',
            'title',
            'subtitle',
            'summary',
            'owner',
            'lang',
            'status',
            'editor_id',
            'updated_at',
            'created_at',
        ];
        if ($request->input('content') === 'true') {
            $field[] = 'content';
            $field[] = 'content_type';
        }
        $table = Article::select($field);
        switch ($request->input('view')) {
            case 'template':
                $studioId = StudioApi::getIdByName($request->input('studio_name'));
                $table = $table->where('owner', $studioId);
                break;
            case 'studio':
                // 获取studio内所有 article
                $user = AuthService::current($request);
                if (! $user) {
                    return $this->error(__('auth.failed'), [], 401);
                }
                // 判断当前用户是否有指定的studio的权限
                $studioId = StudioApi::getIdByName($request->input('name'));
                if ($user['user_uid'] !== $studioId) {
                    return $this->error(__('auth.failed'), [], 403);
                }

                if ($request->input('view2', 'my') === 'my') {
                    $table = $table->where('owner', $studioId);
                } else {
                    // 协作
                    $resList = ShareApi::getResList($studioId, 3);
                    $resId = [];
                    foreach ($resList as $res) {
                        $resId[] = $res['res_id'];
                    }
                    $table = $table->whereIn('uid', $resId)->where('owner', '<>', $studioId);
                }

                // 根据anthology过滤
                if ($request->has('anthology')) {
                    switch ($request->input('anthology')) {
                        case 'all':
                            break;
                        case 'none':
                            // 我的文集
                            $myCollection = Collection::where('owner', $studioId)->select('uid')->get();
                            // 收录在我的文集里面的文章
                            $articles = ArticleCollection::whereIn('collect_id', $myCollection)
                                ->select('article_id')->groupBy('article_id')->get();
                            // 不在这些范围之内的文章
                            $table = $table->whereNotIn('uid', $articles);
                            break;
                        default:
                            $articles = ArticleCollection::where('collect_id', $request->input('anthology'))
                                ->select('article_id')->get();
                            $table = $table->whereIn('uid', $articles);
                            break;
                    }
                }
                break;
            case 'public':
                $table = $table->where('status', 30);
                break;
            default:
                $this->error('view error');
                break;
        }
        // 处理搜索
        if ($request->has('search') && ! empty($request->input('search'))) {
            $table = $table->where('title', 'like', '%'.$request->input('search').'%');
        }
        if ($request->has('subtitle') && ! empty($request->input('subtitle'))) {
            $table = $table->where('subtitle', 'like', $request->input('subtitle'));
        }
        // 获取记录总条数
        $count = $table->count();
        // 处理排序
        $table = $table->orderBy(
            $request->input('order', 'updated_at'),
            $request->input('dir', 'desc')
        );
        // 处理分页
        $table = $table->skip($request->input('offset', 0))
            ->take($request->input('limit', 1000));
        // 获取数据
        $result = $table->get();

        return $this->ok(['rows' => ArticleResource::collection($result), 'count' => $count]);
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function showMyNumber(Request $request)
    {
        $user = AuthService::current($request);
        if (! $user) {
            return $this->error(__('auth.failed'));
        }
        // 判断当前用户是否有指定的studio的权限
        $studioId = StudioApi::getIdByName($request->input('studio'));
        if ($user['user_uid'] !== $studioId) {
            return $this->error(__('auth.failed'));
        }
        // 我的
        $my = Article::where('owner', $studioId)->count();
        // 协作
        $resList = ShareApi::getResList($studioId, 3);
        $resId = [];
        foreach ($resList as $res) {
            $resId[] = $res['res_id'];
        }
        $collaboration = Article::whereIn('uid', $resId)->where('owner', '<>', $studioId)->count();

        return $this->ok(['my' => $my, 'collaboration' => $collaboration]);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store(Request $request)
    {
        // 判断权限
        $user = AuthService::current($request);
        if (! $user) {
            return $this->error(__('auth.failed'), [], 401);
        } else {
            $user_uid = $user['user_uid'];
        }

        $canManage = ArticleController::userCanManage($user_uid, $request->input('studio'));
        if (! $canManage) {
            // 判断是否有文集权限
            if ($request->has('anthologyId')) {
                $currPower = ShareApi::getResPower($user_uid, $request->input('anthologyId'));
                if ($currPower <= 10) {
                    return $this->error(__('auth.failed'), [], 403);
                }
            } else {
                return $this->error(__('auth.failed'), [], 403);
            }
        }
        // 权限判断结束

        // 查询标题是否重复
        /*
        if(Article::where('title',$request->input('title'))->where('owner',$studioUuid)->exists()){
            return $this->error(__('validation.exists'));
        }*/
        $newArticle = new Article;
        DB::transaction(function () use ($user, $request, $newArticle) {
            $studioUuid = StudioApi::getIdByName($request->input('studio'));
            // 新建文章，加入文集必须都成功。否则回滚
            $newArticle->id = app('snowflake')->id();
            $newArticle->uid = Str::uuid();
            $newArticle->title = mb_substr($request->input('title'), 0, 128, 'UTF-8');
            $newArticle->lang = $request->input('lang');
            if (! empty($request->input('status'))) {
                $newArticle->status = $request->input('status');
            }
            $newArticle->owner = $studioUuid;
            $newArticle->owner_id = $user['user_id'];
            $newArticle->editor_id = $user['user_id'];
            $newArticle->parent = $request->input('parentId');
            $newArticle->create_time = time() * 1000;
            $newArticle->modify_time = time() * 1000;
            $newArticle->save();
            OpsLog::debug($user['user_uid'], $newArticle);

            $anthologyId = $request->input('anthologyId');
            if (Str::isUuid($anthologyId)) {
                $parentNode = $request->input('parentNode');
                if (Str::isUuid($parentNode)) {
                    $map = ArticleCollection::where('collect_id', $anthologyId)
                        ->orderBy('id')->get();
                    $newMap = [];
                    $parentNodeLevel = -1;
                    $appended = false;
                    foreach ($map as $key => $row) {
                        $orgNode = $row;
                        if (! $appended) {
                            if ($parentNodeLevel > 0) {
                                if ($row->level <= $parentNodeLevel) {
                                    // parent node 末尾
                                    $newNode = [];
                                    $newNode['collect_id'] = $anthologyId;
                                    $newNode['article_id'] = $newArticle->uid;
                                    $newNode['level'] = $parentNodeLevel + 1;
                                    $newNode['title'] = $newArticle->title;
                                    $newNode['children'] = 0;
                                    $newMap[] = $newNode;
                                    $appended = true;
                                }
                            } else {
                                if ($row->article_id === $parentNode) {
                                    $parentNodeLevel = $row->level;
                                    $orgNode['children'] = $orgNode['children'] + 1;
                                }
                            }
                        }
                        $newMap[] = $orgNode;
                    }
                    if ($parentNodeLevel > 0) {
                        if ($appended === false) {
                            $newNode = [];
                            $newNode['collect_id'] = $anthologyId;
                            $newNode['article_id'] = $newArticle->uid;
                            $newNode['level'] = $parentNodeLevel + 1;
                            $newNode['title'] = $newArticle->title;
                            $newNode['children'] = 0;
                            $newMap[] = $newNode;
                        }
                    } else {
                        Log::warning('没找到挂接点'.$parentNode);
                    }

                    $delete = ArticleCollection::where('collect_id', $anthologyId)->delete();
                    $count = 0;
                    foreach ($newMap as $key => $row) {
                        $new = new ArticleCollection;
                        $new->id = app('snowflake')->id();
                        $new->article_id = $row['article_id'];
                        $new->collect_id = $row['collect_id'];
                        $new->title = $row['title'];
                        $new->level = $row['level'];
                        $new->children = $row['children'];
                        $new->editor_id = $user['user_id'];
                        if (isset($row['deleted_at'])) {
                            $new->deleted_at = $row['deleted_at'];
                        }
                        $new->save();
                        $count++;
                    }
                    ArticleMapController::updateCollection($anthologyId);
                } else {
                    $articleMap = new ArticleCollection;
                    $articleMap->id = app('snowflake')->id();
                    $articleMap->article_id = $newArticle->uid;
                    $articleMap->collect_id = $request->input('anthologyId');
                    $articleMap->title = Article::find($newArticle->uid)->title;
                    $articleMap->level = 1;
                    $articleMap->save();
                }
            }
        });
        if (Str::isUuid($newArticle->uid)) {
            return $this->ok(new ArticleResource($newArticle));
        } else {
            return $this->error('fail');
        }
    }

    /**
     * Display the specified resource.
     *
     * @return Response
     */
    public function show(Request $request, Article $article)
    {
        //
        if (! $article) {
            return $this->error('no recorder');
        }
        // 判断权限
        $user = AuthService::current($request);
        if (! $user) {
            $user_uid = '';
        } else {
            $user_uid = $user['user_uid'];
        }

        $canRead = ArticleController::userCanRead($user_uid, $article);
        if (! $canRead) {
            return $this->error(__('auth.failed'), 403, 403);
        }

        return $this->ok(new ArticleResource($article));
    }

    /**
     * Display the specified resource.
     *
     * @param  string  $article
     * @return Response
     */
    public function preview(Request $request, string $articleId)
    {
        //
        $article = Article::find($articleId);
        if (! $article) {
            return $this->error('no recorder');
        }
        // 判断权限
        $user = AuthService::current($request);
        if (! $user) {
            $user_uid = '';
        } else {
            $user_uid = $user['user_uid'];
        }

        $canRead = ArticleController::userCanRead($user_uid, $article);
        if (! $canRead) {
            return $this->error(__('auth.failed'), [], 401);
        }
        if ($request->has('content')) {
            $article->content = $request->input('content');

            return $this->ok(new ArticleResource($article));
        } else {
            return $this->error('no content', [], 200);
        }
    }

    /**
     * Update the specified resource in storage.
     *
     * @return Response
     */
    public function update(Request $request, Article $article)
    {
        //
        if (! $article) {
            return $this->error('no recorder');
        }
        // 鉴权
        $user = AuthService::current($request);
        if (! $user) {
            return $this->error(__('auth.failed'), 401, 401);
        } else {
            $user_uid = $user['user_uid'];
        }

        $canEdit = ArticleController::userCanEdit($user_uid, $article);
        if (! $canEdit) {
            return $this->error(__('auth.failed'), 401, 401);
        }

        /*
        //查询标题是否重复
        if(Article::where('title',$request->input('title'))
                  ->where('owner',$article->owner)
                  ->where('uid',"<>",$article->uid)
                  ->exists()){
            return $this->error(__('validation.exists'));
        }*/

        $content = $request->input('content');
        if ($request->input('to_tpl') === true) {
            /**
             * 转化为模版
             */
            $tplContent = $this->toTpl(
                $content,
                $request->input('anthology_id'),
                $user
            );
            $content = $tplContent;
        }

        $article->title = mb_substr($request->input('title'), 0, 128, 'UTF-8');
        $article->subtitle = mb_substr($request->input('subtitle'), 0, 128, 'UTF-8');
        $article->summary = mb_substr($request->input('summary'), 0, 1024, 'UTF-8');
        $article->content = $content;
        $article->lang = $request->input('lang');
        $article->status = $request->input('status', 10);
        $article->editor_id = $user['user_id'];
        $article->modify_time = time() * 1000;
        $article->save();

        OpsLog::debug($user_uid, $article);

        return $this->ok(new ArticleResource($article));
    }

    /**
     * Remove the specified resource from storage.
     *
     * @return Response
     */
    public function destroy(Request $request, Article $article)
    {
        //
        $user = AuthService::current($request);
        if (! $user) {
            return $this->error(__('auth.failed'));
        }
        // 判断当前用户是否有指定的studio的权限
        if ($user['user_uid'] !== $article->owner) {
            return $this->error(__('auth.failed'));
        }
        $delete = 0;
        DB::transaction(function () use ($article, $delete) {
            // TODO 删除文集中的文章
            $delete = $article->delete();
            ArticleMapController::deleteArticle($article->uid);
        });

        return $this->ok($delete);
    }

    public function toTpl($content, $anthologyId, $user)
    {
        // 查询书号
        if (! Str::isUuid($anthologyId)) {
            throw new \Exception('anthology Id not uuid');
        }

        $bookId = $this->getBookId($anthologyId, $user);

        $tpl = $this->convertToTpl($content, $bookId['book'], $bookId['paragraph']);

        // 保存原文到句子表
        $customBook = $this->getCustomBookByBookId($bookId['book']);
        $sentenceSave = new SentenceApi;
        $auth = $sentenceSave->auth($customBook->channel_id, $user['user_uid']);
        if (! $auth) {
            throw new \Exception('auth fail');
        }
        foreach ($tpl['sentences'] as $key => $sentence) {
            $sentenceSave->store($sentence, $user);
        }

        return $tpl['content'];
    }

    private function getCustomBookByBookId($bookId)
    {
        return CustomBook::where('book_id', $bookId)->first();
    }

    private function getBookId($anthologyId, $user)
    {
        $anthology = Collection::where('uid', $anthologyId)->first();
        if (! $anthology) {
            throw new \Exception('anthology not exists id='.$anthologyId);
        }
        $bookId = $anthology->book_id;
        if (empty($bookId)) {
            // 生成 book id
            $newBookId = CustomBook::max('book_id') + 1;

            $newBook = new CustomBook;
            $newBook->id = app('snowflake')->id();
            $newBook->book_id = $newBookId;
            $newBook->title = $anthology->title;
            $newBook->owner = $anthology->owner;
            $newBook->editor_id = $user['user_id'];
            $newBook->lang = $anthology->lang;
            $newBook->status = $anthology->status;
            // 查询anthology所在的studio有没有符合要求的channel 没有的话，建立
            $channelId = ChannelApi::userBookGetOrCreate($anthology->owner, $anthology->lang, $anthology->status);
            if ($channelId === false) {
                throw new \Exception('user book get fail studio='.$anthology->owner.' language='.$anthology->lang);
            }
            $newBook->channel_id = $channelId;
            $ok = $newBook->save();
            if (! $ok) {
                throw new \Exception('user book create fail studio='.$anthology->owner.' language='.$anthology->lang);
            }
            CustomBookId::where('key', 'max_book_number')->update(['value' => $newBookId]);
            $bookId = $newBookId;
            $anthology->book_id = $newBookId;
            $anthology->save();
        } else {
            $channelId = CustomBook::where('book_id', $bookId)->value('channel_id');
        }
        $maxPara = Sentence::where('channel_uid', $channelId)
            ->where('book_id', $bookId)->max('paragraph');
        if (! $maxPara) {
            $maxPara = 0;
        }

        return ['book' => $bookId, 'paragraph' => $maxPara + 1];
    }

    public function convertToTpl($content, $bookId, $paraStart)
    {
        $newSentence = [];
        $para = $paraStart;
        $sentNum = 1;
        $newText = '';
        $isTable = false;
        $isList = false;
        $newSent = '';
        $sentences = explode("\n", $content);
        foreach ($sentences as $row) {
            // $data 为一行文本
            $listHead = '';
            $isList = false;

            $heading = false;
            $title = false;

            $trimData = trim($row);

            // 判断是否为list
            $listLeft = strstr($row, '- ', true);
            if ($listLeft !== false) {
                if (ctype_space($listLeft) || empty($listLeft)) {
                    // - 左侧是空，判定为list
                    $isList = true;
                    $iListPos = mb_strpos($row, '- ', 0, 'UTF-8');
                    $listHead = mb_substr($row, 0, $iListPos + 2, 'UTF-8');
                    $listBody = mb_substr($row, $iListPos + 2, mb_strlen($row, 'UTF-8') - $iListPos + 2, 'UTF-8');
                }
            }

            // TODO 判断是否为标题
            $headingStart = mb_strpos($row, '# ', 0, 'UTF-8');
            if ($headingStart !== false) {
                $headingLeft = mb_substr($row, 0, $headingStart + 2, 'UTF-8');
                $title = mb_substr($row, $headingStart + 2, null, 'UTF-8');
                if (str_replace('#', '', trim($headingLeft)) === '') {
                    // 除了#没有其他东西，那么是标题
                    $heading = $headingLeft;
                    $newText .= $headingLeft;
                    $newText .= '{{'."{$bookId}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
                    $newSentence[] = $this->newSent($bookId, $para, $sentNum, $sentNum, $title);
                    $newSent = '';
                    $para++;
                    $sentNum = 1;

                    continue;
                }
            }

            // 判断是否为表格开始
            if (mb_substr($trimData, 0, 1, 'UTF-8') == '|') {
                $isTable = true;
            }
            if ($trimData != '' && $isTable == true) {
                // 如果是表格 不新增句子
                $newSent .= "{$row}\n";

                continue;
            }
            if ($isList == true) {
                $newSent .= $listBody;
            } else {
                $newSent .= $trimData;
            }

            // 生成句子编号
            if ($trimData == '') {
                // 空行
                if (strlen($newSent) > 0) {
                    // 之前有内容
                    $newText .= '{{'."{$bookId}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
                    $newSentence[] = $this->newSent($bookId, $para, $sentNum, $sentNum, $newSent);
                    $newSent = '';
                }
                // 新的段落 不插入数据库
                $para++;
                $sentNum = 1;
                $newText .= "\n";
                $isTable = false; // 表格开始标记
                $isList = false;

                continue;
            } else {
                $sentNum = $sentNum + 10;
            }

            if (mb_substr($trimData, 0, 2, 'UTF-8') == '{{') {
                // 已经有的句子链接不处理
                $newText .= $trimData."\n";
            } else {
                $newText .= $listHead;
                $newText .= '{{'."{$bookId}-{$para}-{$sentNum}-{$sentNum}"."}}\n";
                $newSentence[] = $this->newSent($bookId, $para, $sentNum, $sentNum, $newSent);
                $newSent = '';
            }
        }

        return [
            'content' => $newText,
            'sentences' => $newSentence,
        ];
    }

    private function newSent($book, $para, $start, $end, $content)
    {
        return [
            'book_id' => $book,
            'paragraph' => $para,
            'word_start' => $start,
            'word_end' => $end,
            'content' => $content,
        ];
    }
}
