<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Enums\UserActions;
use App\Enums\UserTypes;
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
use App\Http\Controllers\Helpers\ResponseHelper;
use App\Models\User;
use Hypervel\Http\Request;
use Hypervel\Support\Facades\Auth;
use Hypervel\Support\Facades\Hash;
use Hypervel\Support\Facades\Redis;
use Hypervel\Support\Facades\Validator;

class UserController
{
    public function index(Request $request)
    {
        if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ListAllUsersAsParentforUserCreation)) {
            return ResponseHelper::returnUnauthorized();
        }

        $query = User::orderByDesc('id');

        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('mobile_number', 'like', "%{$search}%")
                  ->orWhere('username', 'like', "%{$search}%");
            });
        }

        if ($acctType = $request->input('acct_type')) $query->where('acct_type', $acctType);
        if ($request->input('active_only')) $query->where('active', true);

        $users = $query->paginate((int) $request->input('per_page', 25));

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

    public function show(Request $request)
    {
        $target = $request->input('target');
        $user = is_numeric($target)
            ? User::find($target)
            : User::where('hashkey', $target)->first();

        if (!$user) return ResponseHelper::returnError('User not found', 404);

        if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewUserInfo)) {
            return ResponseHelper::returnUnauthorized();
        }

        return response()->json(['success' => true, 'data' => $this->present($user)]);
    }

    public function store(Request $request)
    {
        if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::CreateUser)) {
            return ResponseHelper::returnUnauthorized();
        }

        $validator = Validator::make($request->all(), [
            'name'          => 'required|string|max:255',
            'mobile_number' => 'required|string|max:20|unique:users,mobile_number',
            'username'      => 'nullable|string|max:100|unique:users,username',
            'password'      => 'required|string|min:6',
            'acct_type'     => 'required|string',
            'parentuid'     => 'nullable|integer|exists:users,id',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $acctType = UserTypes::tryFrom($request->input('acct_type'));
        if (!$acctType) {
            return ResponseHelper::returnError('Invalid account type', 422);
        }

        $user = User::create([
            'name'          => $request->input('name'),
            'mobile_number' => $request->input('mobile_number'),
            'username'      => $request->input('username'),
            'password'      => Hash::make($request->input('password')),
            'acct_type'     => $acctType,
            'parentuid'     => $request->input('parentuid', Auth::id()),
            'hashkey'       => hash('sha256', uniqid((string) now(), true)),
            'active'        => true,
        ]);

        return response()->json(['success' => true, 'data' => $this->present($user), 'message' => 'User created']);
    }

    public function update(Request $request)
    {
        $target = $request->input('target');
        $user = User::where('hashkey', $target)->first();
        if (!$user) return ResponseHelper::returnError('User not found', 404);

        if (!UserPermissions::isActionPermitted($target, UserActions::ModifyUser)) {
            return ResponseHelper::returnUnauthorized();
        }

        $allowedFields = ['name', 'username', 'acct_type', 'nickname', 'fullname'];
        $data = $request->only($allowedFields);
        if (isset($data['acct_type'])) {
            $acctType = UserTypes::tryFrom($data['acct_type']);
            if (!$acctType) return ResponseHelper::returnError('Invalid account type', 422);
            $data['acct_type'] = $acctType;
        }

        $user->update($data);

        return response()->json(['success' => true, 'data' => $this->present($user), 'message' => 'User updated']);
    }

    public function setActive(Request $request)
    {
        $target = $request->input('target');
        $user = User::where('hashkey', $target)->first();
        if (!$user) return ResponseHelper::returnError('User not found', 404);

        $active = (bool) $request->input('active', true);
        $action = $active ? UserActions::SetActiveUser : UserActions::SetInActiveUser;

        if (!UserPermissions::isActionPermitted($target, $action)) {
            return ResponseHelper::returnUnauthorized();
        }

        $user->update(['active' => $active]);

        return response()->json(['success' => true, 'data' => $this->present($user)]);
    }

    public function changePassword(Request $request)
    {
        $target = $request->input('target');
        $user = User::where('hashkey', $target)->first();
        if (!$user) return ResponseHelper::returnError('User not found', 404);

        if (!UserPermissions::isActionPermitted($target, UserActions::ChangeUserPassword)) {
            return ResponseHelper::returnUnauthorized();
        }

        $validator = Validator::make($request->all(), [
            'password' => 'required|string|min:6',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
        }

        $user->update(['password' => Hash::make($request->input('password'))]);

        // Force logout all sessions for this user
        Redis::del("user_session:{$user->id}");

        return response()->json(['success' => true, 'message' => 'Password changed']);
    }

    public function forceLogout(Request $request)
    {
        $target = $request->input('target');
        $user = User::where('hashkey', $target)->first();
        if (!$user) return ResponseHelper::returnError('User not found', 404);

        if (!UserPermissions::isActionPermitted($target, UserActions::ForceLogoutUser)) {
            return ResponseHelper::returnUnauthorized();
        }

        Redis::del("user_session:{$user->id}");

        return response()->json(['success' => true, 'message' => 'User session cleared']);
    }

    public function accountTypes()
    {
        $types = collect(UserTypes::cases())->map(fn ($t) => [
            'value' => $t->value,
            'label' => ucwords(str_replace('_', ' ', $t->value)),
        ]);

        return response()->json(['success' => true, 'data' => $types]);
    }

    private function present(User $user): array
    {
        return [
            'id'            => $user->id,
            'hashkey'       => $user->hashkey,
            'name'          => $user->name,
            'fullname'      => $user->fullname,
            'nickname'      => $user->nickname,
            'username'      => $user->username,
            'mobile_number' => $user->mobile_number,
            'acct_type'     => $user->acct_type,
            'active'        => (bool) $user->active,
            'parentuid'     => $user->parentuid,
            'created_at'    => $user->created_at,
            'updated_at'    => $user->updated_at,
        ];
    }
}
