<?php
namespace Api\Core\RateLimiter;

class FileRateLimiter implements RateLimiterInterface {
    private $dir;
    private $requests;
    private $window;

    public function __construct(?string $storageDir, int $requests = 100, int $window = 60) {
        $this->dir = $storageDir ?? sys_get_temp_dir() . '/api_rate_limit';
        if (!is_dir($this->dir)) {
            mkdir($this->dir, 0700, true);
        }
        $this->requests = $requests;
        $this->window = $window;
    }

    private function fileForKey(string $key): string {
        return $this->dir . '/rl_' . md5($key) . '.json';
    }

    public function allow(string $key): bool {
        $file = $this->fileForKey($key);
        $now = time();

        $data = ['tokens' => $this->requests, 'last' => $now];
        if (file_exists($file)) {
            $fp = fopen($file, 'c+');
            if (!$fp) return true;
            flock($fp, LOCK_EX);
            $contents = stream_get_contents($fp);
            rewind($fp);
            $data = $contents ? json_decode($contents, true) : $data;

            // refill tokens
            $elapsed = $now - ($data['last'] ?? $now);
            $rate = $this->requests / $this->window;
            $refill = floor($elapsed * $rate);
            $data['tokens'] = min($this->requests, ($data['tokens'] ?? $this->requests) + $refill);
            $data['last'] = $now;

            if ($data['tokens'] > 0) {
                $data['tokens']--;
                ftruncate($fp, 0);
                fwrite($fp, json_encode($data));
                fflush($fp);
                flock($fp, LOCK_UN);
                fclose($fp);
                return true;
            } else {
                ftruncate($fp, 0);
                fwrite($fp, json_encode($data));
                fflush($fp);
                flock($fp, LOCK_UN);
                fclose($fp);
                return false;
            }
        } else {
            $fp = fopen($file, 'w');
            if (!$fp) return true;
            flock($fp, LOCK_EX);
            $data = ['tokens' => $this->requests - 1, 'last' => $now];
            fwrite($fp, json_encode($data));
            fflush($fp);
            flock($fp, LOCK_UN);
            fclose($fp);
            return true;
        }
    }

    public function getRetryAfter(string $key): int {
        $file = $this->fileForKey($key);
        if (!file_exists($file)) return 0;
        $data = json_decode(file_get_contents($file), true);
        $tokens = $data['tokens'] ?? 0;
        if ($tokens > 0) return 0;
        $last = $data['last'] ?? time();
        $elapsed = time() - $last;
        $remaining = max(0, $this->window - $elapsed);
        return $remaining;
    }
}
