<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Enums\AuditEvent;
use App\Exports\AuditLogExport;
use App\Models\Asset;
use App\Models\AssetAssignment;
use App\Models\AssetCategory;
use App\Models\AssetWarranty;
use App\Models\AuditLog;
use App\Models\Employee;
use App\Models\Location;
use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Maatwebsite\Excel\Facades\Excel;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

/**
 * The compliance trail — read-only, filterable, exportable. Every action the
 * `Auditable` trait and the domain services record ends up here; nothing on
 * this screen ever writes to `audit_logs` itself, which is what makes it
 * safe to leave open to every signed-in user rather than master-only — see
 * architecture §11.
 */
class AuditLogController extends Controller
{
    /**
     * The `Auditable` models, in the order they appear in the Module filter.
     * `ImportBatch` is deliberately absent — it is not `Auditable`; a bulk
     * import records one summary `imported` event against nothing in
     * particular instead (see `ImportService`).
     *
     * @var array<class-string, string>
     */
    private const MODULES = [
        Asset::class => 'Asset',
        AssetAssignment::class => 'Assignment',
        AssetWarranty::class => 'Warranty',
        Employee::class => 'Employee',
        Team::class => 'Team',
        Location::class => 'Location',
        AssetCategory::class => 'Asset Category',
        User::class => 'User',
    ];

    public function index(Request $request): View
    {
        $filters = $this->filtersFrom($request);

        $logs = $this->filtered($filters)
            ->with('user')
            ->latest()
            ->paginate((int) setting('pagination_per_page', config('ams.pagination.per_page')))
            ->withQueryString();

        return view('audit.index', [
            'logs' => $logs,
            'filters' => $filters,
            'hasFilters' => collect($filters)->filter(fn (string $v): bool => $v !== '')->isNotEmpty(),
            'cards' => $this->cardCounts(),
            'moduleOptions' => self::MODULES,
            'eventOptions' => AuditEvent::options(),
            'userOptions' => User::query()->orderBy('name')->pluck('name', 'id')->all(),
        ]);
    }

    public function show(AuditLog $log): View
    {
        $log->loadMissing('user');

        return view('audit.show', ['log' => $log]);
    }

    public function export(Request $request): BinaryFileResponse
    {
        $filters = $this->filtersFrom($request);

        return Excel::download(
            new AuditLogExport($filters),
            'aumni-ams-audit-logs-'.now()->format('Y-m-d-His').'.xlsx',
        );
    }

    /**
     * @return array<string, string>
     */
    private function filtersFrom(Request $request): array
    {
        return [
            'search' => $request->string('search')->toString(),
            'user_id' => $request->string('user_id')->toString(),
            'module' => $request->string('module')->toString(),
            'event' => $request->string('event')->toString(),
            'date_from' => $request->string('date_from')->toString(),
            'date_to' => $request->string('date_to')->toString(),
        ];
    }

    /**
     * @param  array<string, string>  $filters
     * @return Builder<AuditLog>
     */
    private function filtered(array $filters): Builder
    {
        return AuditLog::query()
            ->when($filters['search'] !== '', fn (Builder $q) => $q->where('description', 'like', '%'.$filters['search'].'%'))
            ->when($filters['user_id'] !== '', fn (Builder $q) => $q->byUser((int) $filters['user_id']))
            ->when($filters['module'] !== '', fn (Builder $q) => $q->where('auditable_type', $filters['module']))
            ->when($filters['event'] !== '', fn (Builder $q) => $q->byEvent($filters['event']))
            ->betweenDates($filters['date_from'] !== '' ? $filters['date_from'] : null, $filters['date_to'] !== '' ? $filters['date_to'] : null);
    }

    /**
     * @return array{total: int, today: int, this_week: int, active_users: int}
     */
    private function cardCounts(): array
    {
        return [
            'total' => AuditLog::query()->count(),
            'today' => AuditLog::query()->whereDate('created_at', today())->count(),
            'this_week' => AuditLog::query()->where('created_at', '>=', now()->startOfWeek())->count(),
            'active_users' => AuditLog::query()
                ->whereNotNull('user_id')
                ->where('created_at', '>=', now()->subDays(30))
                ->distinct('user_id')
                ->count('user_id'),
        ];
    }
}
