<?php

namespace App\Services;

use App\Enums\ParkingStatusEnum;
use App\Enums\QrCodeStatusEnum;
use App\Models\Member;
use App\Models\Parking;
use App\Models\QrCode;
use App\Models\QrSetting;
use App\Models\MemberQrToken;
use App\Models\Security;
use App\Models\VisitorManagement;

class QrCodeService extends BaseService
{
    public function __construct(
        protected MemberQrAccessService $memberQrAccessService
    ) {}

    public function generate(VisitorManagement $creator, array $data): QrCode
    {
        if (empty($data['expires_at'])) {

            $minutes = QrSetting::where('key', 'qr_validity_minutes')
                ->active()
                ->value('value');

            $minutes = $minutes ? (int) $minutes : 60;

            $data['expires_at'] = now()->addMinutes($minutes);
        }

        $data['created_by_id'] = $creator->id;

        return $this->transaction(function () use ($data) {
            return QrCode::create($data);
        });
    }


    public function scan(string $code, Security $scanner): array
    {
        $qrCode = QrCode::where('code', $code)->first();

        if (! $qrCode) {
            // Member entry: ephemeral token, membership qr_code, or optional qr_code_static (when static entry enabled).
            $trim = trim($code);
            $tokenKey = strtoupper($trim);
            $isMemberEphemeral = MemberQrToken::query()->where('token', $tokenKey)->exists();
            $isMemberStatic = Member::query()
                ->where(function ($q) use ($tokenKey) {
                    $q->whereNotNull('qr_code')
                        ->whereRaw('UPPER(TRIM(qr_code)) = ?', [$tokenKey])
                        ->orWhere(function ($q2) use ($tokenKey) {
                            $q2->where('static_entry_qr_enabled', true)
                                ->whereNotNull('qr_code_static')
                                ->whereRaw('UPPER(TRIM(qr_code_static)) = ?', [$tokenKey]);
                        });
                })
                ->exists();

            $isParkingGate = Parking::query()
                ->whereNotNull('qr_code')
                ->whereRaw('UPPER(TRIM(qr_code)) = ?', [$tokenKey])
                ->where('status', ParkingStatusEnum::ACTIVE->value)
                ->exists();

            if ($isMemberEphemeral || $isMemberStatic || $isParkingGate) {
                $memberResult = $this->memberQrAccessService->validateScan($code, $scanner);
                $historyMemberId = isset($memberResult['member']['id'])
                    ? (int) $memberResult['member']['id']
                    : null;
                // This member’s scan count today (any gate; granted + denied) — not other members.
                $scanHistory = $historyMemberId !== null
                    ? $this->memberQrAccessService->buildScannerMemberScanHistoryPayload($scanner, 100, $historyMemberId)
                    : $this->memberQrAccessService->emptyMemberScanHistoryPayload();
                $primaryMessage = $memberResult['message'] ?? __('dashboard.qr_invalid');

                return [
                    'valid'    => (bool) ($memberResult['granted'] ?? false),
                    'status'   => $memberResult['status'] ?? 'INVALID',
                    'message'  => trim($primaryMessage . ' ' . $scanHistory['message']),
                    'type'     => 'member',
                    'member'   => $memberResult['member'] ?? null,
                    'reason'   => $memberResult['reason'] ?? null,
                    'scan_id'  => $memberResult['scan_id'] ?? null,
                    'scanner_scan_history' => $scanHistory,
                ];
            }

            return [
                'valid'    => false,
                'status'   => 'INVALID',
                'message'  => __('dashboard.qr_invalid'),
                'type'     => 'none',
                'member'   => null,
                'scan_id'  => null,
            ];
        }

        if ($qrCode->status === QrCodeStatusEnum::USED->value) {
            return [
                'valid'    => false,
                'status'   => 'USED',
                'message'  => __('dashboard.qr_already_used'),
                'type'     => 'visitor',
                'member'   => null,
                'scan_id'  => null,
                'visitor'  => [
                    'name'        => $qrCode->name,
                    'phone'       => $qrCode->phone,
                    'code'        => $qrCode->code,
                    'car_number'  => $qrCode->car_number,
                ],
            ];
        }

        if ($qrCode->status === QrCodeStatusEnum::EXPIRED->value || $qrCode->isExpired()) {
            if ($qrCode->status !== QrCodeStatusEnum::EXPIRED->value) {
                $qrCode->update(['status' => QrCodeStatusEnum::EXPIRED->value]);
            }

            return [
                'valid'    => false,
                'status'   => 'EXPIRED',
                'message'  => __('dashboard.qr_expired'),
                'type'     => 'visitor',
                'member'   => null,
                'scan_id'  => null,
                'visitor'  => [
                    'name'        => $qrCode->name,
                    'phone'       => $qrCode->phone,
                    'code'        => $qrCode->code,
                    'car_number'  => $qrCode->car_number,
                ],
            ];
        }

        $qrCode->update([
            'status'     => QrCodeStatusEnum::USED->value,
            'used_at'    => now(),
            'used_by_id' => $scanner->id,
        ]);

        return [
            'phone'        => $qrCode->phone,
            'name'         => $qrCode->name,
            'code'         => $qrCode->code,
            'car_number'   => $qrCode->car_number,
            'visitor'      => [
                'name'        => $qrCode->name,
                'phone'       => $qrCode->phone,
                'code'        => $qrCode->code,
                'car_number'  => $qrCode->car_number,
            ],
            'type'         => 'visitor',
            'member'       => null,
            'valid'        => true,
            'status'       => 'VALID',
            'message'      => __('dashboard.qr_valid'),
            'scan_id'      => null,
        ];
    }

    public function expireOverdue(): int
    {
        return QrCode::where('status', QrCodeStatusEnum::ACTIVE->value)
            ->where('expires_at', '<', now())
            ->update(['status' => QrCodeStatusEnum::EXPIRED->value]);
    }
}
