<?php
namespace EasyChat\Library\Messenger;

use EasyChat\Library\SafeRuntime;
use PhpWA\Storage\AesGcmKeyringCipher;

 
final class WhatsAppPersonalAuthStore {
    private $root;
    private $cipher;

    public function __construct() {
        WhatsAppPersonalRuntime::requireAutoload();
        $this->root = WhatsAppPersonalRuntime::privateRoot() . DIRECTORY_SEPARATOR . 'auth';
        if (!is_dir($this->root) && !SafeRuntime::mkdir($this->root, 0700, true)) {
            throw new \RuntimeException('whatsapp_auth_store_unavailable');
        }
        if (!SafeRuntime::chmod($this->root, 0700) || SafeRuntime::permissions($this->root) !== 0700) {
            throw new \RuntimeException('whatsapp_auth_store_permissions_invalid');
        }
        $keys = WhatsAppPersonalRuntime::keys();
        $this->cipher = new AesGcmKeyringCipher('primary', ['primary' => $keys['storage']]);
    }

    public function save(int $channel_id, int $generation, string $attempt_id, string $qr, int $expires_at): void {
        $this->assertIdentity($channel_id, $generation, $attempt_id);
        if ($qr === '' || strlen($qr) > 8192 || $expires_at <= time()) {
            throw new \InvalidArgumentException('whatsapp_qr_payload_invalid');
        }
        $json = json_encode(['qr' => $qr, 'expires_at' => $expires_at], JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
        $envelope = $this->cipher->encrypt($this->context($channel_id, $generation, $attempt_id), (string)$json);
        $this->atomicWrite($this->path($channel_id, $generation, $attempt_id), $envelope);
    }

    public function load(int $channel_id, int $generation, string $attempt_id): array {
        $this->assertIdentity($channel_id, $generation, $attempt_id);
        $path = $this->path($channel_id, $generation, $attempt_id);
        if (!is_file($path) || is_link($path)) {
            return [];
        }
        $raw = SafeRuntime::call(function () use ($path) { return file_get_contents($path, false, null, 0, 16384); }, false);
        if (!is_string($raw) || $raw === '') {
            return [];
        }
        try {
            $plain = $this->cipher->decrypt($this->context($channel_id, $generation, $attempt_id), $raw);
            $data = json_decode($plain, true, 16, JSON_THROW_ON_ERROR);
        } catch (\Throwable $e) {
            return [];
        }
        if (!is_array($data) || (int)($data['expires_at'] ?? 0) <= time() || !is_string($data['qr'] ?? null)) {
            $this->delete($channel_id, $generation, $attempt_id);
            return [];
        }
        return ['qr' => (string)$data['qr'], 'expires_at' => (int)$data['expires_at']];
    }

    public function delete(int $channel_id, int $generation, string $attempt_id): void {
        if ($channel_id > 0 && $generation > 0 && preg_match('/^[a-f0-9]{24}$/D', $attempt_id) === 1) {
            SafeRuntime::unlink($this->path($channel_id, $generation, $attempt_id));
        }
    }

    private function assertIdentity(int $channel_id, int $generation, string $attempt_id): void {
        if ($channel_id <= 0 || $generation <= 0 || preg_match('/^[a-f0-9]{24}$/', $attempt_id) !== 1) {
            throw new \InvalidArgumentException('whatsapp_auth_attempt_invalid');
        }
    }

    private function path(int $channel_id, int $generation, string $attempt_id): string {
        return $this->root . DIRECTORY_SEPARATOR . 'qr-' . $channel_id . '-' . $generation . '-' . $attempt_id . '.enc';
    }

    private function context(int $channel_id, int $generation, string $attempt_id): string {
        return "easychat-whatsapp-qr\0{$channel_id}\0{$generation}\0{$attempt_id}";
    }

    private function atomicWrite(string $path, string $contents): void {
        $temp = $path . '.tmp.' . bin2hex(random_bytes(8));
        $previous = umask(0077);
        try {
            $handle = SafeRuntime::call(function () use ($temp) { return fopen($temp, 'xb'); }, false);
        } finally {
            umask($previous);
        }
        if (!is_resource($handle)) { throw new \RuntimeException('whatsapp_auth_store_write_failed'); }
        try {
            try {
                $written = 0;
                $length = strlen($contents);
                while ($written < $length) {
                    $chunk = fwrite($handle, substr($contents, $written));
                    if ($chunk === false || $chunk === 0) break;
                    $written += $chunk;
                }
                if ($written !== $length || !fflush($handle)) {
                    throw new \RuntimeException('whatsapp_auth_store_write_failed');
                }
            } finally {
                fclose($handle);
            }
        } catch (\Throwable $error) {
            SafeRuntime::unlink($temp);
            throw $error;
        }
        if (!SafeRuntime::chmod($temp, 0600)
            || SafeRuntime::permissions($temp) !== 0600
            || !SafeRuntime::rename($temp, $path)) {
            SafeRuntime::unlink($temp);
            throw new \RuntimeException('whatsapp_auth_store_publish_failed');
        }
    }
}
