<?php

namespace App\Repositories;

use App\Models\MemberAccessLog;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

class MemberAccessLogRepository extends BaseRepository
{
    public function __construct(MemberAccessLog $model)
    {
        parent::__construct($model);
    }

    public function alreadyEnteredToday(int $memberId): bool
    {
        return $this->model->newQuery()
            ->where('member_id', $memberId)
            ->whereDate('scanned_at', now()->toDateString())
            ->where('action', 'scan')
            ->where('result', 'granted')
            ->exists();
    }

    public function createGenerateLog(int $memberId, string $token): void
    {
        $this->model->newQuery()->create([
            'member_id'     => $memberId,
            'scanned_by_id' => null,
            'token'         => $token,
            'action'        => 'generate',
            'result'        => 'generated',
            'deny_reason'   => null,
            'scanned_at'    => now(),
        ]);
    }

    public function createScanLog(
        ?int $memberId,
        ?int $scannerId,
        string $token,
        string $result,
        ?string $denyReason = null,
        ?string $note = null
    ): int {
        $log = $this->model->newQuery()->create([
            'member_id'     => $memberId,
            'scanned_by_id' => $scannerId,
            'token'         => $token,
            'action'        => 'scan',
            'result'        => $result,
            'deny_reason'   => $denyReason,
            'note'          => $note,
            'scanned_at'    => now(),
        ]);

        return (int) $log->id;
    }

    public function attachNoteForScanner(
        int $scanId,
        int $securityId,
        ?string $note,
        bool $updateNoteField = true
    ): ?MemberAccessLog {
        $log = $this->model->newQuery()
            ->where('id', $scanId)
            ->where('scanned_by_id', $securityId)
            ->where('action', 'scan')
            ->first();

        if (! $log instanceof MemberAccessLog) {
            return null;
        }

        if ($updateNoteField) {
            $log->update(['note' => $note]);
            $log = $log->fresh();
        }

        return $log;
    }

    public function memberHistory(int $memberId, int $perPage = 20): LengthAwarePaginator
    {
        return $this->model->newQuery()
            ->where('member_id', $memberId)
            ->orderByDesc('scanned_at')
            ->paginate($perPage);
    }

    public function guardHistory(?int $memberId = null, int $perPage = 50): LengthAwarePaginator
    {
        return $this->model->newQuery()
            ->when($memberId, fn ($q) => $q->where('member_id', $memberId))
            ->with(['member:id,name,phone,member_type', 'scannedBy:id,name'])
            ->orderByDesc('scanned_at')
            ->paginate($perPage);
    }

    /**
     * This security user's member QR scan rows today (all members), granted and denied.
     *
     * @return array{total_count: int, scans: list<array{id: int, scanned_at: string|null}>}
     */
    public function scannerMemberScanSummary(int $scannerId, int $limit = 100): array
    {
        $today = now()->toDateString();

        $baseQuery = fn () => $this->model->newQuery()
            ->where('scanned_by_id', $scannerId)
            ->where('action', 'scan')
            ->whereDate('scanned_at', $today);

        $totalCount = (int) $baseQuery()->count();

        $rows = $baseQuery()
            ->orderByDesc('scanned_at')
            ->orderByDesc('id')
            ->limit($limit)
            ->get(['id', 'scanned_at']);

        $scans = $rows->map(fn (MemberAccessLog $log) => [
            'id'         => $log->id,
            'scanned_at' => $log->scanned_at?->toIso8601String(),
        ])->values()->all();

        return [
            'total_count' => $totalCount,
            'scans'       => $scans,
        ];
    }

    /**
     * All member QR scan logs for this member today (granted or denied), any security scanner.
     *
     * @return array{total_count: int, scans: list<array{id: int, scanned_at: string|null}>}
     */
    public function memberScanSummaryToday(int $memberId, int $limit = 100): array
    {
        $today = now()->toDateString();

        $baseQuery = fn () => $this->model->newQuery()
            ->where('member_id', $memberId)
            ->where('action', 'scan')
            ->whereDate('scanned_at', $today);

        $totalCount = (int) $baseQuery()->count();

        $rows = $baseQuery()
            ->orderByDesc('scanned_at')
            ->orderByDesc('id')
            ->limit($limit)
            ->get(['id', 'scanned_at']);

        $scans = $rows->map(fn (MemberAccessLog $log) => [
            'id'         => $log->id,
            'scanned_at' => $log->scanned_at?->toIso8601String(),
        ])->values()->all();

        return [
            'total_count' => $totalCount,
            'scans'       => $scans,
        ];
    }
}

