<?php

declare(strict_types=1);

namespace ImovelZapAi\Conversations\Application\Services;

use ImovelZapAi\Conversations\Application\Data\InboundWhatsAppMessage;
use ImovelZapAi\Conversations\Application\Data\WhatsAppDeliveryUpdate;
use ImovelZapAi\Conversations\Application\Data\WhatsAppWebhookPayload;

final class WhatsAppWebhookParser
{
    /**
     * @param  array<string, mixed>  $payload
     */
    public function parse(array $payload): WhatsAppWebhookPayload
    {
        $messages = [];
        $deliveryUpdates = [];

        foreach ($payload['entry'] ?? [] as $entry) {
            if (! is_array($entry)) {
                continue;
            }

            foreach ($entry['changes'] ?? [] as $change) {
                if (! is_array($change)) {
                    continue;
                }

                $value = $change['value'] ?? null;

                if (! is_array($value)) {
                    continue;
                }

                $phoneNumberId = (string) ($value['metadata']['phone_number_id'] ?? '');
                $contactsByWaId = $this->indexContacts($value['contacts'] ?? []);

                foreach ($value['messages'] ?? [] as $message) {
                    if (! is_array($message)) {
                        continue;
                    }

                    $parsed = $this->parseInboundMessage($phoneNumberId, $message, $contactsByWaId);

                    if ($parsed !== null) {
                        $messages[] = $parsed;
                    }
                }

                foreach ($value['statuses'] ?? [] as $status) {
                    if (! is_array($status)) {
                        continue;
                    }

                    $parsedStatus = $this->parseDeliveryUpdate($phoneNumberId, $status);

                    if ($parsedStatus !== null) {
                        $deliveryUpdates[] = $parsedStatus;
                    }
                }
            }
        }

        return new WhatsAppWebhookPayload($messages, $deliveryUpdates);
    }

    /**
     * @param  list<mixed>  $contacts
     * @return array<string, string>
     */
    private function indexContacts(array $contacts): array
    {
        $indexed = [];

        foreach ($contacts as $contact) {
            if (! is_array($contact)) {
                continue;
            }

            $waId = (string) ($contact['wa_id'] ?? '');

            if ($waId === '') {
                continue;
            }

            $indexed[$waId] = (string) ($contact['profile']['name'] ?? '');
        }

        return $indexed;
    }

    /**
     * @param  array<string, mixed>  $message
     * @param  array<string, string>  $contactsByWaId
     */
    private function parseInboundMessage(string $phoneNumberId, array $message, array $contactsByWaId): ?InboundWhatsAppMessage
    {
        $providerMessageId = (string) ($message['id'] ?? '');
        $waId = (string) ($message['from'] ?? '');
        $messageType = (string) ($message['type'] ?? 'text');

        if ($phoneNumberId === '' || $providerMessageId === '' || $waId === '') {
            return null;
        }

        $body = match ($messageType) {
            'text' => (string) ($message['text']['body'] ?? ''),
            'interactive' => (string) ($message['interactive']['button_reply']['title'] ?? ''),
            default => '',
        };

        $interactiveReplyId = match ($messageType) {
            'interactive' => (string) ($message['interactive']['button_reply']['id'] ?? ''),
            default => null,
        };

        if ($interactiveReplyId === '') {
            $interactiveReplyId = null;
        }

        return new InboundWhatsAppMessage(
            phoneNumberId: $phoneNumberId,
            providerMessageId: $providerMessageId,
            waId: $waId,
            displayName: $contactsByWaId[$waId] ?? null,
            body: $body,
            messageType: $messageType,
            providerTimestamp: (int) ($message['timestamp'] ?? 0),
            interactiveReplyId: $interactiveReplyId,
        );
    }

    /**
     * @param  array<string, mixed>  $status
     */
    private function parseDeliveryUpdate(string $phoneNumberId, array $status): ?WhatsAppDeliveryUpdate
    {
        $providerMessageId = (string) ($status['id'] ?? '');
        $deliveryStatus = (string) ($status['status'] ?? '');

        if ($phoneNumberId === '' || $providerMessageId === '' || $deliveryStatus === '') {
            return null;
        }

        return new WhatsAppDeliveryUpdate(
            phoneNumberId: $phoneNumberId,
            providerMessageId: $providerMessageId,
            status: $deliveryStatus,
            providerTimestamp: (int) ($status['timestamp'] ?? 0),
        );
    }
}
