<?php

namespace WPSN\Modules\Diagnostics;

defined('ABSPATH') || exit;

/**
 * Stores external platform probe reports (latest + small history ring buffer).
 *
 * Reports are sanitized before storage to avoid large payloads in wp_options.
 */
final class PlatformOpsReportRepository
{
    public const LAST_OPTION = 'wpsn_platform_ops_last_results';
    public const HISTORY_OPTION = 'wpsn_platform_ops_history';
    public const PINNED_ID_OPTION = 'wpsn_platform_ops_pinned_run_id';
    public const PINNED_OPTION = 'wpsn_platform_ops_pinned_run';
    public const MAX_ITEMS = 20;

    /**
     * @param array<string,mixed> $report
     */
    public function save(array $report): void
    {
        $safe = $this->sanitizePayload($report);
        update_option(self::LAST_OPTION, $safe, false);

        $id = isset($safe['id']) ? trim((string) $safe['id']) : '';
        if ($id !== '' && $id === $this->getPinnedId()) {
            update_option(self::PINNED_OPTION, $safe, false);
        }

        $history = get_option(self::HISTORY_OPTION, []);
        $history = is_array($history) ? $history : [];

        $filtered = [];
        foreach ($history as $row) {
            if (!is_array($row)) {
                continue;
            }
            if ($id !== '' && (string) ($row['id'] ?? '') === $id) {
                continue;
            }
            $filtered[] = $row;
        }

        array_unshift($filtered, $safe);
        if (count($filtered) > self::MAX_ITEMS) {
            $filtered = array_slice($filtered, 0, self::MAX_ITEMS);
        }

        update_option(self::HISTORY_OPTION, $filtered, false);
    }

    /**
     * @return array<string,mixed>
     */
    public function getLast(): array
    {
        $row = get_option(self::LAST_OPTION, []);
        return is_array($row) ? $row : [];
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    public function getHistory(int $limit = 10): array
    {
        $limit = max(1, min(100, $limit));
        $rows = get_option(self::HISTORY_OPTION, []);
        if (!is_array($rows)) {
            return [];
        }

        $out = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $out[] = $row;
            if (count($out) >= $limit) {
                break;
            }
        }

        return $out;
    }

    /**
     * @return array<string,mixed>
     */
    public function get(string $id): array
    {
        $id = trim((string) $id);
        if ($id === '') {
            return [];
        }

        $pinned = $this->getPinnedOptionRow();
        if (!empty($pinned) && (string) ($pinned['id'] ?? '') === $id) {
            return $pinned;
        }

        return $this->getFromSavedRuns($id);
    }

    /**
     * @param array<string,mixed> $report
     */
    public function pin(array $report): void
    {
        $safe = $this->sanitizePayload($report);
        $id = isset($safe['id']) ? trim((string) $safe['id']) : '';
        if ($id === '') {
            return;
        }

        update_option(self::PINNED_ID_OPTION, $id, false);
        update_option(self::PINNED_OPTION, $safe, false);
    }

    public function unpin(): void
    {
        delete_option(self::PINNED_ID_OPTION);
        delete_option(self::PINNED_OPTION);
    }

    public function getPinnedId(): string
    {
        $id = get_option(self::PINNED_ID_OPTION, '');
        if (is_string($id) && trim($id) !== '') {
            return trim($id);
        }

        $row = $this->getPinnedOptionRow();
        return !empty($row['id']) ? (string) $row['id'] : '';
    }

    /**
     * @return array<string,mixed>
     */
    public function getPinned(): array
    {
        $row = $this->getPinnedOptionRow();
        if (!empty($row)) {
            return $row;
        }

        $id = $this->getPinnedId();
        if ($id === '') {
            return [];
        }

        $row = $this->getFromSavedRuns($id);
        if (!empty($row)) {
            $this->pin($row);
        }

        return $row;
    }

    public function clear(bool $includePinned = false): void
    {
        delete_option(self::LAST_OPTION);
        delete_option(self::HISTORY_OPTION);

        if ($includePinned) {
            $this->unpin();
        }
    }

    /**
     * @return array<string,mixed>
     */
    private function getFromSavedRuns(string $id): array
    {
        $id = trim((string) $id);
        if ($id === '') {
            return [];
        }

        $last = $this->getLast();
        if (!empty($last) && (string) ($last['id'] ?? '') === $id) {
            return $last;
        }

        foreach ($this->getHistory(self::MAX_ITEMS) as $row) {
            if ((string) ($row['id'] ?? '') === $id) {
                return $row;
            }
        }

        return [];
    }

    /**
     * @return array<string,mixed>
     */
    private function getPinnedOptionRow(): array
    {
        $row = get_option(self::PINNED_OPTION, []);
        if (!is_array($row) || empty($row['id'])) {
            return [];
        }

        return $row;
    }

    /**
     * @param mixed $value
     * @return mixed
     */
    private function sanitizePayload($value)
    {
        if (is_array($value)) {
            $out = [];
            foreach ($value as $k => $v) {
                if (is_string($k) && in_array($k, ['raw', 'body', 'body_raw', 'payload_raw'], true)) {
                    continue;
                }
                $out[$k] = $this->sanitizePayload($v);
            }
            return $out;
        }

        if (is_string($value)) {
            if (strlen($value) > 8000) {
                return substr($value, 0, 8000) . '…';
            }
            return $value;
        }

        if (is_scalar($value) || $value === null) {
            return $value;
        }

        return null;
    }
}
