<?php

declare(strict_types=1);

namespace App\Infrastructure\Api\RapidMail;

use App\Framework\Http\Method;
use App\Infrastructure\Api\RapidMail\Commands\CreateRecipientCommand;
use App\Infrastructure\Api\RapidMail\Commands\UpdateRecipientCommand;
use App\Infrastructure\Api\RapidMail\ReadModels\Recipient;

/**
 * Modern RecipientService with Value Objects and Command/Query separation
 *
 * Use the new methods (createWithCommand, get with RecipientId, etc.) for type safety.
 * Legacy methods are marked as deprecated but still functional for backward compatibility.
 */
final readonly class RecipientService
{
    public function __construct(
        private RapidMailApiClient $apiClient
    ) {
    }

    /**
     * Creates a new recipient using Command pattern (RECOMMENDED)
     */
    public function createWithCommand(CreateRecipientCommand $command): Recipient
    {
        $data = $this->apiClient->request(
            Method::POST,
            'recipients',
            $command->toArray(),
            $this->apiClient->getDefaultQueryParams()
        );

        return Recipient::fromArray($data);
    }

    /**
     * Gets a recipient by ID using Value Object (RECOMMENDED)
     */
    public function get(RecipientId $recipientId): Recipient
    {
        $data = $this->apiClient->request(Method::GET, "recipients/{$recipientId->value}");

        return Recipient::fromArray($data);
    }

    /**
     * Updates a recipient using Command pattern (RECOMMENDED)
     */
    public function updateWithCommand(UpdateRecipientCommand $command): Recipient
    {
        $data = $this->apiClient->request(
            Method::PATCH,
            "recipients/{$command->id->value}",
            $command->toArray()
        );

        return Recipient::fromArray($data);
    }

    /**
     * Deletes a recipient using Value Object (RECOMMENDED)
     */
    public function delete(RecipientId $recipientId): void
    {
        $this->apiClient->sendRawRequest(Method::DELETE, "recipients/{$recipientId->value}");
    }

    /**
     * Searches for recipients with filters (RECOMMENDED)
     * @return Recipient[]
     */
    public function search(array $filter = [], int $page = 1, int $perPage = 50): array
    {
        $queryParams = [
            'page' => $page,
            'per_page' => $perPage,
        ];

        if (! empty($filter)) {
            $queryParams = array_merge($queryParams, $filter);
        }

        $apiResponse = $this->apiClient->request(Method::GET, 'recipients', [], $queryParams);

        $recipients = $apiResponse['_embedded']['recipients'] ?? [];

        return array_map(
            fn (array $item) => Recipient::fromArray($item),
            $recipients
        );
    }

    /**
     * Finds a specific recipient by email (RECOMMENDED)
     */
    public function findByEmail(string $email, ?RecipientListId $recipientListId = null): ?Recipient
    {
        $filter = ['email' => $email];
        if ($recipientListId !== null) {
            $filter['recipientlist_id'] = $recipientListId->value;
        }

        $recipients = $this->search($filter, 1, 1);

        return empty($recipients) ? null : $recipients[0];
    }

    /**
     * Checks if a recipient exists (RECOMMENDED)
     */
    public function exists(string $email, ?RecipientListId $recipientListId = null): bool
    {
        return $this->findByEmail($email, $recipientListId) !== null;
    }
}
