<?php

declare(strict_types=1);

namespace App\Framework\LiveComponents\Exceptions;

use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\LiveComponents\Validation\DerivedSchema;

/**
 * Exception thrown when component state validation fails
 *
 * Framework Integration:
 * - Extends FrameworkException for consistent error handling
 * - Includes rich context about validation failures
 * - Provides user-friendly error messages
 * - Supports debugging with detailed field-level errors
 */
final class StateValidationException extends FrameworkException
{
    /**
     * Create exception for type mismatch
     *
     * @param string $componentName Component name
     * @param string $field Field name with type mismatch
     * @param string $expectedType Expected type from schema
     * @param string $actualType Actual type received
     */
    public static function typeMismatch(
        string $componentName,
        string $field,
        string $expectedType,
        string $actualType
    ): self {
        $message = "State validation failed for '{$componentName}': " .
                   "Field '{$field}' expects type '{$expectedType}' but got '{$actualType}'";

        return self::create(ErrorCode::VAL_INVALID_FORMAT, $message)
            ->withData([
                'component' => $componentName,
                'field' => $field,
                'expected_type' => $expectedType,
                'actual_type' => $actualType,
                'validation_type' => 'type_mismatch',
            ])
            ->withMetadata([
                'validation_error' => true,
                'log_level' => 'warning',
            ]);
    }

    /**
     * Create exception for missing required field
     *
     * @param string $componentName Component name
     * @param string $field Missing field name
     * @param DerivedSchema $schema Expected schema
     */
    public static function missingField(
        string $componentName,
        string $field,
        DerivedSchema $schema
    ): self {
        $message = "State validation failed for '{$componentName}': " .
                   "Required field '{$field}' is missing";

        return self::create(ErrorCode::VAL_REQUIRED_FIELD_MISSING, $message)
            ->withData([
                'component' => $componentName,
                'missing_field' => $field,
                'expected_fields' => $schema->getFields(),
                'validation_type' => 'missing_field',
            ])
            ->withMetadata([
                'validation_error' => true,
                'log_level' => 'warning',
            ]);
    }

    /**
     * Create exception for unexpected field
     *
     * @param string $componentName Component name
     * @param string $field Unexpected field name
     * @param DerivedSchema $schema Expected schema
     */
    public static function unexpectedField(
        string $componentName,
        string $field,
        DerivedSchema $schema
    ): self {
        $message = "State validation failed for '{$componentName}': " .
                   "Unexpected field '{$field}' not in schema";

        return self::create(ErrorCode::VAL_INVALID_FORMAT, $message)
            ->withData([
                'component' => $componentName,
                'unexpected_field' => $field,
                'allowed_fields' => $schema->getFields(),
                'validation_type' => 'unexpected_field',
            ])
            ->withMetadata([
                'validation_error' => true,
                'log_level' => 'warning',
            ]);
    }

    /**
     * Create exception for multiple validation errors
     *
     * @param string $componentName Component name
     * @param array<string> $errors List of validation errors
     */
    public static function multipleErrors(
        string $componentName,
        array $errors
    ): self {
        $message = "State validation failed for '{$componentName}' with " .
                   count($errors) . " error(s)";

        return self::create(ErrorCode::VAL_INVALID_FORMAT, $message)
            ->withData([
                'component' => $componentName,
                'error_count' => count($errors),
                'errors' => $errors,
                'validation_type' => 'multiple_errors',
            ])
            ->withMetadata([
                'validation_error' => true,
                'log_level' => 'warning',
            ]);
    }

    /**
     * Get user-friendly error message (safe for client-side display)
     */
    public function getUserMessage(): string
    {
        return match ($this->getErrorCode()) {
            ErrorCode::VAL_REQUIRED_FIELD_MISSING => 'Required field is missing',
            ErrorCode::VAL_INVALID_FORMAT => 'Invalid state format',
            default => 'State validation failed'
        };
    }

    /**
     * Get validation errors for debugging
     *
     * @return array<string>
     */
    public function getValidationErrors(): array
    {
        $data = $this->getData();

        return $data['errors'] ?? [$this->getMessage()];
    }

    /**
     * Get affected field (if single-field error)
     */
    public function getField(): ?string
    {
        $data = $this->getData();

        return $data['field'] ?? $data['missing_field'] ?? $data['unexpected_field'] ?? null;
    }
}
