<?php

declare(strict_types=1);

namespace App\Services\Install;

/**
 * Super-admin 비밀번호 정책.
 *
 * zxcvbn 라이브러리가 없는 환경을 위해 자체 휴리스틱 score (0~4) 를 산출:
 *   - 길이 >=12 (+1), >=16 (+2)
 *   - 대문자/소문자/숫자/기호 4종 (+2)
 *   - 흔한 패턴 (12345, qwerty 등) 매칭 시 penalty
 *
 * 통과 기준: score >= 3
 */
final class PasswordPolicy
{
    /** @var list<string> 흔한 패턴 — 정규식 substring */
    private const COMMON_PATTERNS = [
        'password', '12345', 'qwerty', 'admin', 'wdot', 'letmein', 'iloveyou',
    ];

    /**
     * @return array{score:int, passed:bool, feedback:list<string>}
     */
    public function evaluate(string $password): array
    {
        $score = 0;
        $feedback = [];
        $len = strlen($password);

        if ($len >= 12) {
            $score += 1;
        } else {
            $feedback[] = '최소 12 자 이상 필요합니다.';
        }
        if ($len >= 16) {
            $score += 1;
        }

        $classes = 0;
        if (preg_match('/[a-z]/', $password)) $classes++;
        if (preg_match('/[A-Z]/', $password)) $classes++;
        if (preg_match('/[0-9]/', $password)) $classes++;
        if (preg_match('/[^a-zA-Z0-9]/', $password)) $classes++;

        if ($classes >= 3) {
            $score += 1;
        } else {
            $feedback[] = '대문자, 소문자, 숫자, 기호 중 3 종류 이상 포함하세요.';
        }
        if ($classes === 4) {
            $score += 1;
        }

        $lower = strtolower($password);
        foreach (self::COMMON_PATTERNS as $pattern) {
            if (str_contains($lower, $pattern)) {
                $score -= 1;
                $feedback[] = "흔한 패턴이 포함되어 있습니다: '{$pattern}'";
                break;
            }
        }

        $score = max(0, min(4, $score));
        $passed = $score >= 3;

        if ($passed && $feedback === []) {
            $feedback[] = '강한 비밀번호입니다.';
        }

        return [
            'score'    => $score,
            'passed'   => $passed,
            'feedback' => $feedback,
        ];
    }
}
