<?php

namespace App\Services\FaceSwap;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Str;

/**
 * Hosts a try-on input image temporarily so an external face/outfit-swap API
 * can fetch it. Used by drivers that require an HTTP URL (FaceMint, WaveSpeed).
 *
 * Two modes, picked by faceswap.storage:
 *   "cloud" → upload to do_spaces_private + presigned URL (10 min TTL)
 *   "local" → write to tryon_local + return signed Laravel route (10 min TTL)
 *
 * Files are NEVER written to a public disk. Caller passes a $tempFiles array
 * by reference to track what was written, then calls cleanup() in finally{}.
 */
class TempImageHost
{
    /**
     * @param string $imageData  Raw image bytes
     * @param string $prefix     Subdir under tryon-temp/ (e.g. "facemint", "wavespeed")
     * @param array  $tempFiles  Tracking array (passed by reference)
     */
    public static function upload(string $imageData, string $prefix, array &$tempFiles): string
    {
        $token = (string) Str::uuid();
        $relativePath = 'tryon-temp/' . $prefix . '/' . $token . '.jpg';

        $mode = config('faceswap.storage', 'local');

        if ($mode === 'cloud') {
            if (!config('filesystems.disks.do_spaces_private.key')) {
                throw new \RuntimeException(
                    'VIRTUAL_TRYON_STORAGE=cloud requires DO_SPACES_PRIVATE_* env to be set.'
                );
            }
            Storage::disk('do_spaces_private')->put($relativePath, $imageData, 'private');
            $tempFiles[] = ['disk' => 'do_spaces_private', 'path' => $relativePath];

            return Storage::disk('do_spaces_private')->temporaryUrl($relativePath, now()->addMinutes(10));
        }

        // Local mode: write to private disk, expose via signed Laravel route.
        // External APIs need a publicly-resolvable URL — make sure APP_URL is
        // reachable from the internet (e.g. via tunnel) when using FaceMint /
        // WaveSpeed in local mode.
        Storage::disk('tryon_local')->put($relativePath, $imageData);
        $tempFiles[] = ['disk' => 'tryon_local', 'path' => $relativePath];

        return URL::temporarySignedRoute(
            'tryon.temp.image',
            now()->addMinutes(10),
            ['token' => $prefix . '_' . $token]
        );
    }

    public static function cleanup(array $tempFiles): void
    {
        foreach ($tempFiles as $file) {
            try {
                Storage::disk($file['disk'])->delete($file['path']);
            } catch (\Exception $e) {
                Log::warning('TempImageHost cleanup failed', [
                    'path' => $file['path'],
                    'error' => $e->getMessage(),
                ]);
            }
        }
    }

    /**
     * Resolve the signed-route token back to a storage path.
     * Token format: "{prefix}_{uuid}" — single underscore separator.
     */
    public static function tokenToPath(string $token): ?string
    {
        $pos = strpos($token, '_');
        if ($pos === false) return null;
        $prefix = substr($token, 0, $pos);
        $uuid = substr($token, $pos + 1);
        if (!preg_match('/^[a-z0-9]+$/', $prefix)) return null;
        if (!preg_match('/^[0-9a-f-]{36}$/', $uuid)) return null;
        return 'tryon-temp/' . $prefix . '/' . $uuid . '.jpg';
    }
}
