<?php

declare(strict_types=1);

require_once __DIR__ . '/variant_stem_observation_grammar.php';

function mainStemHasMalformedObservationGrammar(string $text): bool
{
    $t = trim($text);
    if ($t === '') {
        return false;
    }
    if (variantStemHasClippedObservationGrammar($t)) {
        return true;
    }
    if (preg_match('/\bRespiratory rate\s+(?!is\s)\d+\s+breaths/i', $t)) {
        return true;
    }
    if (preg_match('/\ba respiratory rate\s+(?!of\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/\ban oxygen saturation\s+(?!of\s|is\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/\ba pulse\s+(?!of\s|is\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/\ba BP\s+(?!of\s)\d/i', $t)) {
        return true;
    }
    if (preg_match('/,\s*oxygen saturation\s+(?!is\s|of\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/\band\s+oxygen saturation\s+(?!is\s|of\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/(?:^|[.!?]\s+)Pulse\s+(?!is\s|of\s)\d+\s+bpm/i', $t)) {
        return true;
    }

    return false;
}

function mainStemHasMixedSentenceObservationMarkers(string $text): bool
{
    $t = trim($text);
    if ($t === '') {
        return false;
    }
    if (preg_match('/\b(?:pulse|blood pressure|BP|respiratory rate)\s+is\s+/i', $t)) {
        return true;
    }
    if (preg_match('/\b(?:His|Her|Their)\s+(?:pulse|respiratory rate|RR|BP|blood pressure)\s+(?!is\s|of\s)\d+/i', $t)) {
        return true;
    }
    if (preg_match('/(?:^|[.!?]\s+)Pulse\s+(?!is\s|of\s)\d+\s+bpm/i', $t)) {
        return true;
    }
    if (preg_match('/(?:^|[.!?]\s+)Respiratory rate\s+(?!is\s)\d+\s+breaths/i', $t)) {
        return true;
    }

    return false;
}

function mainStemRepairCombinedExaminationAndVitals(string $stem): string
{
    return (string) preg_replace_callback(
        '/\b(She|He) has ([^.,;]+?),\s*respiratory rate\s+(?!is\s|of\s)(\d+)\s+breaths per minute(?:\s+and\s+oxygen saturation\s+is\s+([^.;]+))?/i',
        static function (array $m): string {
            $pronoun = $m[1];
            $finding = trim($m[2]);
            $rr = $m[3];
            $o2 = $m[4] ?? '';
            $possessive = strcasecmp($pronoun, 'she') === 0 ? 'Her' : 'His';
            if (
                $finding !== ''
                && !preg_match('/\bon auscultation\b/i', $finding)
                && !preg_match('/\bon examination\b/i', $finding)
            ) {
                $finding .= ' on auscultation';
            }
            $tail = $possessive . ' respiratory rate is ' . $rr . ' breaths per minute';
            if ($o2 !== '') {
                $tail .= ' and oxygen saturation is ' . trim($o2);
            }

            return $pronoun . ' has ' . $finding . '. ' . $tail;
        },
        $stem
    );
}

function mainStemRepairStandaloneRespiratoryRate(string $stem): string
{
    return (string) preg_replace(
        '/(^|[.!?]\s+)(Respiratory rate)\s+(?!is\s)(\d+)(\s+breaths per minute)/i',
        '$1$2 is $3$4',
        $stem
    );
}

function mainStemRepairBareLeadingPulse(string $stem): string
{
    return (string) preg_replace(
        '/(^|[.!?]\s+)(Pulse)\s+(?!is\s|of\s)(\d+)(\s+bpm)/i',
        '$1$2 is $3$4',
        $stem
    );
}

function mainStemRepairMixedSentenceVitals(string $stem): string
{
    $inPossessiveVitalsChain = preg_match('/\b(?:His|Her|Their)\s+(?:temperature|temp)\s+is\s+/i', $stem)
        || preg_match('/\b(?:His|Her|Their)\s+pulse\s/i', $stem);
    if (!$inPossessiveVitalsChain) {
        return $stem;
    }
    $s = (string) preg_replace('/,\s*pulse\s+(?!is\s|of\s)(\d+)\s+bpm/i', ', pulse is $1 bpm', $stem);
    $s = (string) preg_replace('/,\s*BP\s+(\d+\s*\/\s*\d+\s*mmHg)/i', ', blood pressure is $1', $s);
    $s = (string) preg_replace(
        '/,\s*(?:a\s+)?respiratory rate\s+(?:of\s+)?(?!is\s)(\d+)\s+breaths per minute/i',
        ', respiratory rate is $1 breaths per minute',
        $s
    );

    return $s;
}

function mainStemRepairMalformedNounPhrases(string $stem): string
{
    $s = (string) preg_replace('/\ba respiratory rate\s+(?!of\s|is\s)(\d+)/i', 'a respiratory rate of $1', $stem);
    $s = (string) preg_replace('/\ban oxygen saturation\s+(?!of\s|is\s)(\d+)/i', 'an oxygen saturation of $1', $s);
    $s = (string) preg_replace('/\ba pulse\s+(?!of\s|is\s)(\d+)/i', 'a pulse of $1', $s);
    $s = (string) preg_replace('/\ba BP\s+(\d+\s*\/\s*\d+)/i', 'a blood pressure of $1', $s);
    $s = (string) preg_replace(
        '/\ba blood pressure\s+(?!of\s|is\s)(\d+\s*\/\s*\d+)/i',
        'a blood pressure of $1',
        $s
    );
    if (preg_match('/\b(?:She|He) has\b/i', $s) && preg_match('/\ba respiratory rate of\b/i', $s)) {
        $s = (string) preg_replace('/\band\s+oxygen saturation\s+is\s+(\d+)/i', 'and oxygen saturation of $1', $s);
    }

    return $s;
}

/**
 * @return array{stem: string, changed: bool, needs_review: bool}
 */
function mainNormalizeStemObservationGrammar(string $stem): array
{
    $original = $stem;
    $s = $stem;

    if (trim($s) === '') {
        return ['stem' => $s, 'changed' => false, 'needs_review' => false];
    }

    $s = mainStemRepairStandaloneRespiratoryRate($s);
    $s = mainStemRepairBareLeadingPulse($s);
    $s = mainStemRepairMalformedNounPhrases($s);
    $s = mainStemRepairCombinedExaminationAndVitals($s);
    $s = mainStemRepairMixedSentenceVitals($s);

    if (
        variantStemIsListStyleObservationPhrase($s)
        && !mainStemHasMalformedObservationGrammar($s)
        && !mainStemHasMixedSentenceObservationMarkers($s)
    ) {
        return [
            'stem' => $s,
            'changed' => $s !== $original,
            'needs_review' => false,
        ];
    }

    $variantNorm = variantNormalizeStemObservationGrammar($s);
    $s = $variantNorm['stem'];

    if (preg_match('/\b(?:His|Her|Their)\s+/i', $s)) {
        $s = (string) preg_replace(
            '/,\s*respiratory\s+rate\s+(?!is\s|of\s)(\d+)\s+breaths/i',
            ', respiratory rate is $1 breaths',
            $s
        );
    }

    return [
        'stem' => $s,
        'changed' => $s !== $original,
        'needs_review' => mainStemHasMalformedObservationGrammar($s),
    ];
}
