<?php

declare(strict_types=1);

namespace FecaMailshots\Admin;

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

final class RunMailshotAdminPage
{
    use AdminRequestHelpers;

    private const RESULT_OPTION_KEY = 'feca_mailshots_run_ui_result';
    private const CAPABILITY = 'edit_pages';
    private const NONCE_ACTION = 'feca_mailshots_run';

    /** @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_run_api', [$this, 'handleApi']);
        $this->wp->addAction('admin_post_feca_mailshots_run_execute_ui', [$this, 'handleRunUi']);
        $this->wp->addAction('admin_post_feca_mailshots_run_selected_ui', [$this, 'handleRunSelectedUi']);
        $this->wp->addAction('admin_post_feca_mailshots_retry_failed_ui', [$this, 'handleRetryFailedUi']);
        $this->wp->addAction('admin_post_feca_mailshots_retry_recipient_ui', [$this, 'handleRetryRecipientUi']);
    }

    public function registerMenu(): void
    {
        $this->wp->addSubmenuPage('feca-mailshot', 'Run Mailshot', 'Run Mailshot', self::CAPABILITY, 'feca-mailshots-run', [$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');
        if ($selectedMailshotId <= 0 && $mailshots !== []) {
            $selectedMailshotId = (int) ($mailshots[0]['id'] ?? 0);
        }

        $result = $this->result();
        $lastRunRows = $selectedMailshotId > 0 ? $this->mailshotService()->lastRun($selectedMailshotId) : [];
        $recipientSummary = $selectedMailshotId > 0 ? $this->runService()->recipientCount($selectedMailshotId) : ['ok' => false, 'errors' => ['No mailshot selected.']];
        $runCount = !empty($recipientSummary['ok']) ? (int) ($recipientSummary['count'] ?? 0) : 0;
        $action = htmlspecialchars($this->wp->adminUrl('admin-post.php'));

        echo '<div class="wrap feca-mailshots-admin"><h1>Run Mailshot</h1>';
        echo $this->renderAdminUiStyles();
        echo '<p>Execute full sends and retry failures from the current mailshot last-run rows.</p>';

        if ($result !== null) {
            $ok = !empty($result['ok']);
            $bannerClass = $ok ? 'feca-banner-success' : 'feca-banner-error';
            echo '<div class="feca-banner ' . $bannerClass . '">';
            echo '<strong>' . ($ok ? 'Run action completed.' : 'Run action failed.') . '</strong>';
            if ($ok) {
                echo '<p>attempted=' . (int) ($result['attempted'] ?? 0)
                    . ', sent=' . (int) ($result['sent'] ?? 0)
                    . ', failed=' . (int) ($result['failed'] ?? 0)
                    . ', warnings=' . (int) ($result['warnings'] ?? 0)
                    . ', skipped=' . (int) ($result['skipped'] ?? 0)
                    . '</p>';
            }
            if (!empty($result['errors']) && is_array($result['errors'])) {
                echo '<p class="feca-banner-note">' . htmlspecialchars(implode('; ', $result['errors'])) . '</p>';
            }
            echo '</div>';
        }

        echo '<div class="feca-panel">';
        echo '<h2 class="feca-section-title">1. Select Mailshot</h2>';
        echo '<form method="get" action="' . htmlspecialchars($this->wp->adminUrl('admin.php')) . '" id="run-mailshot-picker">';
        echo '<input type="hidden" name="page" value="feca-mailshots-run">';
        echo '<div class="feca-control-row">';
        echo '<div class="feca-control feca-control-min-360">';
        echo '<label for="run_mailshot_id"><strong>Mailshot</strong></label>';
        echo '<select id="run_mailshot_id" name="mailshot_id" onchange="document.getElementById(\'run-mailshot-picker\').submit();">';
        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></div>';
        echo '</form>';
        if (!empty($recipientSummary['ok'])) {
            echo '<p class="feca-banner-note"><strong>Recipient rows:</strong> ' . (int) ($recipientSummary['count'] ?? 0) . '</p>';
        } elseif (!empty($recipientSummary['errors']) && is_array($recipientSummary['errors'])) {
            echo '<p class="feca-banner-note feca-note-danger"><strong>Recipient count failed:</strong> ' . htmlspecialchars(implode('; ', $recipientSummary['errors'])) . '</p>';
        }
        echo '</div>';

        $reviewUrl = $this->wp->adminUrl('admin.php?page=feca-mailshots-review-recipients');
        echo '<form method="post" action="' . $action . '" class="feca-form" id="feca-run-actions-form">';
        echo '<h2 class="feca-section-title">2. Run Actions</h2>';
        echo $this->hiddenNonceField(self::NONCE_ACTION);
        echo '<input type="hidden" name="mailshot_id" value="' . $selectedMailshotId . '">';
        echo '<input type="hidden" name="selected_recipient_keys" id="run_selected_recipient_keys" value="[]">';
        echo '<p class="feca-button-row">';
        echo '<button class="button button-primary" type="submit" name="action" value="feca_mailshots_run_execute_ui" onclick="return confirm(\'Run Mailshot for ' . $runCount . ' recipients?\');">Run Mailshot</button> ';
        echo '<button class="button" type="submit" name="action" value="feca_mailshots_run_selected_ui" id="run-mailshot-selected-btn">Run Mailshot to Selected Rows</button> ';
        echo '<button class="button" type="submit" name="action" value="feca_mailshots_retry_failed_ui" onclick="return confirm(\'Retry all failed recipients for this mailshot?\');">Retry Failed Sends</button>';
        echo '</p>';
        echo '<p class="feca-banner-note">Select rows for mailshot in <a href="' . htmlspecialchars($reviewUrl, ENT_QUOTES) . '">Review Recipients</a> page.</p>';
        echo '</form>';
        echo '<script>';
        echo '(function(){';
        echo 'var form=document.getElementById("feca-run-actions-form");';
        echo 'if(!form){return;}';
        echo 'var selectedBtn=document.getElementById("run-mailshot-selected-btn");';
        echo 'var selectedInput=document.getElementById("run_selected_recipient_keys");';
        echo 'var source=' . json_encode((string) ($this->selectedMailshotDataSource($mailshots, $selectedMailshotId)), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ';';
        echo 'var keyPrefix="fecaReviewRecipientsSelection::";';
        echo 'if(selectedBtn){selectedBtn.addEventListener("click",function(ev){';
        echo 'var keys=[];';
        echo 'try{if(source){var raw=sessionStorage.getItem(keyPrefix+source);if(raw){var parsed=JSON.parse(raw);if(parsed&&typeof parsed==="object"){keys=Object.keys(parsed).filter(function(k){return !!parsed[k];});}}}}catch(_){keys=[];}';
        echo 'if(selectedInput){selectedInput.value=JSON.stringify(keys);}';
        echo 'if(keys.length===0){ev.preventDefault();window.alert("No selected rows found. Select rows in Review Recipients first.");return false;}';
        echo 'return window.confirm("Run Mailshot to "+keys.length+" selected rows?");';
        echo '});}';
        echo '})();';
        echo '</script>';

        echo '<div class="feca-panel">';
        echo '<h2 class="feca-section-title">3. Last Run Rows</h2>';
        if ($lastRunRows === []) {
            echo '<p>No rows in mailshot_last_run for this mailshot.</p>';
        } else {
            echo '<div class="feca-scroll-frame"><div class="feca-scroll-pane">';
            echo '<table class="widefat striped"><thead><tr><th>Recipient Key</th><th>Email</th><th>Status</th><th>Attempts</th><th>Error/Warning</th><th>Retry</th></tr></thead><tbody>';
            foreach ($lastRunRows as $row) {
                $recipientKey = (string) ($row['recipient_key'] ?? '');
                $status = (string) ($row['status'] ?? '');
                $msg = (string) (($row['error_message'] ?? '') ?: ($row['warning_message'] ?? ''));
                echo '<tr>';
                echo '<td>' . htmlspecialchars($recipientKey) . '</td>';
                echo '<td>' . htmlspecialchars((string) ($row['recipient_email_last'] ?? '')) . '</td>';
                echo '<td>' . htmlspecialchars($status) . '</td>';
                echo '<td>' . (int) ($row['attempt_count'] ?? 0) . '</td>';
                echo '<td>' . htmlspecialchars($msg) . '</td>';
                echo '<td>';
                if ($status === 'failed') {
                    echo '<form method="post" action="' . $action . '">';
                    echo '<input type="hidden" name="action" value="feca_mailshots_retry_recipient_ui">';
                    echo $this->hiddenNonceField(self::NONCE_ACTION);
                    echo '<input type="hidden" name="mailshot_id" value="' . $selectedMailshotId . '">';
                    echo '<input type="hidden" name="recipient_key" value="' . htmlspecialchars($recipientKey, ENT_QUOTES) . '">';
                    echo '<button class="button" type="submit" onclick="return confirm(\'Retry this failed recipient now?\');">Retry</button>';
                    echo '</form>';
                }
                echo '</td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
            echo '</div></div>';
        }
        echo '</div>';

        echo '</div>';
    }

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

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

        try {
            if ($op === 'run_mailshot') {
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $this->wp->sendJson($service->runMailshot($mailshotId));
                return;
            }

            if ($op === 'run_mailshot_selected') {
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $selectedRecipientKeys = $this->selectedRecipientKeysFromRequest();
                $this->wp->sendJson($service->runMailshotSelected($mailshotId, $selectedRecipientKeys));
                return;
            }

            if ($op === 'retry_failed') {
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $this->wp->sendJson($service->retryFailed($mailshotId));
                return;
            }

            if ($op === 'retry_recipient') {
                $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
                $recipientKey = (string) ($this->wp->requestParam('recipient_key', '') ?? '');
                $this->wp->sendJson($service->retryRecipient($mailshotId, $recipientKey));
                return;
            }

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

    public function handleRunUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $this->handleRunAction(static fn(self $page, int $mailshotId): array => $page->runService()->runMailshot($mailshotId));
    }

    public function handleRunSelectedUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $this->handleRunAction(static function (self $page, int $mailshotId): array {
            return $page->runService()->runMailshotSelected($mailshotId, $page->selectedRecipientKeysFromRequest());
        });
    }

    public function handleRetryFailedUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $this->handleRunAction(static fn(self $page, int $mailshotId): array => $page->runService()->retryFailed($mailshotId));
    }

    public function handleRetryRecipientUi(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $this->handleRunAction(static function (self $page, int $mailshotId): array {
            $recipientKey = (string) ($page->wp->requestParam('recipient_key', '') ?? '');
            return $page->runService()->retryRecipient($mailshotId, $recipientKey);
        });
    }

    /** @param callable(self,int):array<string,mixed> $action */
    private function handleRunAction(callable $action): void
    {
        $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0');
        $completed = false;
        $fatalHandled = false;

        register_shutdown_function(function () use (&$completed, &$fatalHandled, $mailshotId): void {
            if ($completed || $fatalHandled) {
                return;
            }
            $error = error_get_last();
            if (!is_array($error) || !in_array((int) ($error['type'] ?? 0), [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
                return;
            }
            $fatalHandled = true;
            $this->storeRunFailure('Run action failed: ' . (string) ($error['message'] ?? 'Unknown fatal error.'));
            $this->redirect($mailshotId);
        });

        try {
            $result = $action($this, $mailshotId);
        } catch (\Throwable $e) {
            $result = ['ok' => false, 'errors' => ['Run action failed: ' . $e->getMessage()]];
        }

        $completed = true;
        $this->wp->updateOption(self::RESULT_OPTION_KEY, $result);
        $this->redirect($mailshotId);
    }

    private function storeRunFailure(string $message): void
    {
        try {
            $this->wp->updateOption(self::RESULT_OPTION_KEY, ['ok' => false, 'errors' => [$message]]);
        } catch (\Throwable $e) {
            error_log('Mailshots run failure could not be stored: ' . $e->getMessage());
        }
    }

    private function redirect(int $mailshotId): void
    {
        $url = $this->wp->adminUrl('admin.php?page=feca-mailshots-run&mailshot_id=' . $mailshotId);
        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>> $mailshots */
    private function selectedMailshotDataSource(array $mailshots, int $mailshotId): string
    {
        foreach ($mailshots as $mailshot) {
            if ((int) ($mailshot['id'] ?? 0) === $mailshotId) {
                return trim((string) ($mailshot['DataSource'] ?? ''));
            }
        }
        return '';
    }

    /** @return list<string> */
    private function selectedRecipientKeysFromRequest(): array
    {
        $raw = trim((string) ($this->wp->requestParam('selected_recipient_keys', '[]') ?? '[]'));
        if ($raw === '') {
            return [];
        }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return [];
        }
        $out = [];
        foreach ($decoded as $value) {
            $key = trim((string) $value);
            if ($key !== '') {
                $out[] = $key;
            }
        }
        return array_values(array_unique($out));
    }
}
