<?php

namespace App\Services\Goodnight;

use App\Exceptions\AlertException;
use App\Exceptions\DBException;
use App\Models\Goodnight\SubscribeModel;
use App\models\Goodnight\SystemTagModel;
use App\Models\Goodnight\TagModel;
use App\Models\Goodnight\ThumbModel;
use App\Models\Goodnight\VoiceModel;
use App\Models\User\UserModel;
use App\Services\Service;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class VoiceService extends Service
{
    public function create(array $data): int
    {
        $user = UserModel::find($data['uid']);
        $data['sex'] = $user->sex;
        $vModel = new VoiceModel();
        $voice = $vModel->fill($data);
        if ($voice->save()) {
            return $voice->id;
        } else {
            throw new DBException("数据库异常", 501);
        }
    }

    /**
     * 删除声音
     * @param  int  $uid
     * @param  int  $voice_id
     * @return bool
     * @throws DBException
     * @throws AlertException
     */
    public function delete(int $uid, int $voice_id): bool
    {
        $vModel = new VoiceModel();
        $voice = $vModel->findOrFail($voice_id);
        if ($uid != $voice->uid) {
            throw new AlertException("权限不足", 403);
        }
        if ($voice->delete()) {
            return true;
        } else {
            throw new DBException("数据库异常", 501);
        }
    }

    /**
     * 点赞声音
     * @param  int  $uid
     * @param  int  $voice_id
     * @return bool
     * @throws AlertException
     * @throws DBException
     */
    public function thumb(int $uid, int $voice_id)
    {
        $voice = VoiceModel::findOrFail($voice_id);
        if ($voice->uid == $uid) {
            throw new AlertException("不能点赞自己", 403);
        }
        if (
            ThumbModel::where([
            ['voice_id', $voice->id],
            ['uid', $uid],
            ])->exists()
        ) {
            throw new AlertException("你已经点过赞", 410);
        }
        $vuser = \App\Models\Goodnight\UserModel::find($voice->uid);
        $headimgurls = json_decode($vuser->get_like_headimgurl, true) ?? [];
        $user = UserModel::find($uid);
        array_unshift($headimgurls, $user->headimgurl);
        $headimgurls = array_slice($headimgurls, 0, 3);
        \DB::beginTransaction();
        try {
            DB::table('kdgx_goodnight_voice_thumb')->insert([
                'created_at' => time(),
                'updated_at' => time(),
                'voice_id' => $voice->id,
                'uid' => $uid,
            ]);
            VoiceModel::where('id', $voice->id)->increment('like', 1);
            \DB::table('kdgx_goodnight_user')->where('uid', $voice->uid)->increment('get_like', 1);
            \DB::table('kdgx_goodnight_user')->where('uid', $voice->uid)->increment('gnight_coin', 1);
            \DB::table('kdgx_goodnight_user')->where('uid', $voice->uid)->update([
                'get_like_headimgurl' => json_encode($headimgurls),
            ]);
            \DB::commit();

            return true;
        } catch (\Exception $e) {
            \DB::rollBack();
            throw new DBException("数据库异常", 500);
        }
    }

    /**
     * 标记声音
     * @param  int  $uid
     * @param  array  $data
     * @return bool
     * @throws AlertException
     * @throws DBException
     */
    public function tag(int $uid, array $data)
    {
        $add_gnight_coin = 0;
        $voice = VoiceModel::findOrFail($data['voice_id']);
        if ($voice->uid == $uid) {
            throw new AlertException("不能标记自己", 201);
        }
        if (
            $uid != 0 && TagModel::where([
                ['voice_id', $voice->id],
                ['uid', $uid],
            ])->exists()
        ) {
            throw new AlertException("你已经标记过", 203);
        }
        $tags = json_decode(empty($voice->tags) ? json_encode([]) : $voice->tags, true);
        if (isset($tags[$data['tag']])) {
            $tags[$data['tag']] += 1;
        } else {
            $tags[$data['tag']] = 1;
        }
        \DB::beginTransaction();
        try {
            if (!TagModel::where('uid', $uid)->where('created_at', '>', mktime(0, 0, 0))->exists()) {
                \DB::table('kdgx_goodnight_user')->where('uid', $uid)->increment('gnight_coin', 2);
                $add_gnight_coin = 2;
            }
            TagModel::create([
                'voice_id' => $voice->id,
                'uid' => $uid,
                'tag' => $data['tag'],
            ]);
            VoiceModel::where('id', $voice->id)->update(['tags' => json_encode($tags, JSON_UNESCAPED_UNICODE)]);
            \DB::commit();

            return $add_gnight_coin;
        } catch (\Exception $e) {
            \DB::rollBack();
            throw new DBException("数据库异常", 500);
        }
    }

    /**
     * 用户端获取声音信息
     * @param  int  $uid
     * @param  int  $voice_id
     * @return VoiceModel
     */
    public function getVoice(int $uid, int $voice_id): VoiceModel
    {
        $vmodel = new VoiceModel();
        $voice = $vmodel->findOrFail($voice_id, [
            'id',
            'created_at',
            'uid',
            'sex',
            'cover',
            'voice',
            'check',
            'like',
        ]);
        // 自己对这张卡片的操作
        $self = array(
            'like' => 0,
            'tag' => '',
            'is_self' => false,
        );
        if ($voice->uid == $uid) {
            $self['is_self'] = true;
        }
        if (
            ThumbModel::where([
            ['voice_id', $voice_id],
            ['uid', $uid],
            ])->exists()
        ) {
            $self['like'] = 1;
        }
        $selfTag = TagModel::where([
            ['voice_id', $voice_id],
            ['uid', $uid],
        ])->first();
        if (!collect($selfTag)->isEmpty()) {
            $self['tag'] = $selfTag->tag;
        }
        $voice->self = $self;
        // 点赞集合
        $thumbs = ThumbModel::where('voice_id', $voice_id)->get();
        $users = UserModel::whereIn('uid', $thumbs->pluck('uid'))->get(['uid', 'headimgurl']);
        $voice->like_headimgurl = $users ?? [];
        // 标签集合
        $res = TagModel::where('voice_id', $voice_id)->groupBy('tag')->select(
            'tag',
            \DB::raw('count(*) as count')
        )->get();
        $idxres = array();
        foreach ($res as $v) {
            $idxres[$v->tag] = $v->count;
        }
        $strTag = array();
        $public_id = config('miniprogram.public_id');
        $strs = Redis::hget("app:config:{$public_id}", "night_voice_tags_{$voice->sex}") ?? json_encode([]);
        $tags = json_decode($strs, true);
        foreach ($tags as $tag) {
            if (isset($idxres[$tag])) {
                $count = $idxres[$tag];
            } else {
                $count = 0;
            }
            array_push($strTag, array(
                'tag' => $tag,
                'count' => $count,
            ));
        }
        $voice->tags = $strTag;
        // 发布者信息
        $voice->user = UserModel::find($voice->uid, ['uid', 'nickname', 'headimgurl']);
        // 订阅信息
        $sub = SubscribeModel::where([
            ['voice_id', $voice_id],
            ['uid', $uid],
        ])->first();
        if (!collect($sub)->isEmpty()) {
            $voice->geted_at = $sub->created_at;
        }

        return $voice;
    }

    /**
     * 我录制的晚安列表
     * @param  int  $page
     * @param  int  $limit
     * @param  int  $uid
     * @return array
     */
    public function myVoice(int $page, int $limit, int $uid): array
    {
        $total = VoiceModel::where('uid', $uid)->count();
        $data = VoiceModel::where('uid', $uid)->OrderBy(
            "id",
            "desc"
        )->offset(($page - 1) * $limit)->limit($limit)->get();

        return array(
            'total' => $total,
            'list' => $data,
        );
    }

    /**
     * 某人录制的晚安列表
     * @param  int  $page
     * @param  int  $limit
     * @param  int  $uid
     * @return array
     */
    public function userVoice(int $page, int $limit, int $uid): array
    {
        $total = VoiceModel::where([
            ['uid', $uid],
            ['check', 1],
        ])->count();
        $data = VoiceModel::where([
            ['uid', $uid],
            ['check', 1],
        ])->orderBy('id', 'desc')->offset(($page - 1) * $limit)->limit($limit)->get();

        return array(
            'total' => $total,
            'list' => $data,
        );
    }

    /**
     * 声音库
     * @param  array  $pages
     * @param  array  $search
     * @return array
     */
    public function checkList(array $pages, array $search): array
    {
        $where = array();
        if (isset($search['check'])) {
            $where[] = ['check', $search['check']];
        }
        if (!empty($search['tag'])) {
            $where[] = ['tags', 'like', "%{$search['tag']}%"];
        }
        if (!empty($search['expedit'])) {
            $where[] = ['expedit', $search['expedit']];
        }
        if (isset($search['commit'])) {
            $where[] = ['commit', $search['commit']];
        }

        $uids = [];
        if (isset($search['search'])) {
            $user = UserModel::where('phone', $search['search'])->get();
            $uids = $user->pluck('uid')->toArray();
            array_push($uids, $search['search']);
        }
        $total = VoiceModel::where($where)->when($uids, function ($query, $uids) {
            return $query->whereIn('uid', $uids);
        })->count();
        $voices = VoiceModel::where($where)->when($uids, function ($query, $uids) {
            return $query->whereIn('uid', $uids);
        })->orderBy('id', 'asc')->skip(($pages['page'] - 1) * $pages['limit'])->take($pages['limit'])->get();
        $public_id = config('miniprogram.public_id');
        $strs_1 = Redis::hget("app:config:{$public_id}", "night_voice_tags_1") ?? json_encode([]);
        $tags_1 = json_decode($strs_1, true);
        $strs_2 = Redis::hget("app:config:{$public_id}", "night_voice_tags_2") ?? json_encode([]);
        $tags_2 = json_decode($strs_2, true);
        foreach ($voices as $voice) {
            $strTag = array();
            $idxres = json_decode(empty($voice->tags) ? json_encode([]) : $voice->tags, true);
            if (1 == $voice->sex) {
                $tags = $tags_1;
            } else {
                $tags = $tags_2;
            }
            foreach ($tags as $tag) {
                if (isset($idxres[$tag])) {
                    $count = $idxres[$tag];
                } else {
                    $count = 0;
                }
                $pushtag = array(
                    'tag' => $tag,
                    'count' => $count,
                    'system' => false,
                );
                if (
                    SystemTagModel::where([
                    ['voice_id', $voice->id],
                    ['tag', $tag],
                    ])->exists()
                ) {
                    $pushtag['system'] = true;
                }
                array_push($strTag, $pushtag);
            }
            $voice->tags = $strTag;
        }

        return array(
            'total' => $total,
            'list' => $voices,
        );
    }

    /**
     * 推荐声音
     * @param  int  $voice_id
     * @return bool
     * @throws DBException
     */
    public function commit(int $voice_id): bool
    {
        $voice = VoiceModel::findOrFail($voice_id);
        $voice->commit = abs($voice->commit - 1);
        if ($voice->save()) {
            return true;
        } else {
            throw new DBException("服务器异常", 500);
        }
    }

    /**
     * 审核声音
     * @param  int  $voice_id
     * @param  int  $check
     * @return bool
     * @throws \Exception
     */
    public function check(int $voice_id, int $check): bool
    {
        $voice = VoiceModel::findOrFail($voice_id);
        $voice->check = $check;
        $voice->save();
        try {
            $ns = new NoticeService();
            if ($check == 1) {
                $ns->checkSuccess($voice->uid, $voice->id);
            } else {
                $ns->checkFail($voice->uid, $voice->id);
            }
        } catch (\Exception $e) {
        }

        return true;
    }

    /**
     * 标记声音
     * @param  int  $voice_id
     * @param  string  $tag
     * @return bool
     * @throws \Exception
     */
    public function admintag(int $voice_id, string $tag): bool
    {
        $voice = VoiceModel::findOrFail($voice_id);
        $idxres = json_decode(empty($voice->tags) ? json_encode([]) : $voice->tags, true);
        if (
            SystemTagModel::where([
            ['voice_id', $voice_id],
            ['tag', $tag],
            ])->exists()
        ) {
            // 取消标记
            SystemTagModel::where([
                ['voice_id', $voice_id],
                ['tag', $tag],
            ])->delete();
            $idxres[$tag] -= 1;
        } else {
            $model = new SystemTagModel();
            $tag = $model->fill([
                'voice_id' => $voice_id,
                'tag' => $tag,
            ]);
            $tag->save();
            if (isset($idxres[$tag])) {
                $idxres[$tag] += 1;
            } else {
                $idxres[$tag] = 1;
            }
        }
        $voice->tags = json_encode($idxres);

        return true;
    }

    /**
     * 加急晚安
     * @param  int  $voice_id
     * @param  int  $uid
     * @return bool
     * @throws AlertException
     */
    public function expeditVoice(int $voice_id, int $uid): bool
    {
        $vm = new VoiceModel();
        $voice = $vm->findOrFail($voice_id);
        if ($voice->uid != $uid) {
            throw new AlertException("无权限", 101);
        }
        if ($voice->check != 0) {
            throw new AlertException("语音已审核", 101);
        }
        $voice->expedit = 1;
        $voice->save();

        return true;
    }
}
