<?php

namespace App\Services;

use App\Models\Coupon;

class CouponCodePool
{
    /** @var list<string>|null */
    private ?array $allCodesCache = null;

    public function __construct(
        private ?string $codesPath = null,
    ) {}

    /**
     * @return list<string>
     */
    public function allCodes(): array
    {
        if ($this->allCodesCache !== null) {
            return $this->allCodesCache;
        }

        $path = $this->codesPath ?? resource_path('codes/codes.txt');

        if (! is_readable($path)) {
            throw new \RuntimeException("Coupon codes file is not readable: {$path}");
        }

        $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

        if ($lines === false) {
            throw new \RuntimeException("Unable to read coupon codes file: {$path}");
        }

        $codes = array_values(array_filter(array_map(trim(...), $lines)));

        if ($codes === []) {
            throw new \RuntimeException("Coupon codes file is empty: {$path}");
        }

        return $this->allCodesCache = $codes;
    }

    /**
     * @return list<string>
     */
    public function usedCodes(): array
    {
        return Coupon::query()->pluck('code')->all();
    }

    /**
     * @return list<string>
     */
    public function availableCodes(): array
    {
        return array_values(array_diff($this->allCodes(), $this->usedCodes()));
    }

    public function hasAvailable(): bool
    {
        return $this->availableCodes() !== [];
    }

    public function pickRandom(): ?string
    {
        $available = $this->availableCodes();

        if ($available === []) {
            return null;
        }

        return $available[array_rand($available)];
    }
}
