<?php

namespace App\Http\Services\V1_1;

use App\Generated\V1_1\Messages\Friend\GetEachLikeContactsMessage;
use App\Generated\V1_1\Messages\Friend\ChangeContactNoteMessage;
use App\Generated\V1_1\Messages\Friend\FriendApplyMsgOverviewMessage;
use App\Generated\V1_1\Messages\Friend\GetAllFriendAppliesMessage;
use App\Generated\V1_1\DTOs\ContactUserDTO;
use App\Generated\V1_1\Messages\Friend\GetContactMessage;
use App\Generated\V1_1\Messages\Friend\GetUnReadSayHelloContactListMessage;
use App\Generated\V1_1\Messages\Friend\GetReadSayHelloContactListMessage;
use App\Generated\V1_1\Messages\Friend\GetReceiveFriendApplyListMessage;
use App\Generated\V1_1\Messages\Friend\GetSendFriendApplyListMessage;
use App\Generated\V1_1\Messages\Friend\SendPairFriendApplyMessage;
use App\Generated\V1_1\Messages\Friend\AgreePairFriendApplyMessage;
use App\Generated\V1_1\Messages\Friend\RefusePairFriendApplyMessage;
use App\Exceptions\AlertException;
use App\Generated\V1_1\DTOs\ListFriendApplyDTO;
use App\Generated\V1_1\DTOs\ListFriendDTO;
use App\Generated\V1_1\DTOs\PageDTO;
use App\Generated\V1_1\Messages\Friend\GetContactListMessage;
use App\Generated\V1_1\Messages\Friend\AgreeFriendApplyMessage;
use App\Http\Controllers\Core\Auth;
use App\Managers\FriendManager;
use App\Generated\V1_1\Messages\Friend\RefuseFriendApplyMessage;
use App\Generated\V1_1\Messages\Friend\DeleteContactMessage;
use App\Generated\V1_1\Messages\Friend\StarContactMessage;
use App\Generated\V1_1\Messages\Friend\UnStarContactMessage;
use App\Generated\V1_1\Messages\Friend\UnBlacklistContactMessage;
use App\Generated\V1_1\Messages\Friend\SendFriendApplyMessage;
use App\Generated\V1_1\Messages\Friend\GetStarContactListMessage;
use App\Generated\V1_1\Messages\Friend\GetFriendListMessage;
use App\Generated\V1_1\Messages\Friend\BlacklistContactMessage;
use App\Managers\PairActivityManager;
use App\Managers\PairManager;
use App\Models\Fpdx\ActivityModel;
use App\Models\Fpdx\PairModel;
use App\Models\Friends\FriendApply;
use App\Models\Friends\FriendContact;
use App\Models\Friends\PairContactApply;
use App\Models\NoticeModel;
use App\Services\IM\CustomElem;
use App\Models\User\UserModel;
use App\Utils\ImUtil;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class FriendService
{
    protected $friendManager;
    public function __construct(FriendManager $friendManager)
    {
        $this->friendManager = $friendManager;
    }
    public function refuseFriendApply(RefuseFriendApplyMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendApply::where([array('uid', $contactUid), array('apply_uid', $uid)])->update(['handle' => -1]);
    }
    public function agreeFriendApply(AgreeFriendApplyMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendApply::where([array('uid', $contactUid), array('apply_uid', $uid)])->update(['handle' => 1]);
        $this->friendManager->beFriend($uid, $contactUid);
    }
    public function unStarContact(UnStarContactMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->update(['star_at' => 0]);
    }
    public function starContact(StarContactMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->update(['star_at' => time()]);
    }
    public function deleteContact(DeleteContactMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->orWhere([array('uid', $contactUid), array('friend_uid', $uid)])->delete();
    }
    public function unBlacklistContact(UnBlacklistContactMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->update(['is_blacklist' => 0]);
    }
    public function blacklistContact(BlacklistContactMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->update(['is_blacklist' => 1]);
    }
    public function sendFriendApply(SendFriendApplyMessage $message)
    {
        $contactUid = $message->getContactUid();
        $uid = Auth::auth();
        if (FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid), array('friend_level', 2)])->exists()) {
            throw new AlertException("你们已经是好友了", 401);
        }
        if (!$this->friendManager->canIm($uid, $contactUid)) {
            throw new AlertException("你们处于拉黑关系", 402);
        }
        FriendApply::updateOrCreate(array('uid' => $uid, 'apply_uid' => $contactUid), array('last_at' => time(), 'handle' => 0));
        $receiveUser = UserModel::find($contactUid, ['uid', 'im_account']);
        $message = new CustomElem('EventFriendApply', ['FromUid' => $uid, 'ToUid' => $contactUid]);
        $imUtil = new ImUtil();
        $imUtil->sendMessage("system_event", $receiveUser->im_account, [$message->toArray()]);
    }
    public function getContactList(GetContactListMessage $message)
    {
        $uid = Auth::auth();
        $lists = Collection::make([]);
        // 1. 好友联系人 + 普通联系人
        $contacts = FriendContact::where('uid', $uid)->whereIn('friend_level', [1, 2])->get();
        $contacts->map(function (&$item) {
            $item->list_type = "contact";
            if ($user = UserModel::whereUid($item->friend_uid)->first()) {
                $item->user = $user->toArray();
            } else {
                $item->user = $user;
            }
        });
        $lists = $lists->merge($contacts);
        // 2. 系统消息
        $systemMsg = NoticeModel::whereUid($uid)->orderByDesc('create_at')->first();
        if ($systemMsg) {
            $systemMsgUnreadCnt = NoticeModel::where([['uid', $uid], ['is_read', 0]])->count();
            $lists->push(['list_type' => 'systemNotice', 'last_at' => $systemMsg->create_at->timestamp, 'last_msg' => null, 'list_unread_msg_cnt' => $systemMsgUnreadCnt, 'star_at' => 0, 'user' => null]);
        }
        // 3. 好友申请
        $friendApply = FriendApply::where([array('apply_uid', $uid), array('receive_unread', 1)])->orWhere([array('uid', $uid), array('send_unread', 1)])->orderByDesc('last_at')->first();
        if ($friendApply) {
            $lists->push(['list_type' => 'friendApply', 'last_at' => $friendApply->last_at, 'last_msg' => null, 'list_unread_msg_cnt' => 1, 'star_at' => 0, 'user' => null]);
        }
        // 4. 打招呼
        $helloListUnreadMsgCnt = FriendContact::where([array('uid', $uid), array('friend_level', 0)])->sum('list_unread_msg_cnt');
        if ($helloListUnreadMsgCnt) {
            $helloContact = FriendContact::where([array('uid', $uid), array('friend_level', 0), array('list_unread_msg_cnt', '>', 0)])->orderByDesc('last_at')->first();
            $helloContact->list_unread_msg_cnt = $helloListUnreadMsgCnt;
            $helloContact->user = null;
            $helloContact->list_type = "hello";
            $lists->push($helloContact);
        }
        $lists = array_values($lists->sortByDesc('last_at')->toArray());
        $message->setResponse(ListFriendDTO::initFromModels($lists));
    }

    /**
     * 星标联系人列表
     * @param  GetStarContactListMessage  $message
     */
    public function getStarContactList(GetStarContactListMessage $message)
    {
        $uid = Auth::auth();
        // 好友联系人 + 普通联系人
        $lists = FriendContact::where('uid', $uid)->where('star_at', '>', 0)->whereIn('friend_level', [1, 2])->orderByDesc('last_at')->with('user')->get();
        $lists = array_values($lists->toArray());
        $message->setResponse(ListFriendDTO::initFromEloquents($lists));
    }
    public function getFriendList(GetFriendListMessage $message)
    {
        $uid = Auth::auth();
        // 好友联系人
        $lists = FriendContact::where('uid', $uid)->where('friend_level', 2)->with('user')->get();
        $lists = array_values($lists->sortByDesc('last_at')->toArray());
        $message->setResponse(ListFriendDTO::initFromEloquents($lists));
    }
    public function refusePairFriendApply(RefusePairFriendApplyMessage $message)
    {
        $uid = Auth::auth();
        $contactUid = $message->getContactUid();
        $activityManager = new PairActivityManager(new ActivityModel());
        $enrollingActivity = $activityManager->getEnrollingActivity();
        if (!$enrollingActivity) {
            return;
        }
        PairContactApply::where([array('activity_id', $enrollingActivity->stage_id), array('send_uid', $contactUid), array('receive_uid', $uid)])->update(['handle' => -1]);
        $receiveUser = UserModel::find($contactUid, ['uid', 'im_account']);
        $message = new CustomElem('EventRefuseRefuseFriendApply', ['FromUid' => $uid, 'ToUid' => $contactUid]);
        $imUtil = new ImUtil();
        $imUtil->sendMessage("system_event", $receiveUser->im_account, [$message->toArray()]);
    }
    public function agreePairFriendApply(AgreePairFriendApplyMessage $message)
    {
        $uid = Auth::auth();
        $contactUid = $message->getContactUid();
        $activityManager = new PairActivityManager(new ActivityModel());
        $enrollingActivity = $activityManager->getEnrollingActivity();
        if (!$enrollingActivity) {
            throw new AlertException("活动邀请已过期");
        }
        if (!($pair = PairModel::where([array('uid', $uid), array('stage_id', $enrollingActivity->stage_id)])->first())) {
            throw new AlertException("你还没有参加本期活动");
        }
        if ($pair->assoc_id) {
            throw new AlertException("你已经有CP了");
        }
        if ($pair = PairModel::where([array('uid', $contactUid), array('stage_id', $enrollingActivity->stage_id)])->first() && $pair->assoc_id) {
            throw new AlertException("TA已经有CP了");
        }
        if (!($pairFriendApply = PairContactApply::where([array('activity_id', $enrollingActivity->stage_id), array('send_uid', $contactUid), array('receive_uid', $uid)])->first())) {
            throw new AlertException("没有收到邀请");
        }
        DB::transaction(function () use ($pairFriendApply, $enrollingActivity) {
            $pairFriendApply->handle = 1;
            $pairFriendApply->save();
            $pairManager = new PairManager();
            $pairManager->matchUserAndEnrollAndSign($enrollingActivity->stage_id, $pairFriendApply->send_uid, $pairFriendApply->receive_uid);
            $friendManager = new FriendManager();
            $friendManager->beFriend($pairFriendApply->send_uid, $pairFriendApply->receive_uid);
        });
    }
    public function sendPairFriendApply(SendPairFriendApplyMessage $message)
    {
        $uid = Auth::auth();
        $contactUid = $message->getContactUid();
        $activityManager = new PairActivityManager(new ActivityModel());
        $enrollingActivity = $activityManager->getEnrollingActivity();
        if (!$enrollingActivity) {
            throw new AlertException("不在活动邀请时间");
        }
        if (PairContactApply::where([array('activity_id', $enrollingActivity->stage_id), array('send_uid', $uid), array('handle', '!=', '-1')])->first()) {
            throw new AlertException("每期活动只能发起一个邀请");
        }
        if (PairContactApply::where([array('activity_id', $enrollingActivity->stage_id), array('send_uid', $uid), array('receive_uid', $contactUid)])->first()) {
            throw new AlertException("你已经对TA发起过邀请");
        }
        if (!($pair = PairModel::where([array('uid', $uid), array('stage_id', $enrollingActivity->stage_id)])->first())) {
            throw new AlertException("你还没有参加本期活动");
        }
        if ($pair->assoc_id) {
            throw new AlertException("你已经有CP了");
        }
        if ($pair = PairModel::where([array('uid', $contactUid), array('stage_id', $enrollingActivity->stage_id)])->first() && $pair->assoc_id) {
            throw new AlertException("TA已经有CP了");
        }
        PairContactApply::create(['created_at' => time(), 'send_uid' => $uid, 'receive_uid' => $contactUid, 'activity_id' => $enrollingActivity->stage_id]);
    }
    /**
     * 已读的打招呼联系人列表
     * @param  GetReadSayHelloContactListMessage  $message
     */
    public function getReadSayHelloContactList(GetReadSayHelloContactListMessage $message)
    {
        $page = $message->getPage() ?? 1;
        $take = 20;
        $uid = Auth::auth();
        $lists = FriendContact::where([array('uid', $uid), array('friend_level', 0), array('unread_cnt', 0)])->with('user')->orderByDesc('last_at')->take($take)->skip(($page - 1) * $take)->get();
        $lists = array_values($lists->toArray());
        FriendContact::where('uid', $uid)->where('friend_level', 0)->update(['list_unread_msg_cnt' => 0]);
        $pages = array('total' => FriendContact::where([array('uid', $uid), array('friend_level', 0), array('unread_cnt', 0)])->count(), 'page' => $page, 'limit' => $take);
        $message->setResponse(PageDTO::initFromModel($pages), ListFriendDTO::initFromModels($lists));
    }
    /**
     * 未读的打招呼联系人列表
     * @param  GetUnReadSayHelloContactListMessage  $message
     */
    public function getUnReadSayHelloContactList(GetUnReadSayHelloContactListMessage $message)
    {
        $page = $message->getPage() ?? 1;
        $take = 20;
        $uid = Auth::auth();
        $lists = FriendContact::where([array('uid', $uid), array('friend_level', 0), array('unread_cnt', '>', 0)])->with('user')->orderByDesc('last_at')->take($take)->skip(($page - 1) * $take)->get();
        $lists = array_values($lists->toArray());
        FriendContact::where('uid', $uid)->where('friend_level', 0)->update(['list_unread_msg_cnt' => 0]);
        $pages = array('total' => FriendContact::where([array('uid', $uid), array('friend_level', 0), array('unread_cnt', '>', 0)])->count(), 'page' => $page, 'limit' => $take);
        $message->setResponse(PageDTO::initFromModel($pages), ListFriendDTO::initFromModels($lists));
    }
    /**
     * 获取联系人信息
     * @param  GetContactMessage  $message
     */
    public function getContact(GetContactMessage $message)
    {
        $uid = Auth::auth();
        $contactUid = $message->getContactUid();
        if ($list = FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->first()) {
            $friendLevel = $list->friend_level;
            $isBlackList = $list->is_blacklist;
            $starAt = $list->star_at;
            $user = $list->user->toArray();
        } else {
            $friendLevel = 0;
            $isBlackList = 0;
            $starAt = 0;
            $user = UserModel::find($contactUid)->toArray();
            $user['note'] = null;
        }
        if (FriendApply::where([array('uid', $contactUid), array('apply_uid', $uid), array('handle', 0)])->first()) {
            $isUnHandlerFriendApply = true;
        } else {
            $isUnHandlerFriendApply = false;
        }
        $message->setResponse($isUnHandlerFriendApply, $friendLevel, $isBlackList, $starAt, ContactUserDTO::initFromEloquent($user));
    }
    /**
     * 全部好友申请列表
     * @param  GetAllFriendAppliesMessage  $message
     */
    public function getAllFriendApplies(GetAllFriendAppliesMessage $message)
    {
        $page = $message->getPage() ?? 1;
        $take = 20;
        $uid = Auth::auth();
        $friendApplies = FriendApply::where('apply_uid', $uid)->orWhere('uid', $uid)->with('sendUser')->with('receiveUser')->orderByDesc('last_at')->take($take)->skip(($page - 1) * $take)->get()->toArray();
        array_walk($friendApplies, function (&$item) use ($uid) {
            if ($uid == Arr::get($item, 'uid')) {
                Arr::set($item, 'is_unread', Arr::get($item, 'send_unread'));
                Arr::set($item, 'user', Arr::get($item, 'receive_user'));
            } else {
                Arr::set($item, 'is_unread', Arr::get($item, 'receive_unread'));
                Arr::set($item, 'user', Arr::get($item, 'send_user'));
            }
            return $item;
        });
        $pages = array('total' => FriendApply::where('apply_uid', $uid)->orWhere('uid', $uid)->count(), 'page' => $page, 'limit' => $take);
        $message->setResponse(PageDTO::initFromModel($pages), ListFriendApplyDTO::initFromModels($friendApplies));
    }
    /**
     * 发出的好友申请列表
     * @param  GetSendFriendApplyListMessage  $message
     */
    public function getSendFriendApplyList(GetSendFriendApplyListMessage $message)
    {
        $page = $message->getPage() ?? 1;
        $take = 20;
        $uid = Auth::auth();
        $friendApplies = FriendApply::where('uid', $uid)->with('receiveUser')->orderByDesc('last_at')->take($take)->skip(($page - 1) * $take)->get()->toArray();
        array_walk($friendApplies, function (&$item) use ($uid) {
            Arr::set($item, 'is_unread', Arr::get($item, 'send_unread'));
            Arr::set($item, 'user', Arr::get($item, 'receive_user'));
            return $item;
        });
        $pages = array('total' => FriendApply::where('apply_uid', $uid)->orWhere('uid', $uid)->count(), 'page' => $page, 'limit' => $take);
        $message->setResponse(PageDTO::initFromModel($pages), ListFriendApplyDTO::initFromModels($friendApplies));
    }
    /**
     * 收到的好友申请列表
     * @param  GetReceiveFriendApplyListMessage  $message
     */
    public function getReceiveFriendApplyList(GetReceiveFriendApplyListMessage $message)
    {
        $page = $message->getPage() ?? 1;
        $take = 20;
        $uid = Auth::auth();
        $friendApplies = FriendApply::where([array('apply_uid', $uid)])->with('sendUser')->orderByDesc('last_at')->take($take)->skip(($page - 1) * $take)->get()->toArray();
        array_walk($friendApplies, function (&$item) use ($uid) {
            Arr::set($item, 'is_unread', Arr::get($item, 'receive_unread'));
            Arr::set($item, 'user', Arr::get($item, 'send_user'));
            return $item;
        });
        $pages = array('total' => FriendApply::where('apply_uid', $uid)->orWhere('uid', $uid)->count(), 'page' => $page, 'limit' => $take);
        $message->setResponse(PageDTO::initFromModel($pages), ListFriendApplyDTO::initFromModels($friendApplies));
    }
    /**
     * 好友申请消息概览
     * @param  FriendApplyMsgOverviewMessage  $message
     */
    public function friendApplyMsgOverview(FriendApplyMsgOverviewMessage $message)
    {
        $uid = Auth::auth();
        $sendUnRead = FriendApply::where([array('send_unread', 1), array('uid', $uid)])->count();
        $receiveUnRead = FriendApply::where([array('receive_unread', 1), array('apply_uid', $uid)])->count();
        $message->setResponse($sendUnRead + $receiveUnRead, $sendUnRead, $receiveUnRead);
    }
    public function changeContactNote(ChangeContactNoteMessage $message)
    {
        $uid = Auth::auth();
        $contactUid = $message->getContactUid();
        $note = $message->getNote();
        FriendContact::where([array('uid', $uid), array('friend_uid', $contactUid)])->update(['note' => $note]);
    }

    /**
     * 相互心动联系人列表
     * @param  GetEachLikeContactsMessage  $message
     */
    public function getEachLikeContacts(GetEachLikeContactsMessage $message)
    {
        $uid = Auth::auth();
        $lists = FriendContact::where([array('uid', $uid), array('each_like', 1)])->with('user')->orderByDesc('last_at')->get();
        $lists = array_values($lists->toArray());
        FriendContact::where('uid', $uid)->where('friend_level', 0)->update(['list_unread_msg_cnt' => 0]);
        $message->setResponse(ListFriendDTO::initFromEloquents($lists));
    }
}
