<?php

namespace App\Helpers;

use App\Models\SystemSetting;
use Aws\S3\S3Client;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Storage;

/**
 * StorageHelper — applies admin-saved S3/CDN settings to the runtime
 * Laravel filesystem config so file uploads transparently route to the
 * configured provider (AWS S3, Cloudflare R2, Wasabi, Backblaze B2,
 * DigitalOcean Spaces, Linode, MinIO, etc. — they all speak the S3 API).
 *
 * Called from AppServiceProvider::boot(). When `s3_enabled` is false,
 * we leave Laravel's defaults alone (local disk). When true, we
 * REWRITE the s3 disk config with the admin values and switch the
 * default cloud disk to s3 so existing $request->file()->store() calls
 * land in the bucket without controller changes.
 *
 * Security: the secret is read from SystemSetting which decrypts on get().
 * We never log it.
 */
class StorageHelper
{
    /**
     * Apply saved settings to the runtime filesystem config. Safe to call
     * once at boot — no-ops when nothing is configured.
     */
    public static function applyRuntimeConfig(): void
    {
        try {
            if (!SystemSetting::enabled('s3_enabled', false)) {
                return;
            }
        } catch (\Throwable $e) {
            // DB not ready (fresh install). Skip silently.
            return;
        }

        try {
            $key      = SystemSetting::get('s3_key', '');
            $secret   = SystemSetting::get('s3_secret', ''); // auto-decrypted
            $bucket   = SystemSetting::get('s3_bucket', '');
            $region   = SystemSetting::get('s3_region', 'us-east-1');
            $endpoint = SystemSetting::get('s3_endpoint', '') ?: null;
            $url      = SystemSetting::get('s3_url', '') ?: null;
            $pathStyle = SystemSetting::enabled('s3_path_style', false);
        } catch (\Throwable $e) {
            return;
        }

        if (!$key || !$secret || !$bucket) {
            return; // partial config — skip rather than break uploads
        }

        Config::set('filesystems.disks.s3', [
            'driver'                  => 's3',
            'key'                     => $key,
            'secret'                  => $secret,
            'region'                  => $region,
            'bucket'                  => $bucket,
            'url'                     => $url,
            'endpoint'                => $endpoint,
            'use_path_style_endpoint' => $pathStyle,
            'throw'                   => false,
            'visibility'              => 'public',
        ]);

        // Make the s3 disk the default for cloud-style uploads. Code that
        // still does Storage::disk('public') keeps working — we only steer
        // the "cloud" default, not local.
        Config::set('filesystems.cloud', 's3');
    }

    /**
     * Test the configured S3 connection by writing + reading + deleting a
     * tiny probe file. Returns [success, message].
     *
     * Why this matters: silent connection failures on uploads are nightmarish
     * to debug. The Test button gives admins instant feedback that their
     * key/bucket combo actually works BEFORE they switch over production.
     */
    public static function testConnection(array $overrides = []): array
    {
        try {
            $key      = $overrides['key']      ?? SystemSetting::get('s3_key', '');
            $secret   = $overrides['secret']   ?? SystemSetting::get('s3_secret', '');
            $bucket   = $overrides['bucket']   ?? SystemSetting::get('s3_bucket', '');
            $region   = $overrides['region']   ?? SystemSetting::get('s3_region', 'us-east-1');
            $endpoint = $overrides['endpoint'] ?? (SystemSetting::get('s3_endpoint', '') ?: null);
            $pathStyle = $overrides['path_style']
                ?? SystemSetting::enabled('s3_path_style', false);

            if (!$key || !$secret || !$bucket) {
                return [false, 'Key, Secret, and Bucket are required.'];
            }

            $clientCfg = [
                'version'     => 'latest',
                'region'      => $region,
                'credentials' => ['key' => $key, 'secret' => $secret],
            ];
            if ($endpoint) $clientCfg['endpoint'] = $endpoint;
            if ($pathStyle) $clientCfg['use_path_style_endpoint'] = true;

            $s3 = new S3Client($clientCfg);

            $probeKey = '.mailtrixy-probe-' . bin2hex(random_bytes(4)) . '.txt';
            $s3->putObject([
                'Bucket' => $bucket,
                'Key'    => $probeKey,
                'Body'   => 'mailtrixy-connection-test',
                'ACL'    => 'private',
            ]);
            $s3->deleteObject(['Bucket' => $bucket, 'Key' => $probeKey]);

            return [true, "Connection OK. Bucket '{$bucket}' is writable in region '{$region}'."];
        } catch (\Aws\Exception\AwsException $e) {
            return [false, $e->getAwsErrorMessage() ?: $e->getMessage()];
        } catch (\Throwable $e) {
            return [false, $e->getMessage()];
        }
    }
}
