<?php

namespace App\Services\Pair;

use App\Exceptions\AlertException;
use App\Exceptions\DBException;
use App\Http\Controllers\Core\Auth;
use App\Models\Deed\DeedModel;
use App\Models\Fpdx\ActivityModel;
use App\Models\Fpdx\GroupModel;
use App\Models\Fpdx\PairModel;
use App\Models\Fpdx\RoomModel;
use App\Models\Fpdx\WxkfModel;
use App\Models\TicketModel;
use App\Models\User\AuthKey;
use App\Models\User\UserModel;
use App\Services\App\KfService;
use App\Services\App\ProfileService;
use App\Services\Pay\OrderService;
use App\Services\Service;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class PairService extends Service
{
    /**
     * 通过小花提升成功率
     * @param  int  $pair_id
     * @param  array  $flowers
     * @return bool
     * @throws AlertException
     * @throws DBException
     */
    public function addScoreByFlower(int $pair_id, array $flowers)
    {
        $pair = PairModel::findOrFail($pair_id);
        if ($pair->state > 200) {
            throw new AlertException("报名时间已结束", 402);
        }
        $user = UserModel::findOrFail($pair->uid);
        if (
            $user->red_flower < $flowers['red_flower']
            || $user->gold_flower < $flowers['gold_flower']
        ) {
            throw new AlertException("余额不足", 403);
        }
        $flower = $flowers['red_flower'] + $flowers['gold_flower'];
        if ($flower * 10 + $pair->score > 90) {
            throw new AlertException("超过上限", 404);
        }
        $pair->score = $pair->score + $flower * 10;
        if ($pair->score >= 60 && $pair->state < 100) {
            $pair->state = $pair->state + 100;

            // 通知
            try {
                // 系统消息
                $notice = new \App\Services\Pair\NoticeService();
                $notice->inviteToSuccess($pair->uid);
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }
        }
        if ($pair->save()) {
            UserModel::where('uid', $pair->uid)->update([
                'red_flower' => $user->red_flower - $flowers['red_flower'],
                'gold_flower' => $user->gold_flower - $flowers['gold_flower'],
            ]);
            \DB::table('kdgx_partner_charge_pay_logs')->insert([
                'uid' => $pair->uid,
                'create_at' => time(),
                'type' => 13,
                'red_flower' => 0 - $flowers['red_flower'],
                'gold_flower' => 0 - $flowers['gold_flower'],
                'remark' => "72小时提升匹配成功率",
            ]);

            return true;
        } else {
            throw new DBException();
        }
    }

    /**
     * 通过超级会员卡提升成功率
     * @param  int  $pair_id
     * @return bool
     * @throws AlertException
     */
    public function addScoreBySupvip(int $pair_id)
    {
        $pair = PairModel::findOrFail($pair_id);
        if ($pair->state > 200) {
            throw new AlertException("报名时间已结束", 402);
        }

        $ticket = TicketModel::where(array(
            ['uid', $pair->uid],
            ['validity_time', '>', time()],
            ['type', 3],
            ['state', 0],
        ))->orderBy('validity_time', 'asc')->first();
        if (collect($ticket)->isEmpty()) {
            throw new AlertException("本月已经没有次数了");
        }

        if ($pair->score >= 92) {
            throw new AlertException("超过上限", 404);
        }
        $ticket->state = 1;
        $ticket->save();
        if ($pair->state < 100) {
            $pair->state = $pair->state + 100;

            // 通知
            try {
                $notice = new \App\Services\Pair\NoticeService();
                $notice->inviteToSuccess($pair->uid);
            } catch (\Exception $e) {
            }
        }
        $pair->score = 92;
        $pair->save();

        return true;
    }

    /**
     * 不/同意匹配结果
     * @param  int  $pair_id  报名记录
     * @param  int  $confirm  1同意;-1不同意
     * @return bool
     * @throws AlertException
     * @throws DBException
     */
    public function confirmPair(int $pair_id, int $confirm)
    {
        $pair = PairModel::findOrFail($pair_id);

        $uid = Auth::auth();
        if ($pair->uid != $uid) {
            throw new AlertException("无权限", 101);
        }

        if (
            $pair->state < 400
            || $pair->state > 499
            || empty($pair->assoc_id)
            || $pair->room_id > 0
        ) {
            throw new AlertException("不在活动签到时间!");
        }
        $activity = ActivityModel::findOrFail($pair->stage_id);
        if (time() > $activity->activity_time + 3600 * 10) {
            throw new AlertException("不在活动签到时间");
        }

        if ($pair->confirm != 0) {
            throw new AlertException("恭喜！CP关系确认成功,匹配对象确认CP关系后将会解锁活动群", 102);
        }

        switch ($confirm) {
            case 1:
                $other = PairModel::findOrFail($pair->assoc_id);
                $pair->confirm = time();
                if (0 < $other->confirm) {
                    DB::beginTransaction();
                    try {
                        $room = RoomModel::create([
                            'stage_id' => $pair->stage_id,
                            'member' => "{$pair->uid},{$other->uid}",
                            'create_time' => time(),
                            'type' => 1,
                        ]);
                        $pair->room_id = $room->room_id;
                        $other->room_id = $room->room_id;
                        $pair->save() && $other->save();
                        DB::commit();
                    } catch (\Exception $exception) {
                        DB::rollBack();
                        throw new DBException($exception->getMessage());
                    }
                } else {
                    $pair->save();
                }
                break;
            case -1:
                $pair->confirm = 0 - time();
                $pair->save();
                break;
            default:
                throw new AlertException("错误的操作逻辑");
        }

        // 发送通知
        try {
            $other = PairModel::findOrFail($pair->assoc_id);
            $noticeService = new NoticeService();
            // pair同意 => 单方确认（通知对方）
            if (0 < $pair->confirm && $other->confirm == 0) {
                $noticeService->unilateralConfirm($other->uid, $other->id);
            }
            // pair不同意 => 单方不同意（通知对方）
            if (0 > $pair->confirm && $other->confirm == 0) {
                $noticeService->unilateralAgain($other->uid, $other->id);
            }
            // pair同意;other同意 => 双方同意 (通知双方)
            if (0 < $pair->confirm && 0 < $other->confirm) {
                $noticeService->unlockGroup($other->uid, $other->id);
                $noticeService->unlockGroup($pair->uid, $pair->id);
            }
        } catch (\Exception $exception) {
        }

        return true;
    }

    /**
     * 匹配成功-72-签到反悔
     * @param  int  $pair_id
     * @return bool
     * @throws AlertException
     */
    public function goBackConfirm(int $pair_id)
    {
        $pair = PairModel::findOrFail($pair_id);

        $uid = Auth::auth();
        if ($pair->uid != $uid) {
            throw new AlertException("无权限");
        }

        if (0 == $pair->confirm || abs($pair->confirm) + 3600 <= time()) {
            throw new AlertException("当前不可反悔");
        }

        $activity = ActivityModel::findOrFail($pair->stage_id);
        if (time() >= $activity->activity_time + 3600 * 10) {
            throw new AlertException("当前时间不可反悔");
        }

        if ($pair->goback_at > 0) {
            throw new AlertException("反悔次数已用完");
        }

        $pair->confirm = 0;
        $pair->goback_at = time();

        if ($pair->room_id > 0) {
            try {
                DB::beginTransaction();
                $pair->save();
                RoomModel::where('room_id', $pair->room_id)->delete();
                PairModel::where('room_id', $pair->room_id)->update(['room_id' => 0]);
                DB::commit();
            } catch (\Exception $exception) {
                DB::rollBack();
                throw $exception;
            }
        } else {
            $pair->save();
        }

        Redis::sadd("fpdx:pair:{$pair->stage_id}:gobackconfirm", $pair->uid);

        // 通知
        try {
            $other = PairModel::findOrFail($pair->assoc_id);
            $noticeService = new NoticeService();
            $noticeService->regretConfirm($other->uid);
        } catch (\Exception $exception) {
        }

        return true;
    }

    /**
     * 获取某人最近一期的状态
     * @param  int  $uid
     * @param  int  $stage_id
     * @return array
     */
    public function getActivityInfo(int $uid, int $stage_id)
    {
        $next = PairModel::where([
            ['uid', $uid],
            ['stage_id', $stage_id],
        ])->first();
        if (collect($next)->isEmpty()) {
            return array();
        } else {
            $result = $next->toArray();
            $activity = ActivityModel::find($next->stage_id, [
                'stage_id',
                'activity_name',
                'activity_time',
                'close_time',
                'signbegin_time',
                'signend_time',
                'open_time',
                'rematch_begin_at',
                'rematched_at',
            ]);
            $result['activity'] = $activity;
            $result = array_merge($result, $activity->toArray());
            $result['pair_info'] = array();
            $user = UserModel::find($uid);
            try {
                $progress = $next->progress();
                $result['progress'] = $progress;
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }
            $result['pair_info']['user_info'] = array_merge($next->toArray(), $user->toArray());
            if (empty($result['assoc_id'])) {
                return $result;
            }
            $result['pair_info']['room_info'] = RoomModel::find($result['room_id']) ?? [];
            $result['pair_info']['group'] = GroupModel::find($result['group_id']);
            $partner_pair = PairModel::find($result['assoc_id']);
            $partner_user = UserModel::find($partner_pair->uid);
            $result['pair_info']['partner_info'] = array_merge($partner_pair->toArray(), $partner_user->toArray());

            return $result;
        }
    }

    // 获取某人最近一期的状态
    public function getRecentState(int $uid)
    {
        $next = PairModel::where('uid', $uid)->OrderBy('stage_id', 'desc')->first();
        if (collect($next)->isEmpty()) {
            return [];
        } else {
            $result = $next->toArray();
            $activity = ActivityModel::findOrFail($next->stage_id, [
                'activity_name',
                'activity_time',
                'close_time',
                'signbegin_time',
                'signend_time',
                'open_time',
                'rematched_at',
                'qbj_stage_id',
            ]);
            $result = array_merge($result, $activity->toArray());
            try {
                $progress = $next->progress();
                $result['progress'] = $progress;
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }
            $result['pair_info'] = array();
            $result['activity'] = $activity;
            if (empty($result['assoc_id'])) {
                return $result;
            }
            $result['pair_info']['room_info'] = RoomModel::find($result['room_id']) ?? [];
            $partner_pair = PairModel::findOrFail($result['assoc_id']);
            $partner_user = UserModel::findOrFail($partner_pair->uid);
            $result['pair_info']['partner_info'] = array_merge($partner_pair->toArray(), $partner_user->toArray());
            $user = UserModel::findOrFail($uid);
            $result['pair_info']['user_info'] = array_merge($next->toArray(), $user->toArray());

            return $result;
        }
    }

    /**
     * 结算本期|报名下一期
     * @param  int  $stageId
     * @param  int  $uid
     * @param  array  $enroll
     * @param  string  $os
     * @return int
     * @throws AlertException
     */
    public function enrollNext(int $stageId, int $uid, array $enroll, string $os)
    {
        $data = PairModel::where([
            ['uid', $uid],
            ['stage_id', $stageId],
        ])->first();
        if (collect($data)->isEmpty() || 'qbj' == $data->activity_type) {
            throw new AlertException("错误的期数", 103);
        }

        $isture = false;        // 是否自动报名下一期: 否
        $canenroll = false;     // 是否结算: 否

        // 匹配失败
        if ($data->state >= 300 && $data->state < 400) {
            $isture = true; // 是否结算：是
            $canenroll = true; // 自动报名下一期：是
            $state = 700 + intval($data->state) % 100; // 本期状态 => 70x
            $next_state = 100 + intval($data->state) % 100; // 自动报名成功
            $order_id = $data->order_id; // 携带报名费用
            $pay = $data->pay; // 携带报名费用
            $score = $data->score; // 携带报名分数
            $add_score = $data->add_score; // 携带报名分数
        }
        // 不满意
        if ($data->state >= 500 && $data->state < 600) {
            $isture = true; // 是否结算：是
            $canenroll = true; // 自动报名下一期：是
            $state = 700 + intval($data->state) % 100; // 本期状态 => 70x
            $next_state = 100 + intval($data->state) % 100; // 自动报名成功
            $order_id = $data->order_id; // 携带报名费用
            $pay = $data->pay; // 携带报名费用
            $score = $data->score; // 携带报名分数
            $add_score = $data->add_score;
        }
        // 报名失败
        if ($data->state >= 900 && $data->state < 999) {
            $isture = true; // 是否结算：是
            $canenroll = false; // 自动报名下一期：否
            $state = 1000 + intval($data->state) % 100;// 本期状态 => 100x
            $next_state = 0; // 自动报名成功: 否
            $order_id = 0; // 携带报名费用: 否
            $pay = 0;
            $score = 0; // 携带报名分数: 否
            $add_score = $data->add_score;
        }
        // 自己未操作对方重配
        if ($data->state >= 800 && $data->state < 900 && $data->confirm == 0 && empty($data->assoc_id)) {
            $isture = true; // 是否结算：是
            $canenroll = false; // 自动报名下一期: 否
            $state = 700 + intval($data->state) % 100; // 本期状态 => 70x
            $next_state = 0; // 自动报名成功: 否
            $order_id = 0; // 携带报名费用: 否
            $pay = 0;
            $score = 0; // 携带报名分数: 否
            $add_score = $data->add_score;
        }
        // 重配失败
        if (
            (($data->state >= 400
                    && $data->state < 500)
                || ($data->state >= 800
                    && $data->state < 900))
            && empty($data->assoc_id)
            && $data->last_assoc > 0
            && $data->confirm != 0
        ) {
            $isture = true; // 是否结算：是
            $canenroll = true; // 自动报名下一期:是
            $state = 700 + intval($data->state) % 100; // 本期状态 => 70x
            $next_state = 100 + intval($data->state) % 100; // 自动报名成功: 是
            $order_id = 0; // 携带报名费用: 否
            $pay = 0;
            $score = $data->score; // 携带报名分数: 是
            $add_score = $data->add_score;
        }

        if (!$isture) {
            throw new AlertException("不可报名下一期", 100);
        }

        $pair_id = 0;
        if ($canenroll) {
            $ings = ActivityModel::getActivitys();
            $next = PairModel::where([
                ['uid', $uid],
                ['stage_id', $ings['next']],
            ])->first();
            if (!collect($next)->isEmpty()) {
                throw new AlertException("你已报名下一期", 100);
            }
            $user = UserModel::findOrFail($uid);
            if (!in_array($user->sex, [1, 2])) {
                throw new AlertException("请补全性别", 100);
            }
            $tmp = [
                'uid' => $data->uid,
                'stage_id' => $ings['next'],
                'state' => $next_state,
                'order_id' => $order_id,
                'pay' => $pay,
                'score' => $score,
                'add_score' => $add_score,
                'data' => $os,
                'sex' => $user->sex,
                'create_time' => time(),
                'media_id' => 'gh_b598cb7474d8',
            ];
            $pair = array_merge($tmp, $enroll);
            DB::beginTransaction();
            try {
                $save = array(
                    'state' => $state,
                );
                if ($order_id > 0) {
                    $save['pay'] = 0;
                }
                DB::table("kdgx_partner_charge_pair")->where('id', $data->id)->update($save);
                $pair_id = DB::table("kdgx_partner_charge_pair")->insertGetId($pair);
                DB::commit();

                try {
                    // 系统消息
                    $notice = new \App\Services\Pair\NoticeService();
                    $notice->inviteToSuccess($pair->uid);
                } catch (\Exception $e) {
                }
            } catch (\Exception $exception) {
                DB::rollBack();
                throw $exception;
            }
        } else {
            DB::table("kdgx_partner_charge_pair")->where('id', $data->id)->update(['state' => $state]);
        }

        return $pair_id;
    }

    /**
     * 免费报名
     * @param  int  $uid
     * @param  int  $stage_id
     * @param  array  $data
     * @return mixed
     * @throws AlertException
     */
    public function freeEnroll(int $uid, int $stage_id, array $data)
    {
        $pm = new PairModel();
        if ($pm->where([['uid', $uid], ['stage_id', $stage_id]])->exists()) {
            throw new AlertException("你已经报名了本期活动", 101);
        }
        $user = UserModel::findOrFail($uid);
        if (!in_array($user->sex, [1, 2])) {
            throw new AlertException("请补全性别", 102);
        }
        if ($user->sex == 2 && $data['state'] == 3) {
            $data['state'] = 103;
        }
        $data = array_merge(
            ['uid' => $uid, 'stage_id' => $stage_id, 'sex' => $user->sex, 'create_time' => time()],
            $data
        );
        DB::beginTransaction();
        try {
            $pair_id = DB::table('kdgx_partner_charge_pair')->insertGetId($data);
            DB::commit();
            if ($data['state'] > 100) {
                // 通知
                try {
                    // 系统消息
                    $notice = new \App\Services\Pair\NoticeService();
                    $notice->inviteToSuccess($uid);
                } catch (\Exception $e) {
                    app('sentry')->captureException($e);
                }
            }

            return $pair_id;
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * 超级会员报名
     * @param  int  $uid
     * @param  int  $stage_id
     * @param  array  $data
     * @return int
     * @throws AlertException
     */
    public function supvipEnroll(int $uid, int $stage_id, array $data)
    {
        $pm = new PairModel();
        if ($pm->where([['uid', $uid], ['stage_id', $stage_id]])->exists()) {
            throw new AlertException("你已经报名了本期活动", 101);
        }
        $user = UserModel::findOrFail($uid);
        if (!in_array($user->sex, [1, 2])) {
            throw new AlertException("请补全性别", 102);
        }
        $ticket = TicketModel::where(array(
            ['uid', $uid],
            ['validity_time', '>', time()],
            ['type', 3],
            ['state', 0],
        ))->orderBy('validity_time', 'asc')->first();
        if (collect($ticket)->isEmpty()) {
            throw new AlertException("本月已经没有次数了");
        }
        $data = array_merge(
            ['uid' => $uid, 'stage_id' => $stage_id, 'sex' => $user->sex, 'create_time' => time()],
            $data
        );
        DB::beginTransaction();
        try {
            $pair_id = DB::table('kdgx_partner_charge_pair')->insertGetId($data);
            $ticket->state = 1;
            $ticket->save();
            DB::commit();

            // 通知
            try {
                // 系统消息
                $notice = new \App\Services\Pair\NoticeService();
                $notice->inviteToSuccess($uid);
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }

            return $pair_id;
        } catch (\Exception $exception) {
            DB::rollBack();
            throw $exception;
        }
    }

    /**
     * 获取某人是否可以使用微信kf
     * @param  int  $uid
     * @return bool
     * @throws \App\Exceptions\ApiException
     */
    public function isopenwxkf(int $uid): bool
    {
        $pf = new ProfileService();
        $js = $pf->get('fpdx_open_status');
        if (empty($js)) {
            return false;
        } else {
            $conf = json_decode($js, true);
            if (!isset($conf['fpdx_zskf']) || $conf['fpdx_zskf'] == 0) {
                return false;
            }
        }
        $user = UserModel::findOrFail($uid);
        $wxm = new WxkfModel();
        if (empty($user->wxkf)) {
            $kfs = new KfService();
            $wxid = $kfs->hashWxkf($user->uid);
            if ($wxid) {
                return true;
            }

            return false;
        } else {
            if (
                $auth = AuthKey::where([
                ['uid', $user->uid],
                ['auth_type', 'wxid'],
                ])->exists()
            ) {
                return false;
            }
            $wxkf = $wxm->where('wxid', $user->wxkf)->first();
            if (collect($wxkf)->isEmpty()) {
                return false;
            }
            if ("活动" == $wxkf->type && $wxkf->state == 1) {
                return true;
            } else {
                return false;
            }
        }
    }

    public function keepRoom($uid)
    {
        $keep_rooms = Redis::smembers("keep_rooms");
        $room_id = PairModel::where('uid', $uid)->whereIn("room_id", $keep_rooms)->value('room_id');

        return $room_id;
    }

    /**
     * 保持CP关系
     * @param $uid
     * @param $room_id
     * @throws AlertException
     */
    public function keep($uid, $room_id)
    {
        // 判断有没有保持CP的报名信息
        $pair = PairModel::where(['uid' => $uid, 'keep' => 1])->first();
        if ($pair) {
            //
            if (RoomModel::where('room_id', $pair->room_id)->where('keep', 1)->first()) {
                throw new AlertException("只能跟一个CP保持关系", 403);
            } else {
                $this->unKeep($uid, $pair->room_id);
            }
        }
        $pair = PairModel::where(['uid' => $uid, 'room_id' => $room_id])->first();
        if (!$pair) {
            throw new AlertException("不存在", 404);
        }
        $activity = ActivityModel::findOrFail($pair->stage_id);
        if ($activity->open_time > time() && $activity->close_time <= time()) {
            throw new AlertException("只能在活动期间保持关系", 410);
        }
        $pair->keep = 1;
        $pair->save();
        $other = PairModel::find($pair->assoc_id);
        if ($other->keep == 1) {
            Redis::sadd("keep_rooms", $room_id);
        }
    }

    /**
     * 取消关系
     * @param $uid
     * @param $room_id
     */
    public function unKeep($uid, $room_id)
    {
        $pair = PairModel::where(['uid' => $uid, 'room_id' => $room_id])->first();
        $pair->keep = 0;
        $pair->save();
        Redis::srem("keep_rooms", $room_id);
    }

    /**
     * 删除报名纪录
     * @param $uid
     * @return bool
     * @throws AlertException
     * @throws \App\Exceptions\ApiException
     */
    public function deletePair($uid)
    {
        // 检验当前活动
        $stage_id = ActivityModel::where([
            ['signend_time', '<', time()],
            ['close_time', '>', time()],
        ])->value('stage_id');
        if (PairModel::where('uid', $uid)->where('stage_id', $stage_id)->where('state', '<', 600)->first()) {
            throw new AlertException("正在活动中不能删除报名信息", 409);
        }

        // 检验最近一期活动
        $stages = ActivityModel::getActivitys();
        $pair = PairModel::where([
            ['uid', $uid],
            ['stage_id', $stages['next']],
        ])->whereBetween('state', [0, 299])->whereNull('assoc_id')->first();
        if (collect($pair)->isEmpty()) {
            return true;
//            throw new AlertException('未能自动索引到报名纪录，请联系管理员手动处理(每周三的下午12：30-16：00[视情况调整时间]为预匹配时间,请稍后重试)',204);
        }

        // 退款
        if ($pair->order_id > 0 && $pair->pay > 0) {
            $orderService = new OrderService();
            $orderService->refund($pair->order_id, $pair->pay * 100, "72小时CP退款", true);
        }
        PairModel::where('id', $pair->id)->delete();
        DeedModel::where([
            ['type', 1],
            ['uid', $pair->uid],
            ['ack', $pair->id],
        ])->delete();

        return true;
    }
}
