<?php

namespace App\Http\Controllers\Settings;

use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Models\User;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

class DepartmentController extends Controller
{
    public function index(Request $request): View
    {
        $currentUser = $request->user();
        $dealerId = $currentUser->dealer_id;

        $departments = Department::query()
            ->where('dealer_id', $dealerId)
            ->with(['users' => function ($q) {
                $q->with('roles')
                    ->orderBy('name')
                    ->orderBy('surname');
            }])
            ->orderBy('name')
            ->get();

        $deletedDepartments = Department::onlyTrashed()
            ->where('dealer_id', $dealerId)
            ->orderBy('name')
            ->get();

        return view('settings.departments.index', compact('departments', 'deletedDepartments'));
    }

    public function create(Request $request): View
    {
        return view('settings.departments.create');
    }

    public function store(Request $request): RedirectResponse
    {
        $currentUser = $request->user();
        $dealerId = $currentUser->dealer_id;

        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);

        $baseSlug = Str::slug($data['name']);
        $slug = $baseSlug;
        $i = 2;

        while (Department::query()
            ->where('dealer_id', $dealerId)
            ->where('slug', $slug)
            ->exists()
        ) {
            $slug = $baseSlug.'-'.$i;
            $i++;
        }

        $codeBase = 'DEPT-'.strtoupper(Str::slug($data['name'], '-'));
        $code = $codeBase;
        $suffix = 2;

        while (Department::query()
            ->where('dealer_id', $dealerId)
            ->where('code', $code)
            ->exists()
        ) {
            $code = $codeBase.'-'.$suffix;
            $suffix++;
        }

        Department::create([
            'dealer_id' => $dealerId,
            'name' => $data['name'],
            'slug' => $slug,
            'code' => $code,
            'is_system' => false,
        ]);

        return redirect()
            ->route('settings.departments.index')
            ->with('status', 'Department saved.');
    }

    public function edit(Request $request, int $department): View
    {
        $departmentModel = $this->findScopedDepartment($request->user(), $department);

        abort_if($departmentModel->is_system || $departmentModel->is_builtin, 403);

        return view('settings.departments.edit', compact('departmentModel'));
    }

    public function update(Request $request, int $department): RedirectResponse
    {
        $currentUser = $request->user();
        $departmentModel = $this->findScopedDepartment($currentUser, $department);

        abort_if($departmentModel->is_system || $departmentModel->is_builtin, 403);

        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);

        $departmentModel->name = $data['name'];

        if ($departmentModel->isDirty('name')) {
            $baseSlug = Str::slug($departmentModel->name);
            $slug = $baseSlug;
            $i = 2;

            while (Department::query()
                ->where('dealer_id', $departmentModel->dealer_id)
                ->where('slug', $slug)
                ->where('id', '!=', $departmentModel->id)
                ->exists()
            ) {
                $slug = $baseSlug.'-'.$i;
                $i++;
            }

            $departmentModel->slug = $slug;
        }

        $departmentModel->save();

        return redirect()
            ->route('settings.departments.index')
            ->with('status', 'Department updated.');
    }

    public function destroy(Request $request, int $department): RedirectResponse
    {
        $departmentModel = $this->findScopedDepartment($request->user(), $department);

        if ($departmentModel->is_system || $departmentModel->is_builtin || $departmentModel->name === 'System Administration') {
            return back()->withErrors(['delete' => 'This department is protected and cannot be deleted.']);
        }

        $userCount = User::query()
            ->where('department_id', $departmentModel->id)
            ->count();

        if ($userCount > 0) {
            return back()->withErrors(['delete' => 'Cannot delete a department that still has users assigned.']);
        }

        $departmentModel->delete();

        return redirect()
            ->route('settings.departments.index')
            ->with('status', 'Department deleted.');
    }

    public function restore(Request $request, int $department): RedirectResponse
    {
        $currentUser = $request->user();

        $query = Department::withTrashed();
        if (! $currentUser->hasSystemAdminRole()) {
            $query->where('dealer_id', $currentUser->dealer_id);
        }

        $departmentModel = $query->whereKey($department)->firstOrFail();

        if (! $departmentModel->trashed()) {
            return back()->with('status', 'Department is not deleted.');
        }

        $departmentModel->restore();

        return back()->with('status', 'Department restored.');
    }

    public function addMembers(Request $request, int $department): RedirectResponse
    {
        $departmentModel = $this->findScopedDepartment($request->user(), $department);

        $data = $request->validate([
            'user_ids' => ['required', 'array'],
            'user_ids.*' => ['integer'],
        ]);

        $userIds = $data['user_ids'] ?? [];
        if ($userIds === []) {
            return back()->with('status', 'No users selected.');
        }

        User::query()
            ->where('dealer_id', $departmentModel->dealer_id)
            ->whereIn('id', $userIds)
            ->update(['department_id' => $departmentModel->id]);

        return back()->with('status', 'Users added to department.');
    }

    public function removeMembers(Request $request, int $department): RedirectResponse
    {
        $departmentModel = $this->findScopedDepartment($request->user(), $department);

        $data = $request->validate([
            'user_ids' => ['required', 'array'],
            'user_ids.*' => ['integer'],
        ]);

        $userIds = $data['user_ids'] ?? [];
        if ($userIds === []) {
            return back()->with('status', 'No users selected.');
        }

        User::query()
            ->where('dealer_id', $departmentModel->dealer_id)
            ->where('department_id', $departmentModel->id)
            ->whereIn('id', $userIds)
            ->update(['department_id' => null]);

        return back()->with('status', 'Users removed from department.');
    }

    public function searchMembers(Request $request, int $department)
    {
        $departmentModel = $this->findScopedDepartment($request->user(), $department);
        $dealerId = $departmentModel->dealer_id;
        $q = trim((string) $request->query('q', ''));

        $query = User::query()
            ->where('dealer_id', $dealerId)
            ->where(function ($inner) use ($departmentModel) {
                $inner
                    ->whereNull('department_id')
                    ->orWhere('department_id', '!=', $departmentModel->id);
            });

        if ($q !== '') {
            $query->where(function ($inner) use ($q) {
                $inner
                    ->where('name', 'like', "%{$q}%")
                    ->orWhere('surname', 'like', "%{$q}%")
                    ->orWhere('email', 'like', "%{$q}%");
            });
        }

        $users = $query
            ->orderBy('name')
            ->orderBy('surname')
            ->limit(20)
            ->get(['id', 'name', 'surname', 'email']);

        return response()->json(
            $users->map(fn (User $user) => [
                'id' => $user->id,
                'name' => $user->name,
                'surname' => $user->surname,
                'email' => $user->email,
            ])
        );
    }

    protected function findScopedDepartment(User $currentUser, int $id): Department
    {
        $query = Department::query();

        if (!$currentUser->hasSystemAdminRole()) {
            $query->where('dealer_id', $currentUser->dealer_id);
        }

        return $query->whereKey($id)->firstOrFail();
    }
}

