<?php

namespace PloverCRM\Modules\Automations\Services;

use PloverCRM\Core\Container;

/**
 * Resolves preview contacts and renders internal email previews.
 */
class InternalEmailPreviewService
{
    private const CONTACT_SCAN_LIMIT = 100;

    private Container $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    public function preview(array $input): array
    {
        $subject = sanitize_text_field((string) ($input['subject'] ?? ''));
        $body = wp_kses_post((string) ($input['body'] ?? ''));
        $sourceFilter = sanitize_text_field((string) ($input['source_filter'] ?? 'any'));
        $listIds = array_values(array_filter(array_map('absint', (array) ($input['list_ids'] ?? []))));
        $contactId = absint($input['contact_id'] ?? 0);

        $contact = $contactId > 0
            ? $this->resolvePreviewContactById($contactId)
            : $this->resolveRecentPreviewContact($sourceFilter, $listIds);

        if (!$contact) {
            return [
                'contact' => null,
                'subjectRendered' => '',
                'bodyRendered' => '',
                'warnings' => [
                    'No matching contact was found for preview yet. Create one that matches the selected filters, then refresh.',
                ],
            ];
        }

        $rendered = InternalEmailRenderer::render([
            'subject' => $subject,
            'body' => $body,
        ], $contact, [
            'strict' => false,
        ]);

        return [
            'contact' => $this->serializePreviewContact($contact),
            'subjectRendered' => $rendered['subject'],
            'bodyRendered' => $rendered['body'],
            'warnings' => $rendered['warnings'],
        ];
    }

    private function resolvePreviewContactById(int $contactId): ?array
    {
        $crm = $this->container->get('crm');

        if (!$crm || !$crm->isAvailable()) {
            return null;
        }

        $contact = $crm->getContact($contactId);

        return is_array($contact) ? $contact : null;
    }

    private function resolveRecentPreviewContact(string $sourceFilter, array $listIds): ?array
    {
        $crm = $this->container->get('crm');

        if (!$crm || !$crm->isAvailable()) {
            return null;
        }

        $recentContacts = $crm->getContactsByOwner([
            'page' => 1,
            'per_page' => self::CONTACT_SCAN_LIMIT,
        ]);

        foreach ((array) ($recentContacts['contacts'] ?? []) as $contact) {
            if (!is_array($contact)) {
                continue;
            }

            if (!$this->matchesSourceFilter($contact, $sourceFilter)) {
                continue;
            }

            if (!$this->matchesListFilter($contact, $listIds)) {
                continue;
            }

            return $contact;
        }

        return null;
    }

    private function matchesSourceFilter(array $contact, string $sourceFilter): bool
    {
        if ($sourceFilter === '' || $sourceFilter === 'any') {
            return true;
        }

        return strcasecmp((string) ($contact['source'] ?? ''), $sourceFilter) === 0;
    }

    private function matchesListFilter(array $contact, array $listIds): bool
    {
        if (empty($listIds)) {
            return true;
        }

        $contactListIds = [];

        foreach ((array) ($contact['lists'] ?? []) as $list) {
            if (is_array($list) && isset($list['id'])) {
                $contactListIds[] = absint($list['id']);
                continue;
            }

            if (is_object($list) && isset($list->id)) {
                $contactListIds[] = absint($list->id);
                continue;
            }

            if (is_numeric($list)) {
                $contactListIds[] = absint($list);
            }
        }

        return !empty(array_intersect($listIds, array_filter($contactListIds)));
    }

    private function serializePreviewContact(array $contact): array
    {
        $fullName = trim((string) ($contact['full_name'] ?? ''));

        if ($fullName === '') {
            $fullName = trim(
                implode(' ', array_filter([
                    (string) ($contact['first_name'] ?? ''),
                    (string) ($contact['last_name'] ?? ''),
                ]))
            );
        }

        return [
            'id' => isset($contact['id']) ? (int) $contact['id'] : 0,
            'fullName' => $fullName,
            'email' => (string) ($contact['email'] ?? ''),
            'source' => (string) ($contact['source'] ?? ''),
        ];
    }
}
