<?php

namespace Maestro\Core\Http\Controllers;

use Maestro\Core\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class UserManagementController extends Controller
{
    private function scopedQuery(Request $request): Builder
    {
        $organizationId = $request->user()->organization_id;
        abort_if(! $organizationId, 403);

        return User::query()->where('organization_id', $organizationId)->with(['roles:id,name']);
    }

    public function index(Request $request): JsonResponse
    {
        abort_unless($request->user()?->can('users.view'), 403);

        $users = $this->scopedQuery($request)
            ->orderBy('name')
            ->get()
            ->map(fn (User $user) => $this->userPayload($user));

        return response()->json(['data' => $users]);
    }

    public function store(Request $request): JsonResponse
    {
        abort_unless($request->user()?->can('users.create'), 403);

        $organizationId = $request->user()->organization_id;
        abort_if(! $organizationId, 403);

        $validator = Validator::make($request->all(), [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'max:255', 'unique:users,email'],
            'password' => ['required', 'string', 'min:8'],
            'is_active' => ['boolean'],
            'roles' => ['nullable', 'array'],
            'roles.*' => ['string', 'exists:roles,name'],
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed.',
                'errors' => $validator->errors(),
            ], 422);
        }

        $user = User::create([
            'name' => $request->input('name'),
            'email' => $request->input('email'),
            'organization_id' => $organizationId,
            'password' => Hash::make($request->input('password')),
            'is_active' => $request->boolean('is_active', true),
        ]);

        if ($request->filled('roles') && $request->user()->can('users.assign-roles')) {
            $user->syncRoles($request->input('roles'));
        }

        return response()->json([
            'data' => $this->userPayload($user->fresh('roles:id,name')),
        ], 201);
    }

    public function update(Request $request, User $user): JsonResponse
    {
        abort_unless($request->user()?->can('users.edit'), 403);

        abort_unless(
            $user->organization_id === $request->user()->organization_id,
            404,
        );

        $validator = Validator::make($request->all(), [
            'name' => ['sometimes', 'string', 'max:255'],
            'email' => ['sometimes', 'email', 'max:255', 'unique:users,email,'.$user->id],
            'password' => ['nullable', 'string', 'min:8'],
            'is_active' => ['boolean'],
            'roles' => ['nullable', 'array'],
            'roles.*' => ['string', 'exists:roles,name'],
        ]);

        if ($validator->fails()) {
            return response()->json([
                'message' => 'Validation failed.',
                'errors' => $validator->errors(),
            ], 422);
        }

        $data = $request->only(['name', 'email']);
        if ($request->has('is_active')) {
            $data['is_active'] = $request->boolean('is_active');
        }
        if ($request->filled('password')) {
            $data['password'] = Hash::make($request->input('password'));
        }

        if ($data !== []) {
            $user->update($data);
        }

        if ($request->has('roles') && $request->user()->can('users.assign-roles')) {
            $user->syncRoles($request->input('roles', []));
        }

        return response()->json([
            'data' => $this->userPayload($user->fresh('roles:id,name')),
        ]);
    }

    public function destroy(Request $request, User $user): JsonResponse
    {
        abort_unless($request->user()?->can('users.delete'), 403);
        abort_unless(
            $user->organization_id === $request->user()->organization_id,
            404,
        );
        abort_if($user->id === $request->user()->id, 422, 'You cannot delete your own account.');

        $user->delete();

        return response()->json(['message' => 'Deleted.']);
    }

    /**
     * @return array<string, mixed>
     */
    private function userPayload(User $user): array
    {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'is_active' => (bool) ($user->is_active ?? true),
            'roles' => $user->roles->pluck('name')->values()->all(),
        ];
    }
}
