<?php

namespace App\Service;

/**
 * Génère une « POST policy » S3 signée (SigV4) permettant au NAVIGATEUR de
 * téléverser un objet directement vers S3 par un POST multipart — sans CORS
 * (un POST de formulaire n'est pas soumis au contrôle CORS) et sans que le
 * serveur OVH ait besoin d'un accès réseau (la signature est un calcul local).
 *
 * Réutilisé pour l'upload des photos pendant le scan (Phase 2).
 */
final class S3PostPolicy
{
    public function __construct(private readonly S3Settings $s3)
    {
    }

    /**
     * @param string      $objectKey       clé complète de l'objet à créer
     * @param string      $contentType     type MIME imposé (ex. image/jpeg)
     * @param int         $maxBytes        taille max autorisée
     * @param string|null $successRedirect URL de redirection après succès (sinon HTTP 201)
     *
     * @return array{url:string, fields:array<string,string>}
     *
     * @throws \RuntimeException si la configuration S3 est incomplète
     */
    public function build(string $objectKey, string $contentType, int $maxBytes, ?string $successRedirect = null): array
    {
        if (!$this->s3->isConfigured()) {
            throw new \RuntimeException('Configuration S3 incomplète.');
        }

        $region = $this->s3->region();
        $bucket = $this->s3->bucket();
        $accessKey = $this->s3->accessKey();
        $key = ltrim($objectKey, '/');

        $now = time();
        $amzDate = gmdate('Ymd\THis\Z', $now);
        $dateStamp = gmdate('Ymd', $now);
        $credential = $accessKey . '/' . $dateStamp . '/' . $region . '/s3/aws4_request';
        $expiration = gmdate('Y-m-d\TH:i:s\Z', $now + 900); // 15 min pour finir l'upload

        $conditions = [
            ['bucket' => $bucket],
            ['key' => $key],
            ['Content-Type' => $contentType],
            ['x-amz-algorithm' => 'AWS4-HMAC-SHA256'],
            ['x-amz-credential' => $credential],
            ['x-amz-date' => $amzDate],
            ['content-length-range', 0, $maxBytes],
        ];

        $fields = [
            'key' => $key,
            'Content-Type' => $contentType,
            'x-amz-algorithm' => 'AWS4-HMAC-SHA256',
            'x-amz-credential' => $credential,
            'x-amz-date' => $amzDate,
        ];

        if ($successRedirect !== null && $successRedirect !== '') {
            $conditions[] = ['success_action_redirect' => $successRedirect];
            $fields['success_action_redirect'] = $successRedirect;
        } else {
            $conditions[] = ['success_action_status' => '201'];
            $fields['success_action_status'] = '201';
        }

        $policy = base64_encode((string) json_encode([
            'expiration' => $expiration,
            'conditions' => $conditions,
        ]));

        $fields['policy'] = $policy;
        $fields['x-amz-signature'] = hash_hmac('sha256', $policy, $this->signingKey($dateStamp, $region));

        return [
            'url' => 'https://' . $bucket . '.s3.' . $region . '.amazonaws.com/',
            'fields' => $fields,
        ];
    }

    private function signingKey(string $dateStamp, string $region): string
    {
        $k = hash_hmac('sha256', $dateStamp, 'AWS4' . $this->s3->secretKey(), true);
        $k = hash_hmac('sha256', $region, $k, true);
        $k = hash_hmac('sha256', 's3', $k, true);

        return hash_hmac('sha256', 'aws4_request', $k, true);
    }
}
