<?php

declare(strict_types=1);

namespace PhpWA\Client;

use PhpWA\Exception\ProtocolException;
use PhpWA\Protocol\Proto\Message;

/**
 * Safely removes WhatsApp service wrappers around the user-visible message.
 *
 * WhatsApp wraps ordinary text and media in ephemeral/view-once/edit/device
 * envelopes. Keeping this protocol detail in one bounded class prevents live
 * delivery and history import from interpreting the same message differently.
 */
final class MessageUnwrapper
{
    private const MAXIMUM_DEPTH = 8;

    /** @return array{message:Message,wrappers:list<string>} */
    public function unwrap(Message $message): array
    {
        $current = $message;
        $wrappers = [];

        for ($depth = 0; $depth < self::MAXIMUM_DEPTH; $depth++) {
            $next = null;
            $name = null;

            foreach ($this->definitions() as $definition) {
                [$has, $get, $wrapperName] = $definition;
                if (!method_exists($current, $has) || !$current->{$has}()) {
                    continue;
                }
                $envelope = $current->{$get}();
                if (!is_object($envelope) || !method_exists($envelope, 'hasMessage')
                    || !$envelope->hasMessage() || !method_exists($envelope, 'getMessage')) {
                    throw new ProtocolException('Wrapped WhatsApp message is incomplete.');
                }
                $candidate = $envelope->getMessage();
                if (!$candidate instanceof Message) {
                    throw new ProtocolException('Wrapped WhatsApp message has an invalid payload.');
                }
                $next = $candidate;
                $name = $wrapperName;
                break;
            }

            if (!$next instanceof Message || !is_string($name)) {
                return ['message' => $current, 'wrappers' => $wrappers];
            }

            $wrappers[] = $name;
            $current = $next;
        }

        foreach ($this->definitions() as $definition) {
            if (method_exists($current, $definition[0]) && $current->{$definition[0]}()) {
                throw new ProtocolException('WhatsApp message wrapper depth exceeds its safety limit.');
            }
        }

        return ['message' => $current, 'wrappers' => $wrappers];
    }

    /** @return list<array{0:string,1:string,2:string}> */
    private function definitions(): array
    {
        return [
            ['hasDeviceSentMessage', 'getDeviceSentMessage', 'device_sent'],
            ['hasEphemeralMessage', 'getEphemeralMessage', 'ephemeral'],
            ['hasViewOnceMessage', 'getViewOnceMessage', 'view_once'],
            ['hasViewOnceMessageV2', 'getViewOnceMessageV2', 'view_once_v2'],
            ['hasViewOnceMessageV2Extension', 'getViewOnceMessageV2Extension', 'view_once_v2_extension'],
            ['hasDocumentWithCaptionMessage', 'getDocumentWithCaptionMessage', 'document_with_caption'],
            ['hasEditedMessage', 'getEditedMessage', 'edited'],
        ];
    }
}
