<?php

declare(strict_types=1);

namespace FecaMailshots\Admin;

use FecaMailshots\Application\AttachmentService;
use FecaMailshots\WordPress\WordPressFacade;

final class AttachmentsAdminPage
{
    use AdminRequestHelpers;

    private const CAPABILITY = 'edit_pages';
    private const RESULT_OPTION_KEY = 'feca_mailshots_attachments_ui_result';
    private const DRAFT_OPTION_KEY = 'feca_mailshots_attachments_ui_draft';
    private const PAGE_SLUG = 'feca-mailshots-attachments';
    private const NONCE_ACTION = 'feca_mailshots_attachments';
    /** @var callable(): AttachmentService */
    private $serviceFactory;
    private WordPressFacade $wp;

    /** @param callable(): AttachmentService $serviceFactory */
    public function __construct(callable $serviceFactory, WordPressFacade $wp)
    {
        $this->serviceFactory = $serviceFactory;
        $this->wp = $wp;
    }

    public function register(): void
    {
        $this->wp->addAction('admin_menu', [$this, 'registerMenu']);
        $this->wp->addAction('admin_post_feca_mailshots_attachments_api', [$this, 'handleApi']);
        $this->wp->addAction('admin_post_feca_mailshots_attachments_ui_save', [$this, 'handleUiSave']);
        $this->wp->addAction('admin_post_feca_mailshots_attachments_ui_delete', [$this, 'handleUiDelete']);
    }

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

    public function render(): void
    {
        if (!$this->wp->currentUserCan(self::CAPABILITY)) {
            echo 'Permission denied';
            return;
        }
        $items = $this->service()->list();
        $draft = $this->consumeOptionArray(self::DRAFT_OPTION_KEY);
        $editId = (int) ($this->wp->requestParam('edit_id', '0') ?? '0');
        if ($editId <= 0 && is_array($draft) && isset($draft['id'])) {
            $editId = (int) $draft['id'];
        }
        $editItem = null;
        foreach ($items as $row) {
            if ((int) ($row['id'] ?? 0) === $editId) {
                $editItem = $row;
                break;
            }
        }
        $result = $this->consumeOptionArray(self::RESULT_OPTION_KEY);
        $action = htmlspecialchars($this->wp->adminUrl('admin-post.php'));
        $name = (string) ($editItem['name'] ?? '');
        $fileName = (string) ($editItem['file_name'] ?? '');
        $base64 = '';
        if (is_array($draft)) {
            $name = (string) ($draft['name'] ?? $name);
            $fileName = (string) ($draft['file_name'] ?? $fileName);
            $base64 = (string) ($draft['file_bytes_base64'] ?? '');
        }

        echo '<div class="wrap"><h1>Attachments</h1>';
        if ($result !== null) {
            $ok = !empty($result['ok']);
            $bg = $ok ? '#f1f8e9' : '#ffebee';
            $border = $ok ? '#8bc34a' : '#ef9a9a';
            $title = $ok ? 'Attachment saved.' : 'Attachment action failed.';
            echo '<div style="padding:10px;border:1px solid ' . $border . ';background:' . $bg . ';margin:12px 0;">';
            echo '<strong>' . htmlspecialchars($title) . '</strong>';
            if (!empty($result['errors']) && is_array($result['errors'])) {
                echo '<p style="margin:6px 0 0 0;">' . htmlspecialchars(implode('; ', $result['errors'])) . '</p>';
            }
            echo '</div>';
        }

        echo '<p><button type="button" class="button button-primary" id="att-open-new">New Attachment</button></p>';
        echo '<div id="att-editor-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.4);z-index:9998;">';
        echo '<div style="max-width:900px;margin:30px auto;background:#fff;padding:12px;max-height:88vh;overflow:auto;">';
        echo '<p style="text-align:right;margin:0;"><button type="button" class="button" id="att-close-editor">Close</button></p>';
        echo '<form method="post" enctype="multipart/form-data" action="' . $action . '" style="padding:12px;border:1px solid #dcdcde;background:#fff;margin-bottom:12px;" id="att-editor-form">';
        echo '<h2 style="margin-top:0;">' . ($editId > 0 ? 'Edit Attachment' : 'New Attachment') . '</h2>';
        echo $this->modalErrorHtml($result);
        echo '<input type="hidden" name="action" value="feca_mailshots_attachments_ui_save">';
        echo $this->hiddenNonceField(self::NONCE_ACTION);
        if ($editId > 0) {
            echo '<input type="hidden" name="id" value="' . $editId . '" id="att-editor-id">';
        } else {
            echo '<input type="hidden" name="id" value="" id="att-editor-id">';
        }
        echo '<table class="form-table" role="presentation">';
        echo '<tr><th scope="row"><label for="att_name">Name</label></th><td><input class="regular-text" type="text" id="att_name" name="name" value="' . htmlspecialchars($name, ENT_QUOTES) . '"></td></tr>';
        echo '<tr><th scope="row"><label for="att_file_name">File Name</label></th><td><input class="regular-text" type="text" id="att_file_name" name="file_name" value="' . htmlspecialchars($fileName, ENT_QUOTES) . '"></td></tr>';
        echo '<tr><th scope="row"><label for="att_file_upload">Upload File</label></th><td><input type="file" id="att_file_upload" name="file_upload"></td></tr>';
        echo '<tr><th scope="row"><label for="att_base64">File Bytes (Base64)</label></th><td><textarea id="att_base64" name="file_bytes_base64" rows="4" class="large-text code">' . htmlspecialchars($base64) . '</textarea><p class="description">Provide base64 directly, or use file upload above.</p></td></tr>';
        echo '</table>';
        echo '<p><button type="submit" class="button button-primary">' . ($editId > 0 ? 'Update Attachment' : 'Create Attachment') . '</button> ';
        if ($editId > 0) {
            echo '<a class="button" href="' . htmlspecialchars($this->wp->adminUrl('admin.php?page=' . self::PAGE_SLUG)) . '">Cancel Edit</a>';
        }
        echo '</p></form>';
        echo '</div></div>';

        echo '<h2>Existing Attachments</h2>';
        echo '<table class="widefat striped"><thead><tr><th>ID</th><th>Name</th><th>File</th><th>MIME</th><th>Bytes</th><th>Actions</th></tr></thead><tbody>';
        foreach ($items as $row) {
            $id = (int) ($row['id'] ?? 0);
            $editUrl = $this->wp->adminUrl('admin.php?page=feca-mailshots-attachments&edit_id=' . $id);
            echo '<tr>';
            echo '<td>' . $id . '</td>';
            echo '<td>' . htmlspecialchars((string) ($row['name'] ?? '')) . '</td>';
            echo '<td>' . htmlspecialchars((string) ($row['file_name'] ?? '')) . '</td>';
            echo '<td>' . htmlspecialchars((string) ($row['mime_type'] ?? '')) . '</td>';
            echo '<td>' . htmlspecialchars((string) ($row['byte_size'] ?? '')) . '</td>';
            echo '<td><a class="button button-small" href="' . htmlspecialchars($editUrl) . '">Edit</a> ';
            echo '<form method="post" action="' . $action . '" style="display:inline;">';
            echo '<input type="hidden" name="action" value="feca_mailshots_attachments_ui_delete">';
            echo $this->hiddenNonceField(self::NONCE_ACTION);
            echo '<input type="hidden" name="id" value="' . $id . '">';
            echo '<button type="submit" class="button button-small" onclick="return confirm(\'Delete this attachment?\');">Delete</button>';
            echo '</form></td>';
            echo '</tr>';
        }
        if ($items === []) {
            echo '<tr><td colspan="6">No attachments found.</td></tr>';
        }
        echo '</tbody></table>';
        echo $this->modalEditorScript(
            'att-editor-modal',
            'att-open-new',
            'att-close-editor',
            'att-editor-form',
            'att-editor-id',
            ['att_name', 'att_file_name', 'att_base64'],
            $editId > 0,
            is_array($draft),
            $result !== null,
            !empty($result['ok']),
            null,
            null,
            'att_file_upload',
            'att_file_name'
        );
        echo '</div>';
    }

