<?php

declare(strict_types=1);

namespace App\Framework\Auth;

/**
 * Password Validation Result Value Object
 *
 * Immutable result of password strength validation containing
 * errors, warnings, and strength assessment.
 */
final readonly class PasswordValidationResult
{
    /**
     * @param array<int, string> $errors
     * @param array<int, string> $warnings
     */
    public function __construct(
        public bool $isValid,
        public array $errors,
        public array $warnings,
        public int $strengthScore,
        public PasswordStrength $strength
    ) {
    }

    /**
     * Check if password has any errors
     */
    public function hasErrors(): bool
    {
        return ! empty($this->errors);
    }

    /**
     * Check if password has any warnings
     */
    public function hasWarnings(): bool
    {
        return ! empty($this->warnings);
    }

    /**
     * Get all issues (errors and warnings combined)
     * @return array<int, string>
     */
    public function getAllIssues(): array
    {
        return array_merge($this->errors, $this->warnings);
    }

    /**
     * Check if password meets minimum security requirements
     */
    public function meetsMinimumRequirements(): bool
    {
        return $this->isValid && $this->strengthScore >= 50;
    }

    /**
     * Check if password is recommended for use
     */
    public function isRecommended(): bool
    {
        return $this->isValid &&
               $this->strengthScore >= 70 &&
               empty($this->warnings);
    }

    /**
     * Get human-readable summary
     */
    public function getSummary(): string
    {
        if (! $this->isValid) {
            return 'Password does not meet requirements: ' . implode(', ', $this->errors);
        }

        if ($this->hasWarnings()) {
            return sprintf(
                'Password is %s but has suggestions: %s',
                $this->strength->getLabel(),
                implode(', ', $this->warnings)
            );
        }

        return sprintf(
            'Password is %s (score: %d/100)',
            $this->strength->getLabel(),
            $this->strengthScore
        );
    }

    /**
     * Convert to array for API responses
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'is_valid' => $this->isValid,
            'errors' => $this->errors,
            'warnings' => $this->warnings,
            'strength_score' => $this->strengthScore,
            'strength' => $this->strength->value,
            'strength_label' => $this->strength->getLabel(),
            'meets_minimum' => $this->meetsMinimumRequirements(),
            'is_recommended' => $this->isRecommended(),
        ];
    }

    /**
     * Create a valid result with no issues
     */
    public static function valid(int $strengthScore = 100): self
    {
        return new self(
            isValid: true,
            errors: [],
            warnings: [],
            strengthScore: $strengthScore,
            strength: self::calculateStrength($strengthScore)
        );
    }

    /**
     * Create an invalid result with errors
     * @param array<int, string> $errors
     */
    public static function invalid(array $errors, int $strengthScore = 0): self
    {
        return new self(
            isValid: false,
            errors: $errors,
            warnings: [],
            strengthScore: $strengthScore,
            strength: PasswordStrength::WEAK
        );
    }

    private static function calculateStrength(int $score): PasswordStrength
    {
        return match (true) {
            $score >= 90 => PasswordStrength::VERY_STRONG,
            $score >= 70 => PasswordStrength::STRONG,
            $score >= 50 => PasswordStrength::MODERATE,
            $score >= 30 => PasswordStrength::WEAK,
            default => PasswordStrength::WEAK
        };
    }
}
