<?php

declare(strict_types=1);

namespace FecaMailshots\Admin;

use FecaMailshots\Application\MailshotRunService;
use FecaMailshots\Application\MailshotService;
use FecaMailshots\WordPress\WordPressFacade;

final class MailshotTestAdminPage
{
    use AdminRequestHelpers;

    private const RESULT_OPTION_KEY = 'feca_mailshots_test_ui_result';
    private const CAPABILITY = 'edit_pages';
    private const NONCE_ACTION = 'feca_mailshots_test';

    /** @var callable(): MailshotRunService */
    private $runServiceFactory;

    /** @var callable(): MailshotService */
    private $mailshotServiceFactory;

    private WordPressFacade $wp;

    /** @param callable(): MailshotRunService $runServiceFactory @param callable(): MailshotService $mailshotServiceFactory */
    public function __construct(callable $runServiceFactory, callable $mailshotServiceFactory, WordPressFacade $wp)
    {
        $this->runServiceFactory = $runServiceFactory;
        $this->mailshotServiceFactory = $mailshotServiceFactory;
        $this->wp = $wp;
    }

    public function register(): void
    {
        $this->wp->addAction('admin_menu', [$this, 'registerMenu']);
        $this->wp->addAction('admin_post_feca_mailshots_test_api', [$this, 'handleApi']);
        $this->wp->addAction('admin_post_feca_mailshots_test_render_ui', [$this, 'handleRenderUi']);
        $this->wp->addAction('admin_post_feca_mailshots_test_send_ui', [$this, 'handleSendUi']);
    }

    public function registerMenu(): void
    {
        $this->wp->addSubmenuPage('feca-mailshot', 'Mailshot Test', 'Mailshot Test', self::CAPABILITY, 'feca-mailshots-test', [$this, 'render']);
    }

