<?php

namespace DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\ErrorParser;

use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\Parser\PayloadParserTrait;
use DeliciousBrains\WP_Offload_Media\Aws3\Aws\Api\StructureShape;
use DeliciousBrains\WP_Offload_Media\Aws3\Psr\Http\Message\ResponseInterface;
/**
 * Provides basic JSON error parsing functionality.
 */
trait JsonParserTrait
{
    use PayloadParserTrait;
    private function genericHandler(ResponseInterface $response) : array
    {
        $code = (string) $response->getStatusCode();
        $error_code = null;
        $error_type = null;
        // Parse error code and type for query compatible services
        if ($this->api && !\is_null($this->api->getMetadata('awsQueryCompatible')) && $response->hasHeader('x-amzn-query-error')) {
            $awsQueryError = $this->parseAwsQueryCompatibleHeader($response);
            if ($awsQueryError) {
                $error_code = $awsQueryError['code'];
                $error_type = $awsQueryError['type'];
            }
        }
        // Parse error code from X-Amzn-Errortype header
        if (!$error_code && $response->hasHeader('X-Amzn-Errortype')) {
            $error_code = $this->extractErrorCode($response->getHeaderLine('X-Amzn-Errortype'));
        }
        $parsedBody = null;
        $body = $response->getBody();
        if (!$body->isSeekable() || $body->getSize()) {
            $parsedBody = $this->parseJson((string) $body, $response);
        }
        // Parse error code from response body
        if (!$error_code && $parsedBody) {
            $error_code = $this->parseErrorFromBody($parsedBody);
        }
        if (!isset($error_type)) {
            $error_type = $code[0] == '4' ? 'client' : 'server';
        }
        return ['request_id' => $response->getHeaderLine('x-amzn-requestid'), 'code' => $error_code ?? null, 'message' => null, 'type' => $error_type, 'parsed' => $parsedBody];
    }
    /**
     * Parse AWS Query Compatible error from header
     *
     * @param ResponseInterface $response
     * @return array|null Returns ['code' => string, 'type' => string] or null
     */
    private function parseAwsQueryCompatibleHeader(ResponseInterface $response) : ?array
    {
        $queryError = $response->getHeaderLine('x-amzn-query-error');
        $parts = \explode(';', $queryError);
        if (\count($parts) === 2 && $parts[0] && $parts[1]) {
            return ['code' => $parts[0], 'type' => $parts[1]];
        }
        return null;
    }
    /**
     * Parse error code from response body
     *
     * @param array|null $parsedBody
     * @return string|null
     */
    private function parseErrorFromBody(?array $parsedBody) : ?string
    {
        if (!$parsedBody || !isset($parsedBody['code']) && !isset($parsedBody['__type'])) {
            return null;
        }
        $error_code = $parsedBody['code'] ?? $parsedBody['__type'];
        return $this->extractErrorCode($error_code);
    }
    /**
     * Extract error code from raw error string containing # and/or : delimiters
     *
     * @param string $rawErrorCode
     * @return string
     */
    private function extractErrorCode(string $rawErrorCode) : string
    {
        // Handle format with both # and uri (e.g., "namespace#http://foo-bar")
        if (\str_contains($rawErrorCode, ':') && \str_contains($rawErrorCode, '#')) {
            $start = \strpos($rawErrorCode, '#') + 1;
            $end = \strpos($rawErrorCode, ':', $start);
            return \substr($rawErrorCode, $start, $end - $start);
        }
        // Handle format with uri only : (e.g., "ErrorCode:http://foo-bar.com/baz")
        if (\str_contains($rawErrorCode, ':')) {
            return \substr($rawErrorCode, 0, \strpos($rawErrorCode, ':'));
        }
        // Handle format with only # (e.g., "namespace#ErrorCode")
        if (\str_contains($rawErrorCode, '#')) {
            return \substr($rawErrorCode, \strpos($rawErrorCode, '#') + 1);
        }
        return $rawErrorCode;
    }
    protected function payload(ResponseInterface $response, StructureShape $member)
    {
        $body = $response->getBody();
        if (!$body->isSeekable() || $body->getSize()) {
            $jsonBody = $this->parseJson($body, $response);
        } else {
            $jsonBody = (string) $body;
        }
        return $this->parser->parse($member, $jsonBody);
    }
}