    public function handleUiSave(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $id = $this->requestOptionalInt('id');
        $uploadedBase64 = $this->uploadedFileToBase64('file_upload');
        $base64 = $uploadedBase64 !== null ? $uploadedBase64 : $this->requestString('file_bytes_base64', '');
        $payload = $this->attachmentPayload($base64);
        $result = $this->service()->save($id, $payload);
        $this->persistResultAndDraft(self::RESULT_OPTION_KEY, self::DRAFT_OPTION_KEY, $result, ['id' => $id] + $payload);
        $editId = $id;
        if (!empty($result['ok']) && isset($result['id'])) {
            $editId = (int) $result['id'];
        }
        $this->redirectToAdminPage(self::PAGE_SLUG, $editId);
    }

    public function handleUiDelete(): void
    {
        if (!$this->enforceMutationGuardOrJson(self::CAPABILITY, self::NONCE_ACTION)) {
            return;
        }
        $id = $this->requestInt('id', 0);
        $result = ['ok' => true];
        try {
            if ($id > 0) {
                $this->service()->delete($id);
            }
        } catch (\Throwable $e) {
            $result = ['ok' => false, 'errors' => [$e->getMessage()]];
        }
        $this->wp->updateOption(self::RESULT_OPTION_KEY, $result);
        $this->redirectToAdminPage(self::PAGE_SLUG);
    }

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

        $op = $this->requestString('op', 'list');

        try {
            $this->handleBasicCrudApi(
                $op,
                fn(): array => ['ok' => true, 'items' => $this->service()->list()],
                function (): array {
                    if (!$this->mutationGuardValid(self::CAPABILITY, self::NONCE_ACTION)) {
                        return ['ok' => false, 'error' => 'Mutation guard rejected request.'];
                    }
                    $id = $this->requestOptionalInt('id');
                    $payload = $this->attachmentPayload($this->requestString('file_bytes_base64', ''));
                    return $this->service()->save($id, $payload);
                },
                function (): array {
                    if (!$this->mutationGuardValid(self::CAPABILITY, self::NONCE_ACTION)) {
                        return ['ok' => false, 'error' => 'Mutation guard rejected request.'];
                    }
                    $id = $this->requestInt('id', 0);
                    $this->service()->delete($id);
                    return ['ok' => true];
                }
            );
        } catch (\Throwable $e) {
            $this->wp->sendJson(['ok' => false, 'error' => $e->getMessage()], 500);
        }
    }

    private function service(): AttachmentService
    {
        return ($this->serviceFactory)();
    }

    /** @return array{name:string,file_name:string,mime_type:string,file_bytes_base64:string} */
    private function attachmentPayload(string $base64): array
    {
        return [
            'name' => $this->requestString('name', ''),
            'file_name' => $this->requestString('file_name', ''),
            'mime_type' => $this->requestString('mime_type', ''),
            'file_bytes_base64' => $base64,
        ];
    }

}
