<?php

namespace App\Livewire\Admin;

use App\Domain\Audit\Models\AuditLog;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Livewire\Concerns\WithSorting;
use App\Livewire\Users\Concerns\FiltersUsersByBranch;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('سجل النشاطات')]
class ActivityLog extends Component
{
    use WithPagination, WithSorting, UsesBranchScope, FiltersUsersByBranch;

    #[Url]
    public string $search = '';

    #[Url]
    public string $actionFilter = '';

    #[Url]
    public string $dateFrom = '';

    #[Url]
    public string $dateTo = '';

    #[Url]
    public string $userFilter = '';

    #[Url]
    public string $entityFilter = '';

    #[Url]
    public string $referenceSearch = '';

    public int $expandedRow = 0;

    public function mount(): void
    {
        $this->authorize('audit.view');
    }

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

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

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

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

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

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

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

    public function toggleExpand(int $id): void
    {
        $this->expandedRow = $this->expandedRow === $id ? 0 : $id;
    }

    public function resetFilters(): void
    {
        $this->reset(['search', 'actionFilter', 'dateFrom', 'dateTo', 'userFilter', 'entityFilter', 'referenceSearch']);
        $this->resetPage();
    }

    /**
     * Translate auditable_type class name to Arabic.
     */
    public static function translateEntityType(string $type): string
    {
        $shortName = class_basename($type);

        $map = [
            'User' => 'مستخدم',
            'Academy' => 'أكاديمية',
            'Branch' => 'فرع',
            'Person' => 'شخص',
            'Participant' => 'مشارك',
            'Guardian' => 'ولي أمر',
            'Invoice' => 'فاتورة',
            'Payment' => 'دفعة',
            'Transaction' => 'معاملة مالية',
            'Enrollment' => 'تسجيل',
            'TrainingProgram' => 'برنامج تدريبي',
            'TrainingGroup' => 'مجموعة تدريبية',
            'TrainingSession' => 'حصة تدريبية',
            'Facility' => 'منشأة',
            'Product' => 'منتج',
            'Warehouse' => 'مستودع',
            'Role' => 'دور',
            'Activity' => 'نشاط',
            'Wallet' => 'محفظة',
            'CashSession' => 'وردية',
            'InventoryMovement' => 'حركة مخزون',
            'AttendanceRecord' => 'سجل حضور',
            'AuditLog' => 'سجل تدقيق',
        ];

        return $map[$shortName] ?? $shortName;
    }

    public function render()
    {
        // `audit_logs` is academy-level by design (rule 19, GLOBAL bucket): it
        // has no branch_id, so there is nothing here to filter on and the list
        // spans the academy. Narrowing it needs a stamped column, not a where —
        // see the note in the packet report.
        $query = AuditLog::query()
            ->with('user')
            ->when($this->search, function ($q) {
                $search = $this->search;
                $q->where(function ($q2) use ($search) {
                    $q2->where('auditable_type', 'ilike', "%{$search}%")
                       ->orWhere('ip_address', 'ilike', "%{$search}%")
                       ->orWhereHas('user', fn ($uq) => $uq->where('name', 'ilike', "%{$search}%")
                           ->orWhere('name_ar', 'ilike', "%{$search}%"));
                });
            })
            ->when($this->referenceSearch, function ($q) {
                $ref = $this->referenceSearch;
                $q->where(function ($q2) use ($ref) {
                    $q2->whereRaw("new_values::text ILIKE ?", ["%{$ref}%"])
                       ->orWhereRaw("old_values::text ILIKE ?", ["%{$ref}%"]);
                });
            })
            ->when($this->entityFilter, function ($q) {
                $entityMap = [
                    'invoice' => 'Invoice',
                    'payment' => 'Payment',
                    'transaction' => 'Transaction',
                    'enrollment' => 'Enrollment',
                    'participant' => 'Participant',
                    'session' => 'TrainingSession',
                    'group' => 'TrainingGroup',
                    'program' => 'TrainingProgram',
                    'user' => 'User',
                    'attendance' => 'AttendanceRecord',
                ];
                $entity = $entityMap[$this->entityFilter] ?? $this->entityFilter;
                $q->where('auditable_type', 'ilike', "%{$entity}%");
            })
            ->when($this->actionFilter, fn ($q) => $q->where('action', $this->actionFilter))
            ->when($this->dateFrom, fn ($q) => $q->whereDate('created_at', '>=', $this->dateFrom))
            ->when($this->dateTo, fn ($q) => $q->whereDate('created_at', '<=', $this->dateTo))
            ->when($this->userFilter, fn ($q) => $q->where('user_id', $this->userFilter))
            ->orderBy($this->sortBy, $this->sortDir);

        // The actor filter is a staff directory. `users` carries no BranchScope
        // and must not — BranchContext resolves the branch *from* the user — so
        // the branch predicate is written out through role_user by
        // FiltersUsersByBranch, the one place that rule lives.
        $users = $this->branchUsers()
            ->select('id', 'name', 'name_ar')
            ->orderBy('name_ar')
            ->get();

        return view('livewire.admin.activity-log', [
            'logs' => $query->paginate(25),
            'users' => $users,
        ]);
    }
}