    public function render(): void
    {
        if (!$this->wp->currentUserCan(self::CAPABILITY)) {
            echo 'Permission denied';
            return;
        }

        $mailshots = $this->mailshotService()->list();
        $selectedMailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');

        $preview = ['ok' => false, 'rows' => [], 'errors' => ['Select a mailshot.']];
        if ($selectedMailshotId > 0) {
            $preview = $this->runService()->previewRecipients($selectedMailshotId, 100);
        }
        $rows = is_array($preview['rows'] ?? null) ? $preview['rows'] : [];

        $selectedRecipientIndex = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
        $defaultEmail = $this->runService()->defaultTestEmail()['default_test_email'] ?? '';
        $testEmail = (string) ($this->wp->requestParam('test_email', (string) $defaultEmail) ?? $defaultEmail);
        $result = $this->result();

        $action = htmlspecialchars($this->wp->adminUrl('admin-post.php'));

        echo '<div class="wrap"><h1>Mailshot Test</h1>';
        echo '<p>Render with a selected recipient context, then optionally send one test email.</p>';

        if ($result !== null) {
            $ok = !empty($result['ok']);
            $bg = $ok ? '#f1f8e9' : '#ffebee';
            $border = $ok ? '#8bc34a' : '#ef9a9a';
            echo '<div style="padding:10px;border:1px solid ' . $border . ';background:' . $bg . ';margin:12px 0;">';
            echo '<strong>' . ($ok ? 'Test action succeeded.' : 'Test action failed.') . '</strong>';
            if (!empty($result['errors']) && is_array($result['errors'])) {
                echo '<p style="margin:6px 0 0 0;">' . htmlspecialchars(implode('; ', $result['errors'])) . '</p>';
            }
            if (!empty($result['warnings']) && is_array($result['warnings'])) {
                echo '<p style="margin:6px 0 0 0;">Warnings: ' . htmlspecialchars(implode('; ', $result['warnings'])) . '</p>';
            }
            if (!empty($result['sent_to'])) {
                echo '<p style="margin:6px 0 0 0;">Sent to: <code>' . htmlspecialchars((string) $result['sent_to']) . '</code></p>';
            }
            if (!empty($result['sent_at'])) {
                echo '<p style="margin:6px 0 0 0;">Sent at: <code>' . htmlspecialchars((string) $result['sent_at']) . '</code></p>';
            }
            if (($result['ui_action'] ?? '') === 'render' && !empty($result['ok']) && is_array($result['rendered'] ?? null)) {
                echo '<p style="margin:8px 0 0 0;"><button type="button" class="button button-primary" id="ms-open-render-preview">Open Render Preview</button></p>';
            }
            echo '<details style="margin-top:8px;"><summary>Show technical details</summary><pre style="margin-top:8px;">' . htmlspecialchars($this->debugJson($result), ENT_QUOTES) . '</pre></details>';
            echo '</div>';
        }

        echo '<div style="padding:12px;border:1px solid #dcdcde;background:#fff;margin-bottom:12px;">';
        echo '<h2 style="margin-top:0;">1. Select Mailshot</h2>';
        echo '<form method="get" action="' . htmlspecialchars($this->wp->adminUrl('admin.php')) . '" style="margin-bottom:0;">';
        echo '<input type="hidden" name="page" value="feca-mailshots-test">';
        echo '<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;">';
        echo '<div style="display:flex;align-items:center;gap:8px;padding-top:6px;min-width:360px;">';
        echo '<label for="mst_mailshot_id" style="white-space:nowrap;padding-left:4px;"><strong>Mailshot</strong></label>';
        echo '<select id="mst_mailshot_id" name="mailshot_id">';
        foreach ($mailshots as $m) {
            $id = (int) ($m['id'] ?? 0);
            $sel = $id === $selectedMailshotId ? ' selected' : '';
            $label = trim((string) ($m['Purpose'] ?? ''));
            if ($label === '') {
                $label = 'Mailshot #' . $id;
            }
            echo '<option value="' . $id . '"' . $sel . '>' . htmlspecialchars($label) . '</option>';
        }
        echo '</select></div><button class="button" type="submit">Load recipients</button></div>';
        echo '</form>';
        echo '</div>';

        if (!empty($preview['errors'])) {
            echo '<div style="padding:10px;border:1px solid #ef9a9a;background:#ffebee;margin:12px 0;">' . htmlspecialchars(implode('; ', $preview['errors'])) . '</div>';
        }

        echo '<form method="post" action="' . $action . '" style="padding:12px;border:1px solid #dcdcde;background:#fff;margin-bottom:12px;">';
        echo '<h2 style="margin-top:0;">2. Render / Send Test</h2>';
        echo $this->hiddenNonceField(self::NONCE_ACTION);
        echo '<input type="hidden" name="mailshot_id" value="' . $selectedMailshotId . '">';

        echo '<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;">';
        echo '<div style="display:flex;align-items:center;gap:8px;padding-top:6px;min-width:380px;">';
        echo '<label for="mst_recipient_index" style="white-space:nowrap;padding-left:4px;"><strong>Recipient row</strong></label>';
        echo '<select id="mst_recipient_index" name="recipient_index">';
        foreach ($rows as $r) {
            $idx = (int) ($r['index'] ?? 0);
            $sel = $idx === $selectedRecipientIndex ? ' selected' : '';
            $email = (string) ($r['recipient_email'] ?? '');
            $key = (string) ($r['recipient_key'] ?? '');
            $text = $email !== '' ? $email : '(no email)';
            if ($key !== '' && strcasecmp($key, $email) !== 0) {
                $text .= ' | ' . $key;
            }
            echo '<option value="' . $idx . '"' . $sel . '>' . htmlspecialchars($text) . '</option>';
        }
        echo '</select></div>';
        echo '</div>';

        echo '<p><button class="button" type="submit" name="action" value="feca_mailshots_test_render_ui">Render Test (No Send)</button></p>';

        echo '<div style="display:flex;gap:12px;align-items:center;flex-wrap:wrap;">';
        echo '<div style="display:flex;align-items:center;gap:8px;padding-top:6px;min-width:420px;">';
        echo '<label for="mst_test_email" style="white-space:nowrap;padding-left:4px;"><strong>Test email address</strong></label>';
        echo '<input id="mst_test_email" class="regular-text" type="email" name="test_email" value="' . htmlspecialchars($testEmail, ENT_QUOTES) . '">';
        echo '</div>';
        echo '</div>';
        echo '<p><button class="button button-primary" type="submit" name="action" value="feca_mailshots_test_send_ui" onclick="return confirm(\'Send one test email to the entered address?\');">Send Test Email</button></p>';
        echo '</form>';

        if ($rows !== []) {
            $sampleColumns = $this->sampleColumns($rows, 4);
            echo '<div style="padding:12px;border:1px solid #dcdcde;background:#fff;">';
            echo '<h2 style="margin-top:0;">Recipient Sample (First 20)</h2><table class="widefat striped"><thead><tr><th>#</th><th>Key</th><th>Email</th>';
            foreach ($sampleColumns as $col) {
                echo '<th>' . htmlspecialchars($col) . '</th>';
            }
            echo '</tr></thead><tbody>';
            foreach (array_slice($rows, 0, 20) as $r) {
                $rowData = is_array($r['row'] ?? null) ? $r['row'] : [];
                echo '<tr><td>' . (int) ($r['index'] ?? 0) . '</td><td>' . htmlspecialchars((string) ($r['recipient_key'] ?? '')) . '</td><td>' . htmlspecialchars((string) ($r['recipient_email'] ?? '')) . '</td>';
                foreach ($sampleColumns as $col) {
                    echo '<td>' . htmlspecialchars($this->displayCellValue($rowData[$col] ?? null)) . '</td>';
                }
                echo '</tr>';
            }
            echo '</tbody></table>';
            echo '</div>';
        }

        if ($result !== null && ($result['ui_action'] ?? '') === 'render' && !empty($result['ok']) && is_array($result['rendered'] ?? null)) {
            $rendered = $result['rendered'];
            $recipient = $this->selectedRecipientSummary($rows, $selectedRecipientIndex);
            $recipientText = $recipient['email'] ?? '';
            if (($recipient['key'] ?? '') !== '' && strcasecmp((string) ($recipient['key'] ?? ''), (string) ($recipient['email'] ?? '')) !== 0) {
                $recipientText .= ($recipientText !== '' ? ' | ' : '') . (string) $recipient['key'];
            }
            if ($recipientText === '') {
                $recipientText = '(recipient unavailable)';
            }
            $subject = (string) ($rendered['subject'] ?? '');
            $messageHtml = (string) ($rendered['message'] ?? '');
            $pdfHtml = (string) ($rendered['pdf_attachment'] ?? '');

            echo '<div id="ms-render-preview-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:100000;">';
            echo '<div style="max-width:1100px;margin:28px auto;background:#fff;padding:14px;max-height:90vh;overflow:auto;">';
            echo '<h2 style="margin-top:0;">Render Preview</h2>';
            echo '<p style="margin:0 0 8px 0;"><strong>Recipient:</strong> ' . htmlspecialchars($recipientText) . '</p>';
            echo '<p style="margin:0 0 10px 0;"><strong>Subject:</strong> ' . htmlspecialchars($subject) . '</p>';
            echo '<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;">';
            echo '<div><h3 style="margin:0 0 8px 0;">Message (HTML)</h3><iframe sandbox="" style="width:100%;height:320px;border:1px solid #dcdcde;background:#fff;" srcdoc="' . htmlspecialchars($messageHtml, ENT_QUOTES) . '"></iframe></div>';
            echo '<div><h3 style="margin:0 0 8px 0;">PDF Attachment (HTML)</h3><iframe sandbox="" style="width:100%;height:320px;border:1px solid #dcdcde;background:#fff;" srcdoc="' . htmlspecialchars($pdfHtml, ENT_QUOTES) . '"></iframe></div>';
            echo '</div>';
            echo '<p style="margin-top:12px;"><button type="button" class="button button-primary" id="ms-close-render-preview">Close</button></p>';
            echo '</div></div>';
            echo '<script>(function(){';
            echo 'var modal=document.getElementById("ms-render-preview-modal");';
            echo 'var open=document.getElementById("ms-open-render-preview");';
            echo 'var close=document.getElementById("ms-close-render-preview");';
            echo 'if(!modal){return;}';
            echo 'var show=function(){modal.style.display="block";};';
            echo 'var hide=function(){modal.style.display="none";};';
            echo 'if(open){open.addEventListener("click",show);}';
            echo 'if(close){close.addEventListener("click",hide);}';
            echo 'modal.addEventListener("click",function(ev){if(ev.target===modal){hide();}});';
            echo 'document.addEventListener("keydown",function(ev){if(ev.key==="Escape"&&modal.style.display==="block"){hide();}});';
            echo 'show();';
            echo '})();</script>';
        }

        echo '</div>';
    }

