<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\AddGroupMemberRequest;
use App\Http\Requests\StoreGroupRequest;
use App\Http\Requests\UpdateGroupMemberRequest;
use App\Http\Requests\UpdateGroupRequest;
use App\Http\Resources\GroupMemberResource;
use App\Http\Resources\GroupResource;
use App\Http\Resources\GroupRowResource;
use App\Models\Group;
use App\Models\Member;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class GroupController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $query = Group::visibleTo($request->user())
            ->with('branch:id,name,code')
            ->withCount('members')
            ->orderBy('name')
            ->limit(500);

        if ($request->query('scope') === 'organization') {
            $query->whereNull('branch_id');
        } elseif ($request->filled('branch_id')) {
            $query->where('branch_id', $request->integer('branch_id'));
        }

        if ($request->filled('type')) {
            $query->where('type', $request->string('type'));
        }

        if ($request->filled('q')) {
            $query->where('name', 'like', $request->string('q').'%');
        }

        $groups = $query->get();

        return GroupRowResource::collection($groups)->response();
    }

    public function store(StoreGroupRequest $request): JsonResponse
    {
        $group = Group::create($request->validated());

        return (new GroupResource($group->load('branch')))
            ->response()
            ->setStatusCode(201);
    }

    public function show(Group $group): GroupResource
    {
        $this->authorize('view', $group);

        $group->loadCount('members');
        $group->load(['branch', 'leaderMember']);

        return new GroupResource($group);
    }

    public function update(UpdateGroupRequest $request, Group $group): GroupResource
    {
        $group->update($request->validated());

        return new GroupResource($group->load(['branch', 'leaderMember'])->loadCount('members'));
    }

    public function destroy(Group $group): JsonResponse
    {
        $this->authorize('delete', $group);

        $group->delete();

        return response()->json(null, 204);
    }

    public function members(Group $group): JsonResponse
    {
        $this->authorize('view', $group);

        $members = $group->members()->orderBy('last_name')->orderBy('first_name')->cursorPaginate(25)->withQueryString();

        return GroupMemberResource::collection($members)->response();
    }

    public function addMember(AddGroupMemberRequest $request, Group $group): JsonResponse
    {
        $member = Member::visibleTo($request->user())->findOrFail($request->input('member_id'));

        $group->members()->syncWithoutDetaching([
            $member->id => [
                'role_in_group' => $request->input('role_in_group', 'member'),
                'joined_at' => now()->toDateString(),
            ],
        ]);

        return (new GroupMemberResource($group->members()->findOrFail($member->id)))
            ->response()
            ->setStatusCode(201);
    }

    public function updateMemberRole(UpdateGroupMemberRequest $request, Group $group, Member $member): GroupMemberResource
    {
        if (! $group->members()->where('members.id', $member->id)->exists()) {
            abort(404);
        }

        $group->members()->updateExistingPivot($member->id, [
            'role_in_group' => $request->input('role_in_group'),
        ]);

        return new GroupMemberResource($group->members()->findOrFail($member->id));
    }

    public function removeMember(Request $request, Group $group, Member $member): JsonResponse
    {
        $this->authorize('update', $group);

        $group->members()->detach($member->id);

        return response()->json(null, 204);
    }
}
