<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

/**
 * Cloud-disk credential + status row. One row per provider key; at most one
 * carries status='enabled' (the active disk). `auth_keys` is encrypted at
 * rest via the `encrypted:array` cast — admins paste API keys in via
 * /admin/settings/storage and they never round-trip plaintext to the client
 * (controller masks key/secret on read, surfacing has_key/has_secret booleans).
 *
 * Region constants carry the canonical region list per provider so the
 * frontend's region picker has the right options.
 */
class StorageSetting extends Model
{
    protected $table = 'file_storage_settings';

    protected $fillable = ['filesystem', 'auth_keys', 'status'];

    protected $casts = [
        'auth_keys' => 'encrypted:array',
    ];

    /** @var self|null */
    private static ?self $activeMemo = null;

    /**
     * S3-compatible filesystems share the same Flysystem driver — only the
     * endpoint differs. `local` is the only non-S3 case.
     */
    public const S3_COMPATIBLE_FILESYSTEMS = ['s3', 'digitalocean', 'wasabi', 'minio'];

    public const AWS_REGIONS = [
        'us-east-2' => 'US East (Ohio) us-east-2',
        'us-east-1' => 'US East (N. Virginia) us-east-1',
        'us-west-1' => 'US West (N. California) us-west-1',
        'us-west-2' => 'US West (Oregon) us-west-2',
        'af-south-1' => 'Africa (Cape Town) af-south-1',
        'ap-east-1' => 'Asia Pacific (Hong Kong) ap-east-1',
        'ap-south-1' => 'Asia Pacific (Mumbai) ap-south-1',
        'ap-northeast-3' => 'Asia Pacific (Osaka-Local) ap-northeast-3',
        'ap-northeast-2' => 'Asia Pacific (Seoul) ap-northeast-2',
        'ap-southeast-1' => 'Asia Pacific (Singapore) ap-southeast-1',
        'ap-southeast-2' => 'Asia Pacific (Sydney) ap-southeast-2',
        'ap-northeast-1' => 'Asia Pacific (Tokyo) ap-northeast-1',
        'ca-central-1' => 'Canada (Central) ca-central-1',
        'eu-central-1' => 'Europe (Frankfurt) eu-central-1',
        'eu-west-1' => 'Europe (Ireland) eu-west-1',
        'eu-west-2' => 'Europe (London) eu-west-2',
        'eu-south-1' => 'Europe (Milan) eu-south-1',
        'eu-west-3' => 'Europe (Paris) eu-west-3',
        'eu-north-1' => 'Europe (Stockholm) eu-north-1',
        'me-south-1' => 'Middle East (Bahrain) me-south-1',
        'me-central-1' => 'Middle East (UAE) me-central-1',
        'sa-east-1' => 'South America (São Paulo) sa-east-1',
    ];

    public const DIGITALOCEAN_REGIONS = [
        'nyc1' => 'New York City, United States',
        'nyc3' => 'New York City, United States',
        'ams3' => 'Amsterdam, the Netherlands',
        'sfo3' => 'San Francisco, United States',
        'sgp1' => 'Singapore',
        'lon1' => 'London, United Kingdom',
        'fra1' => 'Frankfurt, Germany',
        'tor1' => 'Toronto, Canada',
        'blr1' => 'Bangalore, India',
        'syd1' => 'Sydney, Australia',
    ];

    public const WASABI_REGIONS = [
        'ap-southeast-2' => 'AP Southeast 2 (Sydney)',
        'ap-southeast-1' => 'AP Southeast 1 (Singapore)',
        'ap-northeast-2' => 'AP Northeast 2 (Osaka)',
        'ap-northeast-1' => 'AP Northeast 1 (Tokyo)',
        'eu-west-3' => 'EU West 3 (London)',
        'eu-west-2' => 'EU West 2 (Paris)',
        'eu-west-1' => 'EU West 1 (London)',
        'eu-south-1' => 'EU South 1 (Milan)',
        'eu-central-2' => 'EU Central 2 (Frankfurt)',
        'eu-central-1' => 'EU Central 1 (Amsterdam)',
        'ca-central-1' => 'CA Central 1 (Toronto)',
        'us-west-1' => 'US West 1 (Oregon)',
        'us-central-1' => 'US Central 1 (Texas)',
        'us-east-2' => 'US East 2 (N. Virginia)',
        'us-east-1' => 'US East 1 (N. Virginia)',
    ];

    /**
     * Resolve the currently-active storage row. Falls back to the seeded
     * `local` row when no other provider is enabled. Memoized request-scoped
     * so AppServiceProvider::applyStorageSettings + downstream readers don't
     * each hit the DB. Tests reset via `flushCache()`.
     */
    public static function active(): ?self
    {
        if (self::$activeMemo !== null) {
            return self::$activeMemo;
        }

        $row = self::query()->where('status', 'enabled')->first();
        if ($row === null) {
            $row = self::query()->where('filesystem', 'local')->first();
        }

        self::$activeMemo = $row;

        return $row;
    }

    public static function flushCache(): void
    {
        self::$activeMemo = null;
    }

    protected static function booted(): void
    {
        // Memo is request-scoped; mutating any row drops it so the next read
        // reflects the change (tests + admin save round-trips).
        static::saved(fn () => self::flushCache());
        static::deleted(fn () => self::flushCache());
    }
}