    public function handleApi(): void
    {
        if (!$this->enforceCapabilityOrJson(self::CAPABILITY)) {
            return;
        }

        $op = (string) ($this->wp->requestParam('op', '') ?? '');
        $service = $this->runService();

        try {
            if ($op === 'default_test_email') {
                $this->wp->sendJson(['ok' => true] + $service->defaultTestEmail());
                return;
            }

            if ($op === 'render_test') {
                if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
                    return;
                }
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $idx = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
                $this->wp->sendJson($service->renderTest($mailshotId, $idx));
                return;
            }

            if ($op === 'send_test') {
                if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
                    return;
                }
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $idx = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
                $to = (string) ($this->wp->requestParam('test_email', '') ?? '');
                $this->wp->sendJson($service->sendTest($mailshotId, $idx, $to));
                return;
            }

            $this->wp->sendJson(['ok' => false, 'error' => 'Unknown op'], 400);
        } catch (\Throwable $e) {
            $this->wp->sendJson(['ok' => false, 'error' => $e->getMessage()], 500);
        }
    }

    public function handleRenderUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
        $idx = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
        try {
            $result = $this->runService()->renderTest($mailshotId, $idx);
        } catch (\Throwable $e) {
            $result = ['ok' => false, 'errors' => ['Render test failed: ' . $e->getMessage()]];
        }
        $result['ui_action'] = 'render';
        $this->wp->updateOption(self::RESULT_OPTION_KEY, $result);
        $this->redirect($mailshotId, $idx, (string) ($this->wp->requestParam('test_email', '') ?? ''));
    }

    public function handleSendUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
        $idx = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
        $email = (string) ($this->wp->requestParam('test_email', '') ?? '');
        try {
            $result = $this->runService()->sendTest($mailshotId, $idx, $email);
        } catch (\Throwable $e) {
            $result = ['ok' => false, 'errors' => ['Send test failed: ' . $e->getMessage()]];
        }
        unset($result['rendered']);
        $result['ui_action'] = 'send';
        $this->wp->updateOption(self::RESULT_OPTION_KEY, $result);
        $this->redirect($mailshotId, $idx, $email);
    }

    private function redirect(int $mailshotId, int $recipientIndex, string $testEmail): void
    {
        $url = $this->wp->adminUrl('admin.php?page=feca-mailshots-test&mailshot_id=' . $mailshotId . '&recipient_index=' . $recipientIndex . '&test_email=' . rawurlencode($testEmail));
        if (!headers_sent()) {
            header('Location: ' . $url, true, 302);
            exit;
        }
    }

    /** @return array<string,mixed>|null */
    private function result(): ?array
    {
        $raw = $this->wp->getOption(self::RESULT_OPTION_KEY, null);
        $this->wp->deleteOption(self::RESULT_OPTION_KEY);
        return is_array($raw) ? $raw : null;
    }

    private function runService(): MailshotRunService
    {
        return ($this->runServiceFactory)();
    }

    private function mailshotService(): MailshotService
    {
        return ($this->mailshotServiceFactory)();
    }

    /**
     * @param list<array<string,mixed>> $rows
     * @return list<string>
     */
    private function sampleColumns(array $rows, int $maxColumns): array
    {
        if ($rows === [] || $maxColumns <= 0) {
            return [];
        }

        $firstRow = is_array($rows[0]['row'] ?? null) ? $rows[0]['row'] : [];
        if ($firstRow === []) {
            return [];
        }

        $selected = [];
        foreach (array_keys($firstRow) as $key) {
            $name = (string) $key;
            if ($name === '') {
                continue;
            }
            if ($this->isIdLikeField($name) || $this->isEmailLikeField($name)) {
                continue;
            }
            $selected[] = $name;
            if (count($selected) >= $maxColumns) {
                break;
            }
        }

        return $selected;
    }

    private function isIdLikeField(string $field): bool
    {
        $name = strtolower($field);
        return $name === 'id'
            || str_ends_with($name, '.id')
            || str_ends_with($name, '_id')
            || str_contains($name, 'accountid');
    }

    private function isEmailLikeField(string $field): bool
    {
        $name = strtolower($field);
        return $name === 'email' || str_ends_with($name, '.email') || str_contains($name, 'email');
    }

    /** @param mixed $value */
    private function displayCellValue($value): string
    {
        if ($value === null) {
            return '';
        }
        if (is_scalar($value)) {
            return trim((string) $value);
        }
        return json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '';
    }

    /**
     * @param list<array<string,mixed>> $rows
     * @return array{index:int,key:string,email:string}|array{}
     */
    private function selectedRecipientSummary(array $rows, int $recipientIndex): array
    {
        foreach ($rows as $row) {
            $idx = (int) ($row['index'] ?? -1);
            if ($idx !== $recipientIndex) {
                continue;
            }
            return [
                'index' => $idx,
                'key' => trim((string) ($row['recipient_key'] ?? '')),
                'email' => trim((string) ($row['recipient_email'] ?? '')),
            ];
        }
        return [];
    }

    /** @param array<string,mixed> $payload */
    private function debugJson(array $payload): string
    {
        $json = json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);
        if (is_string($json)) {
            return $json;
        }
        $err = function_exists('json_last_error_msg') ? json_last_error_msg() : 'unknown error';
        return '{"debug_error":"Failed to encode technical details: ' . $err . '"}';
    }
}
