<?php

namespace App\Managers;

use App\Exceptions\DBException;
use App\Generated\Exceptions\CustomErrorMessageException;
use App\Models\Fpdx\GroupMemberModel;
use App\Models\Fpdx\GroupModel;
use App\Exceptions\AlertException;
use App\Models\Fpdx\ActivityModel;
use App\Models\Fpdx\MediaOrderModel;
use App\Models\Fpdx\PairModel;
use App\Models\Fpdx\RoomModel;
use App\Models\Friends\PairContactApply;
use App\Models\OrderModel;
use App\Models\Share\PairApplyListShareHelpLog;
use App\Models\User\UserModel;
use App\Services\Pay\OrderService;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\DB;

class PairManager
{

    private $pairModel;
    private $orderModel;
    private $orderManager;

    public function __construct()
    {
        $this->pairModel = new PairModel();
        $this->orderModel = new OrderModel();
        $this->orderManager = new OrderManager();
    }

    public function getRecommendPairApplyContacts(int $uid, array $filterUsers): array
    {
    }

    /**
     * 用户报名匹配并签到
     * @param  int  $stage_id
     * @param  int  $uid
     * @param  int  $pairUid
     * @throws \Throwable
     */
    public function matchUserAndEnrollAndSign(int $stage_id, int $uid, int $pairUid)
    {
        DB::transaction(function () use ($stage_id, $uid, $pairUid) {
            $userPair = PairModel::firstOrNew([
                'uid' => $uid, 'stage_id' => $stage_id
            ], [
                'state' => 103
            ]);
            $pairPair = PairModel::firstOrNew([
                'uid' => $pairUid, 'stage_id' => $stage_id
            ], [
                'state' => 103
            ]);
            if ($pairPair->assoc_id || $userPair->assoc_id) {
                throw new DBException('用户已有匹配对象');
            }
            $userPair->assoc_id = $pairPair->id;
            $userPair->confirm = time();
            $userPair->state = 400 + $userPair->state % 100;
            $pairPair->assoc_id = $userPair->id;
            $pairPair->confirm = time();
            $pairPair->state = 400 + $pairPair->state % 100;
            $userPair->save() && $pairPair->save();
        });
    }

    private function getGoods()
    {
        $goods = $this->orderModel::GOODS[3];
        return $goods;
    }


    /**
     * 获取某人最近一期的状态
     * @param  int  $uid
     * @return array
     */
    public function getRecentState(int $uid): array
    {
        $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  $uid
     * @param  int  $stage_id
     * @return array
     */
    public function getActivityInfo(int $uid, int $stage_id): array
    {
        $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;
        }
    }


    /**
     * 获取保持关联的房间
     * @param  int  $uid
     * @return int $room_id | null
     */
    public function getKeepRoom(int $uid)
    {
        $keep_rooms = Redis::smembers("keep_rooms");
        $room_id = PairModel::where('uid', $uid)->whereIn("room_id", $keep_rooms)->value('room_id');
        return $room_id;
    }


