<?php

namespace Modules\Chat\Http\Controllers;

use App\Events\GroupChatEvent;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Traits\ImageStore;
use Brian2694\Toastr\Facades\Toastr;
use Exception;
use Illuminate\Http\Request;
 use Modules\Chat\Entities\Conversation;
use Modules\Chat\Entities\Group;
use Modules\Chat\Entities\GroupMessageRecipient;
use Modules\Chat\Entities\GroupUser;
use Modules\Chat\Notifications\GroupCreationNotification;
use Modules\Chat\Notifications\GroupMessageNotification;
use Modules\Chat\Services\ConversationService;
use Modules\Chat\Services\GroupService;
use Modules\Chat\Services\InvitationService;
use Validator;

class GroupChatController extends Controller
{
    use ImageStore;

    public $invitationService;
    public $groupService;
    public $conversationService;


    public function __construct(InvitationService $invitationService, GroupService $groupService, ConversationService $conversationService)
    {
        $this->invitationService = $invitationService;
        $this->groupService = $groupService;
        $this->conversationService = $conversationService;
    }

    public function index($id=null, $notification_id=null)
    {

    }

    public function store(Request $request)
    {
         if (demoCheck()) {
            return redirect()->back();
        }
$rules= [
    'name' => 'required',
    'users' => 'required',
];
        $this->validate($request, $rules, validationMessage($rules));


        if ($request->hasFile('group_photo')){
            $request['photo_url'] = $this->saveImage($request->group_photo);
        }else{
            $request['photo_url'] ='public/chat/images/bw-spondon-icon.png';
        }

        $group = Group::create($request->except('_token'));

        GroupUser::create([
            'group_id' => $group->id,
            'user_id' => auth()->id(),
            'added_by' => auth()->id()
        ]);

        foreach ($request->users as $user){
            GroupUser::create([
                'group_id' => $group->id,
                'user_id' => $user,
                'added_by' => auth()->id(),
                'role' => 3
            ]);
            User::find($user)->notify(new GroupCreationNotification($group));
        }

        Toastr::success(trans('common.Operation successful'), trans('common.Success'));
        return redirect()->route('chat.index');
    }

    public function create()
    {
        $myGroups = $this->groupService->getAllGroup();
        $users = $this->invitationService->getAllConnectedUsers();
        return view('chat::group.create', compact('users','myGroups'));
    }

    public function show(Group $group)
    {
        if(!$group->users->contains('id', auth()->id())){
            Toastr::error(trans('common.Operation failed'), trans('common.Failed'));
            return redirect()->back();
        }

        $myGroups = $this->groupService->getAllGroup();
        $users = $this->invitationService->getAllConnectedUsers();
        $remainingUsers = $users->filter(function($value, $key) use($users,$group){
            return !in_array($value->id, array_merge($group->users->pluck('id')->toArray(),[auth()->id()]));
        });

        $this->conversationService->readAllNotificationGroup($group->id);

        $group->load([
            'threads' => function($query){
                $query->latest();
                $query->take(20);
            },
            'threads.conversation.reply',
            'threads.conversation.forwardFrom',
            'threads.removeMessages.user',
            'threads.user.activeStatus', 'users'
        ]);


        foreach ($group->threads as $thread) {
            $thread->removedByMe = $thread->removeMessages->contains('user_id', auth()->id());
        }

        $only_threads = GroupMessageRecipient::with('conversation.reply','conversation.forwardFrom','removeMessages.user','user.activeStatus')
            ->where('group_id', $group->id)
            ->whereDoesntHave('removeMessages')
            ->get();
          $single_threads = $only_threads->sortByDesc('created_at')->take(20)->toArray();

        $myRole = GroupUser::where('user_id', auth()->id())->where('group_id', $group->id)->first()->role;

        return view('chat::group.show', compact('group','users','myGroups', 'remainingUsers', 'myRole','single_threads'));
    }

    public function edit($id)
    {
        return view('chat::edit');
    }

    public function destroy(Request $request)
    {
        if (demoCheck()) {
            return redirect()->back();
        }
        Group::find($request->group_id);

        $relatedGroup = GroupUser::where('group_id', $request->group_id)
            ->where('user_id', auth()->id())
            ->first();

        if ($relatedGroup->role != 1){
            return response()->json(['notPermitted' => true]);
        }

        GroupUser::where('group_id', $request->group_id)->delete();
        $relatedGroup->delete();
        return response()->json(['notPermitted' => false, 'url' => route('chat.index')]);
    }

