<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator\Support;

use Ekesto\CacheAutopilot\Support\DebugLogger;

/**
 * Unified debug logging with dual-destination support.
 *
 * Authority hierarchy (any true → enabled):
 * 1. SupportLog::isSupportModeEnabled() — option-driven support mode
 * 2. SupportLog::isProductConstantEnabled() — EKESTO_CA_DEBUG
 * 3. ECI_DEBUG — plugin-level developer constant
 *
 * Destinations:
 * - Developer path (error_log): active when ECI_DEBUG or EKESTO_CA_DEBUG is set
 * - Support path (SupportLog::write): active when support mode or product constant is set
 */
final class Debug
{
    /** @var string Plugin-level developer constant name. */
    private const DEBUG_CONSTANT = 'ECI_DEBUG';

    /** @var string Plugin-level verbose constant name. */
    private const DEBUG_VERBOSE_CONSTANT = 'ECI_DEBUG_VERBOSE';

    /** @var string Optional plugin-level debug level constant name. */
    private const DEBUG_LEVEL_CONSTANT = 'ECI_DEBUG_LEVEL';

    /** @var string Optional product-level debug level constant name. */
    private const PRODUCT_DEBUG_LEVEL_CONSTANT = 'EKESTO_CA_DEBUG_LEVEL';

    /** @var string Prefix shown in log lines. */
    private const PREFIX = '[ECI]';

    /**
     * Whether any debug destination is active.
     *
     * Returns true if support mode, the product constant, or ECI_DEBUG is active.
     *
     * @return bool
     */
    public static function enabled(): bool
    {
        return DebugLogger::enabled(self::DEBUG_CONSTANT);
    }

    /**
     * Whether verbose debug logging is enabled.
     *
     * Verbose is developer-only. Requires an active developer constant
     * plus a verbose constant (ECI_DEBUG_VERBOSE or EKESTO_CA_DEBUG_VERBOSE).
     *
     * @return bool
     */
    public static function verboseEnabled(): bool
    {
        return DebugLogger::verboseEnabled(self::DEBUG_CONSTANT, self::DEBUG_VERBOSE_CONSTANT);
    }

    /**
     * Return active debug signal level.
     *
     * Resolution order:
     * 1) explicit verbose constants
     * 2) optional level constants (ECI_DEBUG_LEVEL / EKESTO_CA_DEBUG_LEVEL)
     * 3) fallback `normal` when debug is enabled
     *
     * @return string One of: minimal|normal|verbose
     */
    public static function level(): string
    {
        return DebugLogger::level(self::DEBUG_CONSTANT, self::DEBUG_VERBOSE_CONSTANT, self::levelConstants());
    }

    /**
     * Check whether the active debug level meets or exceeds the required level.
     *
     * @param string $requiredLevel Required level: minimal|normal|verbose.
     * @return bool
     */
    public static function allowsLevel(string $requiredLevel): bool
    {
        return DebugLogger::allowsLevel(
            self::DEBUG_CONSTANT,
            self::DEBUG_VERBOSE_CONSTANT,
            self::levelConstants(),
            $requiredLevel
        );
    }

    /**
     * Write a verbose debug log entry.
     *
     * Intended for high-noise diagnostic logging. Never writes to the support log.
     *
     * @param string               $message Log message.
     * @param array<string, mixed> $context Optional structured context.
     * @return void
     */
    public static function verbose(string $message, array $context = []): void
    {
        DebugLogger::verbose(
            self::PREFIX,
            self::DEBUG_CONSTANT,
            self::DEBUG_VERBOSE_CONSTANT,
            $message,
            $context,
            true,
            self::levelConstants()
        );
    }

    /**
     * Debug log with optional structured context.
     *
     * Level DEBUG: writes to error_log when developer constants are active.
     * Support log receives DEBUG entries when support mode or product constant is active.
     *
     * @param string               $message Log message.
     * @param array<string, mixed> $context Optional structured context.
     * @return void
     */
    public static function log(string $message, array $context = []): void
    {
        DebugLogger::log(
            self::PREFIX,
            self::DEBUG_CONSTANT,
            self::DEBUG_VERBOSE_CONSTANT,
            $message,
            $context,
            self::levelConstants()
        );
    }

    /**
     * Informational log entry — written to both destinations when active.
     *
     * @param string               $message Log message.
     * @param array<string, mixed> $context Optional structured context.
     * @return void
     */
    public static function info(string $message, array $context = []): void
    {
        DebugLogger::info(self::PREFIX, self::DEBUG_CONSTANT, $message, $context);
    }

    /**
     * Warning log entry — written to both destinations when active.
     *
     * @param string               $message Log message.
     * @param array<string, mixed> $context Optional structured context.
     * @return void
     */
    public static function warn(string $message, array $context = []): void
    {
        DebugLogger::warn(self::PREFIX, self::DEBUG_CONSTANT, $message, $context);
    }

    /**
     * Error log entry — written to both destinations when active.
     *
     * @param string               $message Log message.
     * @param array<string, mixed> $context Optional structured context.
     * @return void
     */
    public static function error(string $message, array $context = []): void
    {
        DebugLogger::error(self::PREFIX, self::DEBUG_CONSTANT, $message, $context);
    }

    /**
     * Return debug level constants in resolution order.
     *
     * @return string[]
     */
    private static function levelConstants(): array
    {
        return [
            self::DEBUG_LEVEL_CONSTANT,
            self::PRODUCT_DEBUG_LEVEL_CONSTANT,
        ];
    }
}
