<?php

declare(strict_types=1);

namespace PhpWA\Integration;

use InvalidArgumentException;
use LogicException;
use PhpWA\Exception\AccountBusyException;
use PhpWA\Exception\AccountStatePendingException;
use PhpWA\Exception\ConnectionClosedException;
use PhpWA\Exception\CryptoException;
use PhpWA\Exception\MediaDownloadPendingException;
use PhpWA\Exception\OutgoingMessagePendingException;
use PhpWA\Exception\ProtocolException;
use PhpWA\Exception\RunCancelledException;
use PhpWA\Exception\SignalException;
use PhpWA\Exception\StorageConflictException;
use PhpWA\Exception\StorageException;
use PhpWA\Exception\TimeoutException;
use PhpWA\Exception\TransportException;

/** Stable secret-free error metadata for health UI, logs and retry policy. */
final class SafeDiagnostic
{
    /** @var string */ private $code;
    /** @var bool */ private $retryable;

    private function __construct(string $code, bool $retryable)
    {
        $this->code = $code;
        $this->retryable = $retryable;
    }

    public static function fromThrowable(\Throwable $error): self
    {
        if ($error instanceof RunCancelledException) { return new self('stale_generation', false); }
        if ($error instanceof AccountBusyException) { return new self('account_busy', true); }
        if ($error instanceof AccountStatePendingException) { return new self('account_state_pending', true); }
        if ($error instanceof MediaDownloadPendingException) { return new self('media_pending', true); }
        if ($error instanceof OutgoingMessagePendingException) { return new self('outgoing_pending', true); }
        if ($error instanceof TimeoutException) { return new self('timeout', true); }
        if ($error instanceof ConnectionClosedException) { return new self('connection_closed', true); }
        if ($error instanceof StorageConflictException) { return new self('storage_conflict', true); }
        if ($error instanceof StorageException) { return new self('storage_unavailable', false); }
        if ($error instanceof SignalException) { return new self('signal_state', true); }
        if ($error instanceof CryptoException) { return new self('crypto_failure', false); }
        if ($error instanceof ProtocolException) { return new self('protocol_incompatible', false); }
        if ($error instanceof TransportException) { return new self('transport_unavailable', true); }
        if ($error instanceof InvalidArgumentException || $error instanceof LogicException) {
            return new self('integration_error', false);
        }
        return new self('internal_error', false);
    }

    public function code(): string { return $this->code; }
    public function retryable(): bool { return $this->retryable; }

    /** @return array{code:string,retryable:bool} */
    public function toArray(): array { return ['code' => $this->code, 'retryable' => $this->retryable]; }
}
