<?php

namespace App\Services;

use App\Models\Attendance;
use App\Models\Location;
use App\Models\OfflineSyncLog;
use App\Models\User;
use Illuminate\Support\Str;

class AttendanceService
{
    protected QrCodeService $qr;

    public function __construct(QrCodeService $qr)
    {
        $this->qr = $qr;
    }

    /**
     * Record attendance after verifying QR payload.
     * Enforces time-window and duplicate-device rules.
     */
    public function recordScan(
        User   $user,
        string $encryptedPayload,
        string $deviceId,
        string $scanMode = 'online',
        ?float $latitude = null,
        ?float $longitude = null
    ): array {
        // 1. Verify QR
        $data = $this->qr->verifyPayload($encryptedPayload);

        // 2. Find location
        $location = Location::where('location_code', $data['loc'])->first();
        if (!$location) {
            return ['success' => false, 'message' => 'Unknown location in QR code.'];
        }

        // 3. Time-window check (prevent double scan within cooldown period)
        $cooldownMinutes = (int) env('SCAN_COOLDOWN_MINUTES', 15);
        $recentScan = Attendance::where('user_id', $user->id)
            ->where('location_id', $location->id)
            ->where('created_at', '>=', now()->subMinutes($cooldownMinutes))
            ->first();

        if ($recentScan) {
            return [
                'success' => false,
                'message' => "You already scanned attendance for this location within the last {$cooldownMinutes} minutes.",
            ];
        }

        // 4. Device consistency check — flag if user scanned from different device in same day
        $flagged = false;
        $flagReason = null;
        $differentDevice = Attendance::where('user_id', $user->id)
            ->whereDate('created_at', today())
            ->where('device_id', '!=', $deviceId)
            ->exists();

        if ($differentDevice) {
            $flagged = true;
            $flagReason = 'Multiple devices detected for same user on same day.';
        }

        // 5. Create record
        $attendance = Attendance::create([
            'user_id'       => $user->id,
            'role'          => $user->role,
            'location_id'   => $location->id,
            'session_token' => Str::uuid()->toString(),
            'device_id'     => $deviceId,
            'scan_mode'     => $scanMode,
            'latitude'      => $latitude,
            'longitude'     => $longitude,
            'is_flagged'    => $flagged,
            'flag_reason'   => $flagReason,
        ]);

        return [
            'success'    => true,
            'message'    => 'Attendance recorded successfully.',
            'attendance' => $attendance,
            'flagged'    => $flagged,
            'location'   => $location->name,
        ];
    }

    /**
     * Sync a batch of offline attendance records.
     * Returns per-record success/failure.
     */
    public function syncOfflineBatch(array $records, User $user): array
    {
        $results = [];

        foreach ($records as $record) {
            $tempId = $record['temp_id'] ?? Str::uuid();

            // Skip if already synced
            if (OfflineSyncLog::where('temp_id', $tempId)->where('sync_status', 'synced')->exists()) {
                $results[] = ['temp_id' => $tempId, 'status' => 'skipped', 'reason' => 'Already synced.'];
                continue;
            }

            try {
                $result = $this->recordScan(
                    $user,
                    $record['qr_payload'],
                    $record['device_id'] ?? 'offline-device',
                    'offline',
                    $record['latitude'] ?? null,
                    $record['longitude'] ?? null
                );

                $log = OfflineSyncLog::updateOrCreate(
                    ['temp_id' => $tempId],
                    [
                        'attendance_id' => $result['success'] ? $result['attendance']->id : null,
                        'sync_status'   => $result['success'] ? 'synced' : 'failed',
                        'raw_payload'   => json_encode($record),
                        'error_message' => $result['success'] ? null : $result['message'],
                        'synced_at'     => $result['success'] ? now() : null,
                    ]
                );

                $results[] = ['temp_id' => $tempId, 'status' => $result['success'] ? 'synced' : 'failed', 'reason' => $result['message']];
            } catch (\Exception $e) {
                OfflineSyncLog::updateOrCreate(
                    ['temp_id' => $tempId],
                    ['sync_status' => 'failed', 'raw_payload' => json_encode($record), 'error_message' => $e->getMessage()]
                );
                $results[] = ['temp_id' => $tempId, 'status' => 'failed', 'reason' => $e->getMessage()];
            }
        }

        return $results;
    }
}
