<?php
/**
 * @package     MefisAssetBridge
 * @subpackage  MefisAssetBridgeCore_Api_Endpoints
 *
 * @copyright   Copyright (C) 2025 Goran Usljebrka. All rights reserved.
 * @license     Proprietary — No resale or incorporation into other projects without explicit written permission. see LICENSE.txt
 */

namespace MefisAssetBridgeCore\Api\Endpoints\Asset;

use MefisAssetBridgeCore\Api\ApiClient;
use MefisAssetBridgeCore\Auth\AuthenticatedUser;
use MefisAssetBridgeCore\Api\Response\ApiResponse;
use MefisAssetBridgeCore\Cache\CoreCache;
use MefisAssetBridgeCore\Interfaces\EndpointInterface;
use MefisAssetBridgeCore\Traits\Encryptor;
/**
 * getAssetThumbnail API Endpoint
 */
class GetAssetThumbnail implements EndpointInterface
{
    use Encryptor;

    /** @var ApiClient API client instance */
    private ApiClient $ApiClient;

    /** @var AuthenticatedUser|null Authenticated user */
    private ?AuthenticatedUser $user;
    private string $uuid;
    private string $pathHash;
    private bool $verifySSL;
    private ?CoreCache $cache;

    /** @var array Required parameters */
    private array $requiredParams = [
        'id',
    ];
    private string $validationError = '';
    public function __construct(string $uuid, ApiClient $ApiClient, ?AuthenticatedUser $user, string $pathHash = '', string $masterKey = '', bool $verifySSL = true, ?CoreCache $cache = null)
    {
        $this->ApiClient = $ApiClient;
        $this->user      = $user;
        $this->uuid      = $uuid;
        $this->pathHash  = $pathHash;
        $this->verifySSL = $verifySSL;
        $this->cache     = $cache;

        if(empty($masterKey)) {
            throw new \RuntimeException('Master key is required to load asset');
        }
        $this->setEncryptorKey($masterKey);
    }

    /**
     * Validate request parameters
     *
     * @param array $params Request parameters
     * @return bool True if parameters are valid
     */
    public function validateParams(array $params): bool
    {
        foreach ($this->requiredParams as $param) {
            if (! isset($params[$param])) {
                $this->validationError = sprintf('Missing required parameter: %s', $param);
                return false;
            }
        }
        return true;
    }

    /**
     * Send request to get asset thumbnail.
     *
     * Cache is checked first when CoreCache is available.
     * Encrypted binary is always written to cache (even on decrypt failure — not applicable
     * here since decrypt failure returns an error before returning to caller).
     * Decrypt, MIME detection and base64 encoding happen here.
     *
     * Required params: id (int), userUuid (string), assetUuid (string)
     * Optional params: modifiedAt (int Unix timestamp for cache staleness check)
     *
     * @param array $params
     * @return ApiResponse  Data array: [mime, data (base64), _decrypted, cache]
     */
    public function sendRequest(array $params = []): ApiResponse
    {
        if (!$this->validateParams($params)) {
            return ApiResponse::error($this->validationError);
        }

        $assetId   = (int) $params['id'];
        $userUuid  = $params['userUuid']  ?? '';
        $assetUuid = $params['assetUuid'] ?? '';
        $modifiedAt = isset($params['modifiedAt']) ? (int) $params['modifiedAt'] : null;
        $cacheKey  = $assetUuid . '.thumb';

        // --- Cache read ---
        $encryptedBinary = null;
        $fromCache = false;

        if ($this->cache !== null && $userUuid !== '' && $assetUuid !== '') {
            $cached = $this->cache->get($userUuid, $cacheKey, $modifiedAt);
            if ($cached !== null) {
                $encryptedBinary = $cached;
                $fromCache = true;
            }
        }

        // --- S3 fetch when cache miss ---
        if ($encryptedBinary === null) {
            $this->ApiClient->setUser($this->user);

            $response = $this->ApiClient->get("assets/{$assetId}/storage/thumbnail");
            if (!$response->isSuccess()) {
                return $response;
            }

            $responseData = $response->getData();
            if (!isset($responseData['presignedUrl'])) {
                return ApiResponse::error('Server did not provide presigned URL for thumbnail download');
            }

            $s3 = new \MefisAssetBridgeCore\Api\Storage\S3Storage($this->verifySSL);
            $dl = $s3->download($responseData['presignedUrl']);
            if (!$dl->isSuccess()) {
                return ApiResponse::error('Failed to download thumbnail from S3: ' . $dl->getMessage());
            }

            $dlData = $dl->getData();
            if (!isset($dlData['fileContent'])) {
                return ApiResponse::error('S3 download did not return file content');
            }

            $encryptedBinary = $dlData['fileContent'];

            // Always cache raw encrypted binary immediately after successful download
            if ($this->cache !== null && $userUuid !== '' && $assetUuid !== '') {
                $this->cache->set($userUuid, $encryptedBinary, $cacheKey);
            }
        }

        // --- Decrypt ---
        $decrypted = $this->decrypt($encryptedBinary, false);
        if ($decrypted === null) {
            return ApiResponse::error('Invalid Master Key.');
        }

        // --- MIME detection ---
        if (class_exists('\finfo')) {
            $finfo    = new \finfo(FILEINFO_MIME_TYPE);
            $mimeType = $finfo->buffer($decrypted) ?: 'application/octet-stream';
        } elseif (function_exists('getimagesizefromstring')) {
            $imageInfo = @getimagesizefromstring($decrypted);
            $mimeType  = $imageInfo['mime'] ?? 'application/octet-stream';
        } elseif (function_exists('mime_content_type')) {
            $tmp = tempnam(sys_get_temp_dir(), 'mefis_thumbnail_tmp_');
            if ($tmp && file_put_contents($tmp, $decrypted) !== false) {
                $mimeType = mime_content_type($tmp) ?: 'application/octet-stream';
                unlink($tmp);
            } else {
                $mimeType = 'application/octet-stream';
            }
        } else {
            if (strncmp($decrypted, "\xFF\xD8", 2) === 0) {
                $mimeType = 'image/jpeg';
            } elseif (strncmp($decrypted, "\x89PNG", 4) === 0) {
                $mimeType = 'image/png';
            } elseif (strncmp($decrypted, 'GIF8', 4) === 0) {
                $mimeType = 'image/gif';
            } else {
                $mimeType = 'application/octet-stream';
            }
        }

        return ApiResponse::success([
            'mime'       => $mimeType,
            'data'       => base64_encode($decrypted),
            '_decrypted' => true,
            'cache'      => $fromCache,
        ], 'Thumbnail loaded successfully');
    }
}