<?php

namespace App\Services\Goodnight;

use App\Exceptions\AlertException;
use App\Models\Goodnight\InviteLogModel;
use App\Models\Goodnight\SubscribeModel;
use App\Models\Goodnight\TagModel;
use App\Models\Goodnight\UserModel;
use App\Models\Goodnight\VoiceModel;
use App\Services\Service;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class SubscribeService extends Service
{
    public const SUB_TYPE = [
        1 => [
            'description' => '订阅一周',
            'day' => 7,
            'gnight_coin' => 7,
        ],
        2 => [
            'description' => '订阅一个月',
            'day' => 30,
            'gnight_coin' => 20,
        ],
        3 => [
            'description' => '订阅一年',
            'day' => 365,
            'gnight_coin' => 200,
        ],
    ];

    /**
     * 订阅声音
     * @param  int  $uid
     * @param  int  $type
     * @return int
     * @throws AlertException
     */
    public function subscribe(int $uid, int $type)
    {
        $user = UserModel::findOrFail($uid);
        if ($user->subscribed_at < time()) {
            $time = time();
        } else {
            $time = $user->subscribed_at;
        }
        $data = array();
        if (0 == $user->subscribed_at && 1 == $type) {
            $data['gnight_coin'] = $user->gnight_coin + 3;
            $data['subscribed_at'] = $time + self::SUB_TYPE[$type]['day'] * 86400;
            $data['subscribe_cnt'] = $user->subscribe_cnt + 1;
        } else {
            if ($user->gnight_coin < self::SUB_TYPE[$type]['gnight_coin']) {
                throw new AlertException("晚安币不足", 202);
            }
            $data['gnight_coin'] = $user->gnight_coin - self::SUB_TYPE[$type]['gnight_coin'];
            $data['subscribed_at'] = $time + self::SUB_TYPE[$type]['day'] * 86400;
            $data['subscribe_cnt'] = $user->subscribe_cnt + 1;
        }
        if (0 == $user->subscribed_at) {
            $voice = $this->getRomVoice($uid, [1, 2, 3, 4]);
            if ($voice) {
                SubscribeModel::create([
                    'voice_id' => $voice['id'],
                    'uid' => $user->uid,
                    'type' => 1,
                ]);
            }
            if (0 != $user->invite_uid) {
                UserModel::where('uid', $user->invite_uid)->increment('gnight_coin', 3);
                try {
                    UserModel::where([
                        ['uid', $uid],
                        ['gnight_coin', $user->gnight_coin],
                    ])->update($data);
                } catch (\Exception $e) {
                    UserModel::where('uid', $user->invite_uid)->decrement('gnight_coin', 3);
                }
                $inlogmodel = new InviteLogModel();
                $invite = $inlogmodel->fill([
                    'uid' => $user->invite_uid,
                    'invite_uid' => $uid,
                    'gnight_coin' => 3,
                ]);
                $invite->save();

                return $data['subscribed_at'];
            } else {
                UserModel::where([
                    ['uid', $uid],
                    ['gnight_coin', $user->gnight_coin],
                ])->update($data);

                return $data['subscribed_at'];
            }
        } else {
            UserModel::where([
                ['uid', $uid],
                ['gnight_coin', $user->gnight_coin],
            ])->update($data);

            return $data['subscribed_at'];
        }
    }

    /**
     * Rom获取一条语音
     * @param  int  $uid
     * @param  array  $topics
     * @return bool
     */
    public function getRomVoice(int $uid, $topics = array(1, 2, 3, 4))
    {
        $user = UserModel::findOrFail($uid);
        $edvoices = SubscribeModel::where('uid', $user->uid)->get();
        $selfvoices = VoiceModel::where('uid', $user->uid)->get();
        $voices = VoiceModel::where([
            ['check', 1],
            ['sex', $user->like_sex],
        ])->whereNotIn('id', $edvoices->pluck('voice_id'))
            ->whereIn('topic_id', $topics)
            ->whereNotIn('id', $selfvoices->pluck('id'))->get();
        if (!collect($voices)->isEmpty()) {
            $voice = $voices->random();

            return $voice->toArray();
        }

        return false;
    }

    /**
     * 我订阅的晚安列表
     * @param  int  $page
     * @param  int  $limit
     * @param  int  $uid
     * @return array
     */
    public function voices(int $page, int $limit, int $uid)
    {
        $total = \DB::select(
            "select count(*) as aggregate from `kdgx_goodnight_subscribe_voice` as `sub` inner join `kdgx_goodnight_voice` as `voice` on `voice_id` = voice.id where `sub`.`uid` = ? and `voice`.`deleted_at` is null",
            [$uid]
        );
        $voices = \DB::select(
            "select `voice`.`id`, `voice`.`uid`, `voice`.`expedit`, `sub`.`created_at`, `cover`, `voice`, `like`, `sub`.`created_at` as `geted_at` from `kdgx_goodnight_subscribe_voice` as `sub` inner join `kdgx_goodnight_voice` as `voice` on `voice_id` = voice.id where `sub`.`uid` = ? and `voice`.`deleted_at` is null order by `sub`.`created_at` desc limit ?, ?",
            [$uid, ($page - 1) * $limit, $limit]
        );
        foreach ($voices as &$voice) {
            $tag = TagModel::where([
                ['uid', $uid],
                ['voice_id', $voice->id],
            ])->first();
            if (collect($tag)->isEmpty()) {
                $voice->tag = "";
            } else {
                $voice->tag = $tag->tag;
            }
        }

        return array(
            'total' => $total[0]->aggregate,
            'list' => $voices,
        );
    }

    /**
     * 推送订阅
     */
    public function pushload()
    {
        // 获取有效订阅用户
        $today = date('d');
        $uids = Redis::hkeys("goodnight:push:{$today}");
        $users = UserModel::where('subscribed_at', '>', time())->get();
        foreach ($users as $user) {
            $voice_id = Redis::hget("goodnight:push:{$today}", $user->uid);
            try {
                $voice = VoiceModel::findOrFail($voice_id);
            } catch (\Exception $e) {
                // 筛选声音
                $edvoices = SubscribeModel::where('uid', $user->uid)->get();
                $selfvoices = VoiceModel::where('uid', $user->uid)->get();
                $voices = VoiceModel::where([
                    ['commit', 1],
                    ['sex', $user->like_sex],
                ])->whereNotIn('id', $edvoices->pluck('voice_id'))
                    ->whereNotIn('id', $selfvoices->pluck('id'))->get();
                if (collect($voices)->isEmpty()) {
                    continue;
                }
                $voice = $voices->random();
            }
            // 送入数据库
            SubscribeModel::create([
                'voice_id' => $voice->id,
                'is_push' => 1,
                'uid' => $user->uid,
            ]);
            VoiceModel::where('id', $voice->id)->increment('view', 1);
            // 通知
            try {
                $ns = new NoticeService();
                $ns->subscribe($user->uid, $voice->uid, $voice->id);
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }
        }
    }

    /**
     * 捞取晚安
     * @param  int  $uid
     * @return bool
     * @throws AlertException
     */
    public function fishVoice(int $uid)
    {
        $cnt = SubscribeModel::where([['uid', $uid], ['type', 2]])->whereBetween(
            'created_at',
            [mktime(0, 0, 0), mktime(0, 0, 0) + 86400]
        )->count();
        if ($cnt >= 10) {
            throw new AlertException("漂流瓶获取次数达上限，明天再来吧", 101);
        }
        $voice = $this->getRomVoice($uid, [1, 2, 3, 4]);
        if ($voice) {
            DB::beginTransaction();
            try {
                DB::table('kdgx_goodnight_subscribe_voice')->insert([
                    'created_at' => time(),
                    'updated_at' => time(),
                    'voice_id' => $voice['id'],
                    'uid' => $uid,
                    'type' => 2,
                ]);
                DB::commit();

                return $voice;
            } catch (\Exception $e) {
                DB::rollBack();
                throw new AlertException('很遗憾未能捞到晚安！');
            }
        }
        throw new AlertException('很遗憾未能捞到晚安');
    }

    /**
     * 获取今日晚安
     * @param  int  $uid
     * @return VoiceModel|array
     */
    public function todayVoice(int $uid)
    {
        $vsm = new SubscribeModel();
        $bet = array(
            mktime(21, 30, 0),
            mktime(23, 59, 59),
        );
        $sub = $vsm->where([['uid', $uid], ['is_push', 1]])->whereBetween('created_at', $bet)->first();
        if (collect($sub)->isEmpty()) {
            return array();
        } else {
            $vs = new VoiceService();

            return $vs->getVoice($uid, $sub->voice_id);
        }
    }
}
