<?php

namespace Modules\SmartStorage\Entities\Services;

use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cookie;
use Modules\SmartStorage\Entities\SsDevice;

/**
 * Identifies the calling device via a persistent signed cookie and maintains the
 * ss_devices registry used by the "specific devices" and "this device only"
 * access sub-modes.
 *
 * The fingerprint is a random opaque token stored client-side; we keep only its
 * sha256 hash server-side. A brand-new device is recorded as unapproved so an
 * admin can approve it from the UI.
 */
class DeviceManager
{
    private const COOKIE = 'ss_device';
    private const COOKIE_DAYS = 3650;

    /** @var string|null per-request memo */
    protected $fingerprint;

    /**
     * Raw opaque device token for the current request (from cookie, or freshly
     * minted and queued onto the response).
     */
    public function token(): string
    {
        if ($this->fingerprint !== null) {
            return $this->fingerprint;
        }

        $request = request();
        $token = $request?->cookie(self::COOKIE);

        if (empty($token)) {
            $token = (string) Str::uuid();
            // Attached to the outgoing response by Laravel's cookie middleware.
            Cookie::queue(Cookie::make(self::COOKIE, $token, self::COOKIE_DAYS * 24 * 60));
        }

        return $this->fingerprint = $token;
    }

    public function fingerprintHash(): string
    {
        return hash('sha256', $this->token());
    }

    /**
     * Record/refresh the device row for the current request. Returns the model.
     */
    public function touch($businessId = null): SsDevice
    {
        $request = request();
        $hash = $this->fingerprintHash();

        $device = SsDevice::firstOrNew(['fingerprint_hash' => $hash]);
        if (!$device->exists) {
            $device->business_id = $businessId;
            $device->approved = false;
            $device->name = $this->guessName($request?->userAgent());
            $device->created_by = auth()->id();
        }
        $device->last_ip = $request?->ip();
        $device->last_user_agent = Str::limit((string) $request?->userAgent(), 250, '');
        $device->last_seen_at = now();
        try {
            $device->save();
        } catch (\Throwable $e) {
            // non-fatal
        }

        return $device;
    }

    public function isApproved(): bool
    {
        return SsDevice::where('fingerprint_hash', $this->fingerprintHash())
            ->where('approved', true)
            ->exists();
    }

    protected function guessName(?string $ua): string
    {
        $ua = (string) $ua;
        foreach (['Windows' => 'Windows', 'Macintosh' => 'Mac', 'Linux' => 'Linux', 'Android' => 'Android', 'iPhone' => 'iPhone', 'iPad' => 'iPad'] as $needle => $label) {
            if (str_contains($ua, $needle)) {
                return $label . ' device';
            }
        }
        return 'Unknown device';
    }
}
