<?php
/**
 * RenderException — Exception thrown by the render engine on fatal render errors.
 *
 * Used by RenderEngine, BaseRenderer and their subclasses to signal unrecoverable
 * rendering failures (missing required data, invalid component type, etc.).
 *
 * Callers can catch this exception to surface a graceful admin notice rather
 * than letting the error bubble up to a white-screen.
 *
 * @package UltraguardPro\view
 * @since   6.5.0
 */

namespace UltraguardPro\view;

if ( ! defined( 'ABSPATH' ) ) { exit; }

class RenderException extends \RuntimeException {

    /** @var string  Slug of the component/renderer that failed, e.g. 'card', 'table'. */
    private string $component;

    /** @var array<string,mixed>  Partial render context for debugging. */
    private array $context;

    /**
     * @param string          $message    Human-readable description of the render failure.
     * @param string          $component  Component type that threw (e.g. 'table', 'card').
     * @param array           $context    Partial render context (strip sensitive data before passing).
     * @param int             $code       Exception code (default: 0).
     * @param \Throwable|null $previous   Optional prior exception.
     */
    public function __construct(
        string     $message   = '',
        string     $component = 'unknown',
        array      $context   = [],
        int        $code      = 0,
        ?\Throwable $previous  = null
    ) {
        parent::__construct( $message, $code, $previous );
        $this->component = $component;
        $this->context   = $context;
    }

    /**
     * The component/renderer type that raised this exception.
     *
     * @return string  e.g. 'table', 'card', 'chart', 'form'
     */
    public function get_component(): string {
        return $this->component;
    }

    /**
     * Partial render context captured at the point of failure.
     * Useful for admin-facing debug notices.
     *
     * @return array<string,mixed>
     */
    public function get_context(): array {
        return $this->context;
    }

    /**
     * Create a RenderException for a missing required field in a scheme/config.
     *
     * @param  string $field      The missing field name.
     * @param  string $component  Component type.
     * @param  array  $context    Partial context.
     * @return static
     */
    public static function missing_field( string $field, string $component = 'unknown', array $context = [] ): static {
        return new static(
            sprintf( 'Required field "%s" missing in render scheme for component "%s".', $field, $component ),
            $component,
            $context
        );
    }

    /**
     * Create a RenderException for an unsupported component type.
     *
     * @param  string $type     The unrecognised type value.
     * @param  array  $context  Partial context.
     * @return static
     */
    public static function unsupported_type( string $type, array $context = [] ): static {
        return new static(
            sprintf( 'Unsupported render component type: "%s".', $type ),
            $type,
            $context
        );
    }

    /**
     * Create a RenderException for a template/partial that could not be loaded.
     *
     * @param  string $path     Absolute or relative path that was attempted.
     * @param  array  $context  Partial context.
     * @return static
     */
    public static function template_not_found( string $path, array $context = [] ): static {
        return new static(
            sprintf( 'Render template not found: "%s".', $path ),
            'template',
            $context
        );
    }
}
