<?php

namespace App\Support;

class GradingMarkBoxCounter
{
    public function countFillBlanks(?string $text): int
    {
        $text = (string) $text;
        $count = 0;
        $count += preg_match_all('/_{2,}/u', $text, $m);
        $count += preg_match_all('/（\s*）/u', $text, $m);
        $count += preg_match_all('/\(\s*\)/', $text, $m);

        return max(1, $count);
    }

    public function countAnswerSteps(?string $text, ?string $stem = null): int
    {
        $stepCount = $this->countExplicitAnswerSteps($text);
        if ($stepCount > 0) {
            return $stepCount;
        }

        return $this->inferSubQuestionCount($stem);
    }

    /**
     * 判题卡解答题方框数：
     * - 优先按题干小题编号系列计数（(1)(2)...）
     * - 若不存在系列小题，则固定 1 框（避免被解析步骤数放大）
     */
    public function countAnswerMarkBoxes(?string $stem, ?string $solution = null): int
    {
        $minFromStem = $this->inferSubQuestionCount($stem);
        $stepCount = $this->countExplicitAnswerSteps($solution);

        return max($minFromStem, $stepCount > 0 ? $stepCount : 1);
    }

    /**
     * 仅识别“显式步骤标记”并计数：
     * - 步骤1: / 步骤一：
     * - 第1步: / 第一步：
     * 要求位于段首（行首或标点后），降低误判。
     */
    private function countExplicitAnswerSteps(?string $text): int
    {
        $text = trim((string) $text);
        if ($text === '') {
            return 0;
        }

        $text = preg_replace('/<br\s*\/?>/iu', "\n", $text) ?? $text;
        $stepLabelPattern = '(步骤\s*[0-9一二三四五六七八九十百零两]+\s*[：:]?)';
        $anchorPattern = '/(?:^|[\r\n。；;！？!?])\s*' . $stepLabelPattern . '/u';
        preg_match_all($anchorPattern, $text, $matches);
        $count = count($matches[0] ?? []);

        return max(0, $count);
    }

    /**
     * 当解析里没有步骤时，按题干中的小题“系列编号”估算判题卡方框数。
     * 仅在至少出现 2 个编号时生效，避免误把 f(1) 这类数学表达当作小题。
     */
    private function inferSubQuestionCount(?string $stem): int
    {
        $stem = (string) $stem;
        if ($stem === '') {
            return 1;
        }

        preg_match_all('/[（(][1-9][0-9]*[）)]/u', $stem, $allMarkers);
        $markerCount = count($allMarkers[0] ?? []);
        if ($markerCount < 2) {
            return 1;
        }

        // 与题干显示层保持一致：把小题起始语境标准化到 <br>(n)
        $normalized = preg_replace('/^\s*([（(][1-9][0-9]*[）)])\s*/u', '$1 ', $stem) ?? $stem;
        $normalized = preg_replace('/([。；;！？!?:：.])\s*([（(][1-9][0-9]*[）)])\s*/u', '$1<br>$2 ', $normalized) ?? $normalized;
        $normalized = preg_replace('/(?:(?:\\\\r\\\\n|\\\\n)|(?:\r?\n)|(?:<br\s*\/?>)|\s)+\s*([（(][1-9][0-9]*[）)])\s*/u', '<br>$1 ', $normalized) ?? $normalized;
        $normalized = preg_replace('/(求出|求解|求|写出|计算|证明|判断|化简)\s*([（(][1-9][0-9]*[）)])\s*/u', '$1<br>$2 ', $normalized) ?? $normalized;

        // 统计“行首或换行后”的编号数量，作为子题数量
        preg_match_all('/(?:^|<br>\s*)([（(][1-9][0-9]*[）)])/u', $normalized, $series);
        $seriesCount = count($series[1] ?? []);

        return max(1, $seriesCount);
    }
}
