<?php

namespace App\Livewire;

use App\Enums\UserRole;
use App\Models\Comment;
use App\Models\User;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class AdminUserSearch extends Component
{
    use WithPagination;

    #[Url(history: true)]
    public $search = '';

    #[Url(history: true)]
    public $discordId = '';

    #[Url(history: true)]
    public $email = '';

    #[Url(history: true)]
    public $roleFilter = [];

    #[Url(history: true)]
    public $sortField = 'created_at';

    #[Url(history: true)]
    public $sortDirection = 'desc';

    #[Url(history: true)]
    public $perPage = 20;

    public $selected = [];

    public $selectAll = false;

    public $selectPage = false;

    // Modal state
    public $showUserModal = false;

    public $modalUser = null;

    public $modalUserComments = [];

    protected $queryString = [
        'search' => ['except' => ''],
        'discordId' => ['except' => ''],
        'email' => ['except' => ''],
        'roleFilter' => ['except' => []],
        'sortField' => ['except' => 'created_at'],
        'sortDirection' => ['except' => 'desc'],
        'perPage' => ['except' => 20],
    ];

    protected $allowedSortFields = ['id', 'name', 'email', 'discord_id', 'created_at', 'updated_at'];

    protected $allowedPerPages = [10, 20, 50, 100];

    public function updatedPerPage(): void
    {
        $this->resetPage();
    }

    public function updatedPage(): void
    {
        $this->selectPage = false;
        $this->selected = [];
    }

    public function updatedSelectPage($value): void
    {
        if ($value) {
            $this->selected = $this->users->pluck('id')->map(fn ($id) => (string) $id)->toArray();
        } else {
            $this->selected = [];
        }
    }

    public function sortBy(string $field): void
    {
        if (! in_array($field, $this->allowedSortFields)) {
            return;
        }

        if ($this->sortField === $field) {
            $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
        } else {
            $this->sortField = $field;
            $this->sortDirection = 'asc';
        }
    }

    public function clearFilters(): void
    {
        $this->search = '';
        $this->discordId = '';
        $this->email = '';
        $this->roleFilter = [];
        $this->sortField = 'created_at';
        $this->sortDirection = 'desc';
        $this->perPage = 20;
        $this->resetPage();
    }

    public function viewUser(int $userId): void
    {
        $this->modalUser = User::find($userId);

        if ($this->modalUser) {
            $this->modalUserComments = $this->modalUser->comments()
                ->orderBy('created_at', 'desc')
                ->limit(10)
                ->get();
            $this->showUserModal = true;
        }
    }

    public function closeModal(): void
    {
        $this->showUserModal = false;
        $this->modalUser = null;
        $this->modalUserComments = [];
    }

    public function banUser(int $userId): void
    {
        $user = User::findOrFail($userId);
        $user->addRole(UserRole::BANNED);
        cache()->flush();
        $this->dispatch('notify', type: 'success', message: "{$user->name} has been banned.");

        if ($this->showUserModal && $this->modalUser?->id === $userId) {
            $this->modalUser->refresh();
        }
    }

    public function unbanUser(int $userId): void
    {
        $user = User::findOrFail($userId);
        $user->removeRole(UserRole::BANNED);
        cache()->flush();
        $this->dispatch('notify', type: 'success', message: "{$user->name} has been unbanned.");

        if ($this->showUserModal && $this->modalUser?->id === $userId) {
            $this->modalUser->refresh();
        }
    }

    public function grantModerator(int $userId): void
    {
        $user = User::findOrFail($userId);
        $user->addRole(UserRole::MODERATOR);
        cache()->flush();
        $this->dispatch('notify', type: 'success', message: "{$user->name} has been granted Moderator role.");

        if ($this->showUserModal && $this->modalUser?->id === $userId) {
            $this->modalUser->refresh();
        }
    }

    public function revokeModerator(int $userId): void
    {
        $user = User::findOrFail($userId);
        $user->removeRole(UserRole::MODERATOR);
        cache()->flush();
        $this->dispatch('notify', type: 'success', message: "Moderator role revoked from {$user->name}.");

        if ($this->showUserModal && $this->modalUser?->id === $userId) {
            $this->modalUser->refresh();
        }
    }

    public function deleteUserComments(int $userId): void
    {
        $user = User::findOrFail($userId);
        Comment::where('user_id', $user->id)->delete();
        cache()->flush();
        $this->dispatch('notify', type: 'success', message: "All comments from {$user->name} have been deleted.");

        if ($this->showUserModal && $this->modalUser?->id === $userId) {
            $this->modalUserComments = collect();
        }
    }

    public function bulkBan(): void
    {
        $count = 0;
        foreach ($this->selected as $userId) {
            $user = User::find($userId);
            if ($user && ! $user->hasRole(UserRole::BANNED)) {
                $user->addRole(UserRole::BANNED);
                $count++;
            }
        }
        cache()->flush();
        $this->selected = [];
        $this->selectPage = false;
        $this->dispatch('notify', type: 'success', message: "{$count} user(s) have been banned.");
    }

    public function bulkUnban(): void
    {
        $count = 0;
        foreach ($this->selected as $userId) {
            $user = User::find($userId);
            if ($user && $user->hasRole(UserRole::BANNED)) {
                $user->removeRole(UserRole::BANNED);
                $count++;
            }
        }
        cache()->flush();
        $this->selected = [];
        $this->selectPage = false;
        $this->dispatch('notify', type: 'success', message: "{$count} user(s) have been unbanned.");
    }

    public function bulkDeleteComments(): void
    {
        $count = 0;
        foreach ($this->selected as $userId) {
            $deleted = Comment::where('user_id', (int) $userId)->delete();
            if ($deleted > 0) {
                $count++;
            }
        }
        cache()->flush();
        $this->selected = [];
        $this->selectPage = false;
        $this->dispatch('notify', type: 'success', message: "Deleted comments from {$count} user(s).");
    }

    public function getUsersProperty()
    {
        return User::query()
            ->when($this->search !== '', fn ($query) => $query->where('name', 'like', '%'.$this->search.'%'))
            ->when($this->discordId !== '', fn ($query) => $query->where('discord_id', '=', $this->discordId))
            ->when($this->email !== '', fn ($query) => $query->where('email', 'like', '%'.$this->email.'%'))
            ->when(! empty($this->roleFilter), function ($query) {
                foreach ($this->roleFilter as $role) {
                    $query->whereJsonContains('roles', $role);
                }
            })
            ->orderBy($this->sortField, $this->sortDirection)
            ->paginate((int) $this->perPage);
    }

    public function render()
    {
        return view('livewire.admin-user-search', [
            'users' => $this->users,
        ]);
    }
}