    /**
     * 保持关系
     * @param  int  $uid
     * @param  int  $room_id
     * @throws AlertException
     */
    public function keepRoom(int $uid, int $room_id)
    {
        $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
     * @throws CustomErrorMessageException
     */
    public function removeKeepRoom($uid, $room_id)
    {
        $pair = PairModel::where(['uid' => $uid, 'keep' => 1, 'room_id' => $room_id])->first();
        if (!$pair) {
            throw new CustomErrorMessageException('');
        }
        $pair->keep = 0;
        $pair->save();
        Redis::srem("keep_rooms", $room_id);
    }


    /**
     * 获取落单群
     * @param $uid
     * @param $stage_id
     * @return mixed
     * @throws AlertException
     */
    public function getAloneGroup($uid, $stage_id)
    {
        $activity_type = '72h';
        $group_id = GroupMemberModel::where([
            'stage_id' => $stage_id,
            'uid' => $uid,
            'activity_type' => $activity_type,
            'type' => 'alone'
        ])->value('group_id');
        if (!$group_id) {
            $groups = GroupModel::where([
                'stage_id' => $stage_id,
                'type' => 'alone',
                'activity_type' => $activity_type
            ])->get();
            foreach ($groups as $group) {
                $number = GroupMemberModel::where([
                    'stage_id' => $stage_id,
                    'group_id' => $group->id,
                    'activity_type' => $activity_type,
                    'type' => 'alone'
                ])->count();
                if ($number < $group->number) {
                    $group_id = $group->id;
                    break;
                }
            }
            if (empty($group_id)) {
                throw new AlertException("落单群已经满", 401);
            }
            GroupMemberModel::create([
                'uid' => $uid,
                'stage_id' => $stage_id,
                'group_id' => $group_id,
                'activity_type' => $activity_type,
                'type' => 'alone'
            ]);
        }
        return $group_id;
    }


    /**
     * 免费报名
     * @param  int  $uid
     * @param $stageId
     * @param  array  $attach
     * @return PairModel|\Illuminate\Database\Eloquent\Model
     * @throws CustomErrorMessageException
     */
    public function enrollFree(int $uid, $stageId, array $attach)
    {
        if (PairModel::where([['uid', $uid], ['stage_id', $stageId]])->exists()) {
            throw new CustomErrorMessageException("你已经报名了72小时恋爱体验，请勿重复报名哦");
        }

        $pair = PairModel::create($attach);

        // 通知
        if ($pair->state > 100) {
            try {
                $notice = new \App\Services\Pair\NoticeService();
                $notice->inviteToSuccess($uid);
            } catch (\Exception $e) {
                app('sentry')->captureException($e);
            }
        }
        return $pair;
    }


    /**
     * 退款
     * @param  PairModel  $pair
     * @throws CustomErrorMessageException
     */
    public function refund(PairModel $pair)
    {
        if (!in_array(floor($pair->state / 100), [3, 5, 9])) {
            throw new CustomErrorMessageException("订单不可退");
        }
        try {
            DB::beginTransaction();
            switch ($pair->state % 100) {
                case 1:
                case 4:
                    if ($pair->pay > 0) {
                        $pair->pay = 0;
                        $pair->state = 600 + $pair->state % 100;
                        $pair->save();
                        $order = new OrderService();
                        $order->refund($pair->order_id, $pair->pay * 100, "72小时CP退款", true);
                        if ($pair->fx_money) {
                            MediaOrderModel::create([
                                'media_id' => $pair->media_id,
                                'type' => 'refund',
                                'amount' => -($pair->fx_money * 100),
                                'tag' => '分配对象',
                                'describe' => "用户分配对象活动第{$pair->stage_id}期退款（订单ID：{$pair->order_id}）",
                            ]);
                        }
                    } else {
                        if ($pair->state > 900 && $pair->state < 1000) {
                            $pair->state = 1101;
                            $pair->save();
                        } else {
                            $pair->state = 601;
                            $pair->save();
                        }
                    }
                    DB::commit();
                    break;
                case 2:
                    $pair->state = 1102;
                    $pair->save();
                    DB::commit();
                    break;
                case 3:
                    if ($pair->pay > 0) {
                        $pair->pay = 0;
                        if ($pair->state > 900 && $pair->state < 1000) {
                            $pair->state = 1103;
                        } else {
                            $pair->state = 603;
                        }
                        $pair->save();
                        $order = new OrderService();
                        $order->refund($pair->order_id, $pair->pay * 100, "72小时CP退款", true);
                        if ($pair->fx_money) {
                            MediaOrderModel::create([
                                'media_id' => $pair->media_id,
                                'type' => 'refund',
                                'amount' => -($pair->fx_money * 100),
                                'tag' => '分配对象',
                                'describe' => "用户分配对象活动第{$pair->stage_id}期退款（订单ID：{$pair->order_id}）",
                            ]);
                        }
                    } else {
                        if ($pair->state > 900 && $pair->state < 1000) {
                            $pair->state = 1103;
                        } else {
                            $pair->state = 603;
                        }
                        $pair->save();
                    }
                    DB::commit();
                    break;
            }
        } catch (\Exception $e) {
            DB::rollBack();
            throw new CustomErrorMessageException('退款失败请尝试联系运营人员');
        }
    }


    /**
     * 报名下一期
     * @param  PairModel  $pair
     * @param  array  $attribute
     * @throws CustomErrorMessageException
     */
    public function enrollNext(PairModel $pair, array $attribute)
    {
        switch ($pair / 100) {
            case "3":
                $attribute['state'] = 100 + intval($pair->state) % 100; // 自动报名成功
                $attribute['order_id'] = $pair->order_id; // 携带报名费用
                $attribute['pay'] = $pair->pay; // 携带报名费用
                $attribute['score'] = $pair->score; // 携带报名分数
                $attribute['add_score'] = $pair->add_score; // 携带报名分数
                $pair->state = 700 + intval($pair->state) % 100;
                break;
            case "5":
                $attribute['state'] = 100 + intval($pair->state) % 100; // 自动报名成功
                $attribute['order_id'] = $pair->order_id; // 携带报名费用
                $attribute['pay'] = $pair->pay; // 携带报名费用
                $attribute['score'] = $pair->score; // 携带报名分数
                $attribute['add_score'] = $pair->add_score;
                $pair->state = 700 + intval($pair->state) % 100; // 本期状态 => 70x
                break;
            case "4":
            case "8":
                $attribute['state'] = 100 + intval($pair->state) % 100; // 自动报名成功: 是
                $attribute['score'] = $pair->score; // 携带报名分数: 是
                $attribute['add_score'] = $pair->add_score;
                $pair->state = 700 + intval($pair->state) % 100; // 本期状态 => 70x
                break;
            default:
                throw new CustomErrorMessageException("不支持报名下一期");
                break;
        }
        $pair->save();

        $newPair = $this->pairModel->fill($attribute);
        $newPair->save();
    }
}
