<?php

namespace App\Support;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;

/**
 * Decides which database the request talks to.
 *
 * Aiven (mysql) is the source of truth. When it cannot be reached the app keeps
 * running against a local SQLite mirror, and every write made while offline is
 * recorded in sync_queue so it can be replayed once the cloud is back.
 *
 * The reachability check is cached for a few seconds: without it every page
 * would pay a failed TCP connect, and a flapping link would thrash between the
 * two connections mid-request.
 */
class DbRouter
{
    public const PRIMARY = 'mysql';

    public const FALLBACK = 'fallback';

    private const CACHE_KEY = 'db.primary-online';

    /** Resolved once per request so a mid-request failover cannot split writes. */
    protected static ?string $resolved = null;

    /** The connection this request should use. */
    public static function connection(): string
    {
        return static::$resolved ??= static::primaryOnline() ? static::PRIMARY : static::FALLBACK;
    }

    public static function isOffline(): bool
    {
        return static::connection() === static::FALLBACK;
    }

    /**
     * Is Aiven reachable? Cached briefly — see the class docblock.
     *
     * The cache store is deliberately the file driver: the default store may
     * itself be the database we are trying to test.
     */
    public static function primaryOnline(): bool
    {
        $ttl = (int) config('tracker.sync.health_ttl', 10);

        return (bool) Cache::store('file')->remember(self::CACHE_KEY, $ttl, function () {
            return static::ping();
        });
    }

    /** One real connection attempt, with no caching. */
    public static function ping(): bool
    {
        try {
            DB::connection(static::PRIMARY)->getPdo()->query('SELECT 1');

            return true;
        } catch (Throwable $e) {
            Log::warning('Primary database unreachable, using local mirror.', [
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /** Drops the cached verdict so the next call re-tests the connection. */
    public static function forget(): void
    {
        static::$resolved = null;
        Cache::store('file')->forget(self::CACHE_KEY);
    }

    /** Testing seam — pins the request to one connection. */
    public static function pretend(?string $connection): void
    {
        static::$resolved = $connection;
    }
}
