<?php

namespace App\Testing;

use Illuminate\Mail\Events\MessageSent;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\Mime\Address;

class Mailbox
{
    private const string STORAGE_PATH = 'testing/mailbox.json';

    public static function record(MessageSent $event): void
    {
        if (! config('e2e.testing_enabled')) {
            return;
        }

        $messages = self::read();
        $messages[] = [
            'id' => (string) Str::uuid(),
            'subject' => (string) $event->message->getSubject(),
            'from' => self::formatAddresses($event->message->getFrom()),
            'to' => self::formatAddresses($event->message->getTo()),
            'cc' => self::formatAddresses($event->message->getCc()),
            'bcc' => self::formatAddresses($event->message->getBcc()),
            'html' => method_exists($event->message, 'getHtmlBody') ? $event->message->getHtmlBody() : null,
            'text' => method_exists($event->message, 'getTextBody') ? $event->message->getTextBody() : null,
            'sent_at' => now()->toIso8601String(),
            'headers' => method_exists($event->message, 'getHeaders') && method_exists($event->message->getHeaders(), 'toString')
                ? $event->message->getHeaders()->toString()
                : null,
        ];

        self::write($messages);
    }

    public static function all(): array
    {
        return self::read();
    }

    public static function flush(): void
    {
        self::write([]);
    }

    private static function read(): array
    {
        $disk = Storage::disk('local');

        if (! $disk->exists(self::STORAGE_PATH)) {
            return [];
        }

        $decoded = json_decode($disk->get(self::STORAGE_PATH), true);

        return is_array($decoded) ? $decoded : [];
    }

    private static function write(array $messages): void
    {
        $disk = Storage::disk('local');

        $disk->put(self::STORAGE_PATH, json_encode($messages, JSON_PRETTY_PRINT));
    }

    /**
     * @param  Address[]|array|null  $addresses
     */
    private static function formatAddresses(?array $addresses): array
    {
        return Collection::make($addresses)
            ->filter()
            ->map(function ($address) {
                if ($address instanceof Address) {
                    return [
                        'name' => $address->getName() ?: null,
                        'email' => $address->getAddress(),
                    ];
                }

                return [
                    'name' => null,
                    'email' => (string) $address,
                ];
            })
            ->values()
            ->all();
    }
}
