<?php

namespace App\Services\Files;

use App\Models\File;
use Aws\CloudFront\CloudFrontClient;
use Illuminate\Support\Facades\Storage;

class CdnService
{
    protected ?CloudFrontClient $client = null;

    public function __construct()
    {
        if ($this->isEnabled()) {
            $this->client = new CloudFrontClient([
                'version' => 'latest',
                'region' => config('filesystems.disks.s3.region', 'us-east-1'),
            ]);
        }
    }

    /**
     * Check if CDN is enabled.
     */
    public function isEnabled(): bool
    {
        return config('file_upload.cdn.enabled', false) && config('file_upload.cdn.domain');
    }

    /**
     * Get the CDN URL for a file.
     */
    public function getUrl(File $file): string
    {
        if (! $this->isEnabled()) {
            return Storage::disk($file->disk)->url($file->path);
        }

        $domain = config('file_upload.cdn.domain');

        return "https://{$domain}/{$file->path}";
    }

    /**
     * Get a signed CDN URL for private files.
     */
    public function getSignedUrl(File $file, int $expiresMinutes = null): string
    {
        if (! $this->isEnabled()) {
            // Fallback to S3 signed URL
            return Storage::disk($file->disk)->temporaryUrl(
                $file->path,
                now()->addMinutes($expiresMinutes ?? 60)
            );
        }

        $keyPairId = config('file_upload.cdn.key_pair_id');
        $privateKeyPath = config('file_upload.cdn.private_key_path');

        if (! $keyPairId || ! $privateKeyPath || ! file_exists($privateKeyPath)) {
            // Fallback to S3 signed URL
            return Storage::disk($file->disk)->temporaryUrl(
                $file->path,
                now()->addMinutes($expiresMinutes ?? 60)
            );
        }

        $expires = time() + ($expiresMinutes ?? config('file_upload.cdn.default_expiry', 3600));
        $domain = config('file_upload.cdn.domain');
        $url = "https://{$domain}/{$file->path}";

        // Create CloudFront signed URL
        $policy = json_encode([
            'Statement' => [
                [
                    'Resource' => $url,
                    'Condition' => [
                        'DateLessThan' => [
                            'AWS:EpochTime' => $expires,
                        ],
                    ],
                ],
            ],
        ]);

        $privateKey = file_get_contents($privateKeyPath);
        openssl_sign($policy, $signature, $privateKey, OPENSSL_ALGO_SHA1);

        $signature = base64_encode($signature);
        $signature = str_replace(['+', '=', '/'], ['-', '_', '~'], $signature);

        return "{$url}?Expires={$expires}&Signature={$signature}&Key-Pair-Id={$keyPairId}";
    }

    /**
     * Invalidate CloudFront cache for given paths.
     */
    public function invalidateCache(array $paths): bool
    {
        if (! $this->isEnabled() || ! $this->client) {
            return false;
        }

        try {
            $this->client->createInvalidation([
                'DistributionId' => config('file_upload.cdn.distribution_id'),
                'InvalidationBatch' => [
                    'CallerReference' => (string) time(),
                    'Paths' => [
                        'Quantity' => count($paths),
                        'Items' => array_map(fn ($path) => "/{$path}", $paths),
                    ],
                ],
            ]);

            return true;
        } catch (\Exception $e) {
            report($e);

            return false;
        }
    }
}
