<?php

declare(strict_types=1);

namespace FecaMailshots\WordPress;

final class FixtureWordPressFacade implements WordPressFacade
{
    /** @var array<string, list<callable>> */
    private array $actions = [];
    /** @var array<string, mixed> */
    private array $options = [];
    private string $optionsFile;
    private int $currentUserId = 1;
    /** @var array<string,bool>|null */
    private ?array $allowedCapabilities = null;

    public function __construct(?string $optionsFile = null)
    {
        $this->optionsFile = $optionsFile !== null && $optionsFile !== ''
            ? $optionsFile
            : (sys_get_temp_dir() . '/feca_mailshots_fixture_options.json');
        $this->options = $this->loadOptions();
    }

    public function addAction(string $hook, callable $callback): void
    {
        if (!isset($this->actions[$hook])) {
            $this->actions[$hook] = [];
        }
        $this->actions[$hook][] = $callback;
    }

    public function addMenuPage(string $pageTitle, string $menuTitle, string $capability, string $slug, callable $callback): void
    {
        $this->addAction('fixture_menu:' . $slug, $callback);
    }

    public function addSubmenuPage(string $parentSlug, string $pageTitle, string $menuTitle, string $capability, string $slug, callable $callback): void
    {
        $this->addAction('fixture_submenu:' . $slug, $callback);
    }

    public function currentUserCan(string $capability): bool
    {
        if ($this->allowedCapabilities === null) {
            return true;
        }
        return isset($this->allowedCapabilities[$capability]);
    }

    public function verifyNonce(string $nonce, string $action): bool
    {
        return $nonce !== '';
    }

    public function createNonce(string $action): string
    {
        return 'fixture-nonce-' . $action;
    }

    public function requestParam(string $name, ?string $default = null): ?string
    {
        if (isset($_POST[$name])) {
            return (string) $_POST[$name];
        }
        if (isset($_GET[$name])) {
            return (string) $_GET[$name];
        }
        return $default;
    }

    public function sendJson(array $payload, int $statusCode = 200): void
    {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        echo json_encode($payload, JSON_UNESCAPED_SLASHES);
    }

    public function adminUrl(string $path = ''): string
    {
        return '/wp-admin/' . ltrim($path, '/');
    }

    public function currentUserId(): int
    {
        return $this->currentUserId;
    }

    public function getOption(string $name, $default = null)
    {
        $this->options = $this->loadOptions();
        return $this->options[$name] ?? $default;
    }

    public function updateOption(string $name, $value): bool
    {
        $this->options = $this->loadOptions();
        $this->options[$name] = $value;
        $this->saveOptions();
        return true;
    }

    public function deleteOption(string $name): bool
    {
        $this->options = $this->loadOptions();
        unset($this->options[$name]);
        $this->saveOptions();
        return true;
    }

    public function dispatch(string $hook): void
    {
        foreach ($this->actions[$hook] ?? [] as $callback) {
            $callback();
        }
    }

    public function setCurrentUserId(int $userId): void
    {
        $this->currentUserId = max(1, $userId);
    }

    /** @param list<string> $capabilities */
    public function setAllowedCapabilities(array $capabilities): void
    {
        $map = [];
        foreach ($capabilities as $capability) {
            $key = trim((string) $capability);
            if ($key === '') {
                continue;
            }
            $map[$key] = true;
        }
        $this->allowedCapabilities = $map;
    }

    public function clearAllowedCapabilities(): void
    {
        $this->allowedCapabilities = null;
    }

    /** @return array<string,mixed> */
    private function loadOptions(): array
    {
        if (!is_file($this->optionsFile)) {
            return [];
        }
        $raw = @file_get_contents($this->optionsFile);
        if (!is_string($raw) || $raw === '') {
            return [];
        }
        $decoded = json_decode($raw, true);
        return is_array($decoded) ? $decoded : [];
    }

    private function saveOptions(): void
    {
        @file_put_contents($this->optionsFile, json_encode($this->options, JSON_UNESCAPED_SLASHES));
    }
}