    public function send(Request $request)
    {
         try {

            if ($request->message == null && $request->file_attach == 'null'){
                return response()->json([
                    'empty' => true
                ]);
            }

            $img_name = null;
            $original_name = null;
            $type = 0;

            if ($request->reply && ($request->reply == 'null' || $request->reply == null)){
                $request->reply = null;
            }else{
                $request->reply = (int) $request->reply;
            }

            if ($request->hasFile('file_attach')){
                $extension = $request->file('file_attach')->extension();
                if ($extension == 'png' || $extension == 'jpg' || $extension == 'jpeg'){
                    $img_name = $this->saveImage($request->file('file_attach'));
                } else{
                    $img_name = $this->saveFile($request->file('file_attach'));
                }
                $original_name = $request->file('file_attach')->getClientOriginalName();

                if ($extension == 'png' || $extension == 'jpg' || $extension == 'jpeg'){
                    $type = 1;
                }elseif($extension == 'pdf'){
                    $type = 2;
                }elseif($extension == 'doc' || $extension == 'docx'){
                    $type = 3;
                }elseif($extension == 'webm'){
                    $type = 4;
                }elseif (in_array($extension, ['mp4','3gp','mkv'])){
                    $type = 5;
                } else{
                    $type = 0;
                }
            }

            $message = Conversation::create([
                'message' => $request->message,
                'file_name' => $img_name,
                'original_file_name' => $original_name,
                'message_type' => $type,
                'reply' => $request->reply,
            ])->load('reply');

            $group = Group::find($request->group_id);

            $thread = GroupMessageRecipient::create([
                'user_id' => $request->user_id,
                'conversation_id' => $message->id,
                'group_id' => $group->id
            ]);

             foreach ($group->users as $user){
                if($user->id != auth()->id()){
                    $user->notify(new GroupMessageNotification($group));
                }
            }

             $authData = (object) collect([
                 'id' => auth()->id(),
                 'name' => auth()->user()->name
             ])->toArray();;
             $groupData = (object)collect($group)->only(['id', 'name'])->toArray();;
             $threadData =(object) collect($thread)->only(['id', 'user_id', 'conversation_id', 'group_id'])->toArray();;
             $messageData = (object)collect($message)->only('id', 'message', 'file_name', 'original_file_name', 'message_type')->toArray();;
              broadcast(new GroupChatEvent($groupData, $threadData, $messageData, $authData))->toOthers();
            $group->load('threads.conversation.reply', 'threads.user');
            return ['status' => 'success','thread' => $thread->load('conversation.reply','user','group')];

        }catch (Exception $e){
            return $e->getMessage();
        }

    }

    public function addPeople(Request $request)
    {
        $group = Group::find($request->group_id);
        GroupUser::create([
            'group_id' => $group->id,
            'user_id' => $request->user_id,
            'added_by' => auth()->id(),
        ]);
        User::find($request->user_id)->notify(new GroupCreationNotification($group));

        return true;
    }

    public function removePeople(Request $request)
    {
      $remove =  GroupUser::where('user_id', $request->user_id)
            ->where('group_id', $request->group_id)
            ->first()
            ->delete();
        if ($remove) {
            // Return a success response with a URL or message
            return response()->json([
                'success' => true,
                'message' => 'User removed successfully.',
                'url' => route('chat.index')
            ]);
        }

        // Return an error response if the record was not found
        return response()->json([
            'success' => false,
            'message' => 'Record not found.'
        ], 404);
    }

    public function LeaveGroup(Request $request)
    {
        GroupUser::where('user_id', $request->user_id)
            ->where('group_id', $request->group_id)
            ->first()
            ->delete();
        return response()->json(['notPermitted' => false, 'url' => route('chat.index')]);
    }

    public function assignRole(Request $request)
    {
        $currentUser = GroupUser::where('user_id', auth()->id())->where('group_id', $request->group_id)->first();
        if ($currentUser->role != 1){
            return response()->json(['notPermitted' => true]);
        }
        $group = GroupUser::where('user_id', $request->user_id)
            ->where('group_id', $request->group_id)
            ->first();
        $group->update([
            'role' => $request->role_id
        ]);

        return response()->json(['notPermitted' => false]);

    }

    public function update(Request $request, $id)
    {
        //
    }

    public function readOnly(Request $request)
    {
        $group = Group::find($request->group_id);

        $permitted = GroupUser::where('group_id', $group->id)
            ->where('user_id', auth()->id())
            ->where('role', 1)
            ->first();

        if ($permitted){
            $group->update([
                'read_only' => $request->type == 'unmark' ? 0 : 1
            ]);
            return response()->json(['notPermitted' => false, 'url' => url()->previous()]);
        }

        return response()->json(['notPermitted' => true]);

    }

    public function download($id, Group $group)
    {

        $conversation = Conversation::find($id);
         if (!$group->users->contains('id', auth()->id())){
            Toastr::error(trans('common.Operation failed'), trans('common.Failed'));
            return redirect()->back();
        }

        if (file_exists(base_path($conversation->file_name))) {
            return response()->download(base_path($conversation->file_name));
        } else {
            Toastr::error(trans('common.File Not Found'), trans('common.Failed'));
            return redirect()->back();
         }

    }

    public function newMessageCheck (Request $request)
    {
        $rules =[
            'group_id' => 'required',
            'last_thread_id' => 'required',
        ];

        $validation = Validator::make($request->all(),$rules,validationMessage($rules) );

        if ($validation->fails()){
            return response()->json([
                'invalid' => true,
            ]);
        }

        $group = Group::findOrFail($request->group_id);
        $group->load('threads.conversation.reply', 'threads.user', 'users');

        if(!$group->users->contains('id', auth()->id())){
            return response()->json([
                'invalid' => true,
            ]);
        }


        $messages = $group->threads->where('id', '>', $request->last_thread_id);
        return response()->json([
            'invalid' => false,
            'messages' => $messages
        ]);
    }

    public function forward(Request $request)
    {
        try {
            $message = Conversation::create([
                'message' => $request->message,
                'file_name' => $request->file_name,
                'original_file_name' => $request->original_file_name,
                'message_type' => 0,
                'forward' => $request->forward,
                'reply' => is_array($request->reply) ? $request->reply['id'] : $request->reply,
            ])->load('reply','forwardFrom');

            $group = Group::find($request->group_id);

            $thread = GroupMessageRecipient::create([
                'user_id' => $request->user_id,
                'conversation_id' => $message->id,
                'group_id' => $group->id
            ]);

            foreach ($group->users as $user){
                if($user->id != auth()->id()){
                    User::find($user->id)->notify(new GroupMessageNotification($group));
                }
            }
            $authData = (object) collect([
                'id' => auth()->id(),
                'name' => auth()->user()->name
            ])->toArray();;
            $groupData = (object)collect($group)->only(['id', 'name'])->toArray();;
            $threadData =(object) collect($thread)->only(['id', 'user_id', 'conversation_id', 'group_id'])->toArray();;
            $messageData = (object)collect($message)->only('id', 'message', 'file_name', 'original_file_name', 'message_type')->toArray();;
            broadcast(new GroupChatEvent($groupData, $threadData, $messageData, $authData))->toOthers();
            $group->load('threads.conversation.reply','threads.conversation.forwardFrom', 'threads.user');
            return ['status' => 'success','thread' => $thread->load('conversation.reply','conversation.forwardFrom','user','group')];

        }catch (Exception $e){
            return $e->getMessage();
        }
    }

    public function removeMessage(Request $request)
    {
        $rules =[
            'thread_id' => 'required',
        ];
        $validation = Validator::make($request->all(),$rules,validationMessage($rules) );

        if ($validation->fails()){
            return response()->json([
                'success' => false,
                'message' => $validation->messages()
            ]);
        }

        try {
            if ($this->conversationService->groupMessageDelete($request->all())){
                return response()->json([
                    'success' => true
                ]);
            }
        }catch (Exception $e){
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ]);
        }
    }

    public function loadMore(Request $request)
    {
        $rules =[
            'ids' => 'required',
            'group_id' => 'required',
        ];
        $validation = Validator::make($request->all(),$rules,validationMessage($rules) );

        if ($validation->fails()){
            return response()->json([
                'success' => false
            ]);
        }

        $group = Group::find($request->group_id)->load('threads');

        $group->load(
            'threads.conversation.reply',
            'threads.conversation.forwardFrom',
            'threads.removeMessages.user',
            'threads.user', 'users'
        );

        foreach ($group->threads as $thread){
            $contain = $thread->removeMessages->contains('user_id', auth()->id());
            if ($contain){
                $thread->removedByMe = true;
            }
        }
        $ids = $request->ids;
        $newThreads = $group->threads->filter(function($value, $key) use ($ids){
            return !in_array($value->id, json_decode($ids));
        })->take(20);

        $newThreads->load(
            'conversation.reply',
            'conversation.forwardFrom',
            'removeMessages.user',
            'user',
        );


        if ($newThreads->isEmpty()){
            $newThreads = null;
        }

        return response()->json([
            'success' => true,
            'threads' => $newThreads
        ]);

    }
}
