"""
Large regression benchmark for StreamingQuranMatcher vs indexed baseline.

This test is intentionally slow because it runs both:
1) QuranValidator.scan_for_verses() baseline
2) StreamingQuranMatcher on the same chunk stream

Run explicitly:
    IJAZA_RUN_LARGE_BENCHMARK=1 pytest -s tests/test_stream_matcher_large_regression.py
"""

from __future__ import annotations

import os
import time
from collections import Counter
from dataclasses import dataclass
from statistics import mean

import pytest

from ijaza import QuranValidator, StreamingQuranMatcher, StreamingQuranMatcherOptions
from ijaza.types import ValidatorOptions


CHUNKS_PRE_ENDING_42 = [
    "وان اشغلكم هذه المقدمة سبحان الله وقت المقدمة، ان شاء الله جمعا\nسقت لكم هذه المقدمة لأخذ بيدي وما بنفسي إلى معنى مهم جدا النقل عنه\nوهي حال مقتضاه الله عز وجل سبحانه وتعالى في ذكره عندما تكلم عن أهل رمضان\nيقول الله عز وجل وهل انتبهوا شهر رمضان الشهر الوحيد الذي ذكر اسمه",
    "وذكر اسمه في القرآن وذكر في سياق آية السمع يا أيها الذين آمنوا كتب عليكم الصيام\nعليك صيام كما كتب على الذين من قبلكم لعلكم ترون أيام معدودات\nثم بعد ذلك يم الله عز وجل شهر رمضان بسياق السن فلينتظر الإيمان أيش أن يقول\nأن يقول الله عز وجل تهو رمضان الذي فشل وهش أليس هذا مداخل",
    "ليس هذا المنتظم كتبت عليك ثم بات لك بوصيل اطالة\nفي الإطار الزمني المعظم من الكلام أن في الإطار الزمني يتعلق بهذا الأمر فإن الله عز وجل سبحانه وتعالى\nمن سبحانه المترجم بالقرآن ربط طلبان بشيء آخر قال الله عز وجل\nشهر رمضان الذي أنزل فيه شهر رمضان الذي أنزل فيه القرآن",
    "القرآن هدى للناس وبينات من الهدى والفهى بعد هذا الوصف المعلق كله\nبالقرآن قال الله عز وجل فمن شهد منكم شهر شهر ماذا شهر\nشهر القرآن فمن شهد منكم الشهر فليصوم الصيام فريبة في رمضان\nلكن رمضان الفحوى منه والمعنى بعده الارتباط بكلام الله وإلا",
    "وإلا فما قولكم في الحديث الذي سأخبركم عنه يقول يروي وافلة بن الأزق رضي الله عنه\nرضي الله عنه عن النبي صلى الله عليه وسلم أنه قال أنزلت صحف إبراهيم\nفي أول ليلة من رمضان وأنزلت التوراة ستين متر\nماضينا من رمضان. وأنزلت الإنجيل والإنجيل ب ثلاثة عشر خلت من رمضان.",
    "وأنزل الفرقان أي القرآن ل أربعة وعشرون خرجت من رمضان\nالظاهر أن هذا الشهر اختص بتنزيل كلام الله عز وجل على كل الامم\nعلى كل الأمم ومن هنا ينطبق ذهننا بقول الله عز وجل يا أيها الذين آمنوا كتب عليكم الصيام\nالصيام كما كتب على الذين من قبلكم شهر رمضان الذي أنزل فيه القرآن لعل من كان قبلنا قيل له",
    "إن قيل لهم شهر رمضان الذي أنزل فيه الإنجيل، شهر رمضان الذي أنزل فيه التواة.\nشهر رمضان الذي أنزل فيه الزبور، شهر رمضان الذي أنزل فيه صحف إبراهيم وهكذا\nوهكذا كما كتب على الذين من قبلكم فهذا الربط بين الأمم وهذا الربط بين هذا الشهر الكريم\nهذا الشهر الفاضل والقرآن لا يجب أن يمر علينا هكذا ولا نتدبره ولا نسته.",
    "ولا نستخيفه ورضا الله عز وجل\nقد يغفل جل المسلمين بسبب ربما تباعد الزمن وقلة التذكرة\nوطول الأمد قد يغفل كثير من الناس عن فحوى رمضان فيظن البعض أنه محل الصيام\nإنه يكون محل الصيام فقط كلا إنه شهر القرآن النبي صلى الله عليه وسلم متى كان يتداول",
    "إذا كان يتدارس القرآن مع الزبير في شهر رمضان سبحان الله ثم يظن الناس أنه\nشهر الصيام فقط بل هو شهر القرآن شهر العبادة شهر الكيل بميزان القناطير والأطفال\nالتكثير الإكثار من العبادة من التعبد لله عز وجل من التقرب إلى الله\nسهل التعرض لنفحات ربنا سبحانه وتعالى ولتزليات رحمته",
    "ولمبسات نصره وسوف ترون ما الحكمة من إدخال هذا مبسات النصر\nمن سلسلة النصر في هذا الكلام ولفراس الدخول في زملة عباده المقربين المرضيين\nالذين يباهي بهم جل وعلا الملائكة ويذكرهم في الملاء الأعلى.\nنسأل الله عز وجل أن يكون منهم رمضان إذن ليس شهر الامتناع عن الأكل والشراب",
    "وشهوة الفرج من طلوع الشمس إلى غروبها فقط أبداً إنما هو فرصة\nفرصة لتزكية النفس والسمو بها في مدارسة السالكين إلى الله ومعارج هذا الكلام الآن\nالأن حقيقة اسمعوا كثيراً وله رنين في آذاننا العام اللي فاته العمل اللي قبله\nالعوام قبل هذا كلها ها التزكية وسلوك مدارس السالكين والطموح إن شاء الله في معارج",
    "يا أخ يا أخ كيف أدخل في ذلك المسلك\nوكيف أسير في ذلك في تلك الطريق وكيف أستفيد منك\nأستاذ المستفيدين وأكون من زمرة من يخرج من رمضان وقد أعتقت رقبته من النار حقا من يخرج من رمضان\nمن رمضان وليس هو بعد رمضان كما كان قبل رمضان كيف أعطونا الله يرحم والديكم.",
    "أعطونا خطوات عملية إن شاء الله اليوم سوف نأخذ خطوة عملية\nفي التبصر بالقرآن وقراءته على غيره إن شاء الله ما كنا نلقاه\nفالله أحمد سبحانه الله أحمد وبصايا الأسف\nوأشوف إليكم يا إخواننا أن الله عز وجل من علينا أخرج لنا من خزائنه",
    "إنه يعتبر من خزائن وخبايا رحماته أمرا عظيما قبيل الرهبة\nويمه الناس سوءا وهو والله فتح مبين وهي هذه الوثائق وثائق إبسنا التي خالصت\nهذه الوثائق والله إنها لرسول مهم قال الله عز وجل\nالله عز وجل تلك لاتحسبوه شرا لكم بل هو خير لكم لاتحسبوه شرا لكم بل هو خير لكم",
    "انقضاء الكلام سوف ترون أنه من أعظم الانتصارات وأعظم الخير ما\nما خاز بالوثائق يمشي طيب إيش العلاقة يا أخي في رمضان اسمعوا سوف تعود كنا نتكلم عن النظارة\nعن النظارة التي نقرأ بها القرآن هذه النظارة إن شاء الله نستخرجها من هذه الأحداث\nالله سبحانه يقول في كتابه الايرون عن الكفار أولا يرون أي الكفار الذين كفروا",
    "ماذا يهم أنهم يفتنون في كل عام مرة أو مرتين مرتين\nثم لا يتوب ولا هم يذكر وفي قراءة أخرى وهي أشد\nيبدو على المؤمنين لأنها فيها لعل الواحد الذي لم يتفقه ولم يفصلني ذلك يقول\nطيب الكلام عنهم يعني مساكن كفار يقول الله عز وجل في نفس الآية أولا تروا",
    "أنهم يفتنون في كل عام مرة أو مرتين ثم لا يتوبون ولا هم يذكرون\nأولا ترون أيها المسلمون أنهم يهتمون في كل عام مرة أو مرتين ثم لا يتوبون ولا يذكرون\nلا تكن مثلهم\nفالحمد لله يعني بكل هذا كما ذكرت لكم يعني ما فرح الله به المرسلين",
    "والطاعنين في دين الله عز وجل والمتربصين بالمسلمين ما فضحهم لله عز وجل\nوأحسن ماقيل في هذا قول حبيبنا الدكتور إياد القليل الداعية وإن شاء الله نلخصه لكم\nتلخيصا ونستفيد منه عبرت يقول مما ينبغي أن نفعله ونحن مقبلون على رمضان\nشهر القرآن ان نلبس نظارات نقرأ بها كتاب الله جل وعلا.",
    "نظرة تدرك أنه تنزيل رب العالمين خطاب رب العالمين كلام خالق يزكي الإنسان ويرفعه ويحفظه إلى السكون فإذا قرأت القرآن عندما تذكر القرآن بهذه النظرة رأيت كيف يبني الله الأخلاق وكيف يحمي الفطرة يحمي الفطرة ويضع للناس سياجاً يمنعهم من الإنحدار وحين رأى العالم",
    "ما كشف من فضائح هبستين اللعين وأدرك حجم السقوط الأخلاقي\nالذي يمكن ان يصل اليه البشر إذا انفلته من شرع الله نفهم معنى قوله تعالى\nقال ولولا دفاع الله القراءة ولولا دفع الله الناس\nولولا دفع الله الناس بعضهم ببعض لفسدت الأرض.",
    "لا فسدة الأرض فرمضان فرصة لنقرأ القران بنظرة الفرد البقي بين سماء الشريعة وطهرها وبين الحضيض الذي يبلغه الانسان فالانسان إذا أعرض عن الوحي فالنجاة في الاعتصام بحبل الله والرفعة. في التمسك بكتابه وأسوق لكم في الكلام أمثلة على ذلك",
    "الآن التطبيق العملي أخدنا النظر الآن إلى التطبيق العملي يقرأ\nفي قائل القرآن وانت تستحضر قوله جل جلاله لقد من الله على المؤمنين\nلقد من الله على المؤمنين إذ بعث فيهم رسولا من أنفسهم\nيتلو عليهم آياته ويزكيهم ويعلمهم الكتاب والحكمة وإن كانوا مؤمنين.",
    "وإن كانوا من قبل لفي ضلال مبين\nوقوله بل الله بل الله يمن عليكم ان هددكم\nأن هداكم بل الله يمن عليكم أن هداكم للإيمان إن كنتم صادقين تدرك أن هذا الدين\nهذا الدين ملة إلهية نجاة من الضلال ورحمة من رب العالمين اقرأ قوله تعالى",
    "وما أرسلناك يا محمد وماأناك إلا رحمة للعالمين\nقال بعضكم لعل بعضكم لا يدري ماذا فضح من وثائق كنا قبل نستهجن الزنا\nوالمساكنة ونقول والله هي أخانا اللي مش مسلم المسكنة وهكذا ولا تعرفون\nمن ولد من ومن ومن ومن ومن ومن ومن ومن ومن ابن من الأعراض تختلط ثم يكتشف واحد مع واحدة يكتشف بعد ذلك أنها أخته.",
    "ليس أبواهم يعني زنوا ولم يحفظ الناس ولم يعرف من ابن من ثم الامراض و المشاكل والمصائب\nوالمصائب طيب يا سيدي ما اقتنعت بالزنا طيب الإغتصاب أليس هذا مما تستهزئ به\nما تستهزئ به النفس البشرية هذا التعدي على الضعيف من الجنس الآخر طيب\nعلى لا أقول على الأقل فهذا يعني ظلم وإنما طيب هذا كان يحصل مع البالغين ثم نقول لهم لا تفعلون.",
    "ما تفعلوه مع الأطفال الذين ليس لهم إمكانية الدفاع عن النفس كيف تخبزي الأطفال ماهذا\nطيب الإختصار بعدين انتقلنا إلى أشياء يعني اكتشفناها لم تكن تخطر في البال هي بصراحة كانت تختور في البال\nولا تخطر في بالنا سمعنا قول ربنا ولا تتبعوا خطوات الشيطان فزنا مع\nمع البالغ البالغ اغتصاب للأطفال بعدين أكل الأطفال الله أكبر.",
    "إنما هو خيط خلق وزره إيش عمين عليه الباطن الأسود هذا يعني ما تشوف اللي وراها\nيعني إن كان هذا الذي خرج معه لبر أسود أكله بشر ذاك الذي مخبأ ولم يبشر\nولم يفرق ايش سبحان الله الذي استغرب هذا ويقول كيف يكون هذا وإن الله",
    "وله قلوب لا يفقهون بها وله أعين لا يبصرون بها وله آذان لا يسمعون بها أولئك كالأنعام بل هم أضل أولئك هم الغافلون.",
    "ومنهم رؤساء ومنهم كل من ذو صورة وذقورة فقط هم من لموجود في\nلهم قلوب لا يفقهون بها ولهم أعين لا يبصرون بها\nولهم آذان وما أن أسمع هذه الآية وأقرأها بالنظارة إن شاء الله وأرى ذلك\nذلك الرجل الذي كان يقع على تلك الطفلة ولعلها تصرخ ولعلها تبكي.",
    "ولعلها تضطرب وهو لا يرى ولا يسمح لابكاء ولا شيء لهم أعين لا يبصرون بها ولهم آذان لا يسمعون بها ويسمعون بها أولئك كالأنعام بل هم أضل بل حرف إدراك يعني مثلا إنزل بالفخر لا يسو كالأنعام الأنعام أشرف وأطهر أولئك كالأنعام بل هم أضل",
    "أولئك هم الخاسرون\nحينما تقرأ قول الله عز وجل كنتم خير أمة أخرجت للناس\nيا خير أمة تعلمون لماذا صار ما يصير الان ولماذا فعل ابسيم ما فعله لان خير أمة\nأن خير أمة نامت خير أمة غفلت مع الغافلين وأعرضت مع التسليم",
    "وتعرضت مع المعرضين ولاهت مع اللاهين ولعبت مع اللاعبين فإغتصبت الذروة\nوالأطفال والنساء وقتل إخواننا في غزة وشرب إخواننا في السودان\nوظلم إخواننا الجمهور في الصين واشق على ذلك وتكلم حتى\nحتى ينسف حقك ولا تحيط علما بما وقع في العالم.",
    "للمسلمين ولغير المسلمين من الحفاظ المسلم\nلما تقرأ قول الله عز وجل في آية العفة والطهارة\nيُرمى بها هؤلاء الملحدون ويرمى بنا طاعنون في الدين قل للمؤمنين يغضوا\nالذين يغضون من أبصارهم ويحفظوا فروجهم والأخرى وقل للمؤمنات يغضن من أبصارهن.",
    "من أبصارهن ويحفظن فروجهن (ﷺ) يا أيها النبي قل لأزواجك وبناتك ونسائك\nونساء المؤمنين ممنين عليهن من زلاذهن لماذا كل هذا لكي لا نقع فيها\nلكي لا أقع في أقرأ قول الله عزوجل يا بني ادم ماشي أجمل من هؤلاء\nالنوعان يا بني آدم لا يفتنكم الشيطان لا يفتنكم الشيطان.",
    "ولقب الله عز وجل لا بل بين لك ضرب ذاك المثل بالمثل يفهم الإنسان\nلا يفتنكم الشيطان كما أخرج أبويكم من الجنة ينزع عنهما لباسهما\nليريهما سوءاتهما لما تشوف بالسير وتشوف هذا للوقع وتقرأ هذه الآيات\nاستشعر عظمة الله و منة الله و سود الله وكرمه وتودده اليه.",
    "إلى عباده إذ لم يخلقهم ويهملهم بل خلقهم ورزقهم وهداهم وصانهم\nوصانهم وحفظهم وبنالهم وبين لهم وعلمهم وأراهم\nوسألهم العبر والأمثال أولم يهديهم\nأولم يهد لهم يعني الذين خانوا قبلهم كم أهلكنا قبلهم من قرن من القرون.",
    "من قرن من القرون يمشون في مساكنهم إن في ذلك لآيات لأولي\nيا عباد الذي يعتبر الآن يبسي وان شاء الله في رمضان هذا يمر على القرآن\nالقرآن طبعا القراءة هذه التي نأخذ منها الأجر هذه نقنطر فيها ونكير بالأضماط\nبالأضمان محتاجين قراءة بالمشطي هذا الفرق الرفيع المستوى الرفيع.",
    "اقرأ آية وقل الحمد لله اقرأ آية قل والله واحد الحمد لله\nلا أن الله أحد اعمل لوجه واحد يكفيك كل الأوجه\nمصانعة وجه واحد خير من مصانعة الأوجه كلها\nإقرأ قول الله عز وجل الله الصمد نحن نصلي اليه ونلتجئ اليه سبحانه وتعالى.",
    "سبحاني نلتزم إليه ونقوم به لمدافعة هؤلاء الناس ندافع عن بني آدم هذا الذي ليس مسلما\nليس مسلمًا وكان ممنوع عليه وسيأتي قول الله عز وجل: (قاتِلُوهُمْ يُعَذِّبْهُمُ اللَّـهُ بِأَيْدِيكُمْ وَيُخْزِهِمْ وَيَنصُرْكُمْ عَلَيْهِمْ وَيَشْفِ صُدُورَ قَوْمٍ مُّؤْمِنِينَ) يذهبون\nهؤلاء الناس كان الواحد مش وده واحد للبيت علشان البيت يعني البيت لا تماثله له.",
    "تماكله أهل البيوت في العنكبوت كأنه قد منه ووجدها مركبة في الزبالة\nوالله أنا أحكي لكم صافي بنت خارج بيت زوجها بدافع التحرك من بيت أبيها بدافع التحرك\nفتسلط عليها أحد هؤلاء الوحوش و الآن الحمد لله ما يمكن أن نقول نعم و قال كذا و كان كذا و لا أي حد ما يفي أحد وجد\nأحد يشكك أنت الذي خرج من وجهك لأن الذي ربى أن ينزل مقاتل إلى بلاده",
    "نحن ندافع عن هذه النساء، نحن ندافع عما ندافع عنه. فإذا كنا كمسلمين رحلنا إلى القناة وقرأنا هذه النظرة الجديدة التي كسبناها، رحم الله عز وجل ونرى الفشاة عليه السلام الشراس علينا رحمة الشريعة بقانون الله عز وجل وبين حضير الانتعااب لله عز وجل قوانينه. أقول مسمعوا فاستغفروا الله واستغفروه إنه غفور رحيم",
    "بسم الله الرحمن الرحيم الحمد لله رب العالمين والصلاة والسلام\nعلى أشرف الأنبياء والمرسلين سيدنا محمد (صلى الله عليه وسلم) الرسول الأمين ورحمة الله وبركاته.\nصلوات ربي وسلامه عليه صلوا على رسول الله أحبكم الله،\nفيا إخوان أهم شيء حتى نخرج من رمضان بالاستفادة والجزاء.",
]


@dataclass
class BenchmarkResult:
    baseline_total_s: float
    stream_total_s: float
    speedup_x: float
    baseline_mean_chunk_s: float
    stream_mean_chunk_s: float
    baseline_hits_total: int
    stream_hits_total: int
    matched_hits: int
    recall_proxy: float
    precision_proxy: float
    mismatches: list[tuple[int, list[str], list[str]]]
    baseline_counter: dict[str, int]
    stream_counter: dict[str, int]


def _run_large_regression_benchmark(chunks: list[str]) -> BenchmarkResult:
    validator = QuranValidator(
        ValidatorOptions(fuzzy_threshold=0.8, include_partial=False, asr_tolerant=True)
    )
    opts = StreamingQuranMatcherOptions(
        min_confidence=0.8,
        min_words=3,
        max_words=50,
        asr_tolerant=True,
        beam_size=96,
        max_verifications_per_chunk=192,
        max_full_validations_per_chunk=16,
        max_emit_window_candidates=8,
        min_anchor_score=2.0,
        min_approx_confidence=0.70,
        max_start_delta=2,
        max_len_delta=3,
        max_buffer_words=128,
        max_chunk_span=4,
        max_anchor_age_tokens=96,
        duplicate_ref_window_tokens=32,
    )
    matcher = StreamingQuranMatcher(opts)

    baseline_refs_by_chunk: list[list[str]] = []
    stream_refs_by_chunk: list[list[str]] = []
    baseline_times: list[float] = []
    stream_times: list[float] = []

    t0 = time.perf_counter()
    for chunk in chunks:
        s = time.perf_counter()
        hits = validator.scan_for_verses(
            chunk,
            min_words=3,
            max_words=50,
            confidence_threshold=0.8,
        )
        baseline_times.append(time.perf_counter() - s)
        baseline_refs_by_chunk.append([h.get("reference") for h in hits if h.get("reference")])
    baseline_total = time.perf_counter() - t0

    t1 = time.perf_counter()
    for chunk in chunks:
        s = time.perf_counter()
        result = matcher.process_chunk(chunk)
        stream_times.append(time.perf_counter() - s)
        stream_refs_by_chunk.append([h.reference for h in result.complete_verses if h.reference])
    flush = matcher.flush()
    flush_refs = [h.reference for h in flush.complete_verses if h.reference]
    stream_total = time.perf_counter() - t1

    baseline_counter = Counter(ref for refs in baseline_refs_by_chunk for ref in refs)
    stream_counter = Counter(ref for refs in stream_refs_by_chunk for ref in refs)
    for ref in flush_refs:
        stream_counter[ref] += 1

    matched = sum(min(baseline_counter[k], stream_counter.get(k, 0)) for k in baseline_counter)
    baseline_hits_total = sum(baseline_counter.values())
    stream_hits_total = sum(stream_counter.values())

    recall_proxy = matched / baseline_hits_total if baseline_hits_total else 1.0
    precision_proxy = matched / stream_hits_total if stream_hits_total else 1.0

    mismatches: list[tuple[int, list[str], list[str]]] = []
    for i, (b, s) in enumerate(zip(baseline_refs_by_chunk, stream_refs_by_chunk), 1):
        if Counter(b) != Counter(s):
            mismatches.append((i, b, s))

    return BenchmarkResult(
        baseline_total_s=baseline_total,
        stream_total_s=stream_total,
        speedup_x=(baseline_total / max(stream_total, 1e-9)),
        baseline_mean_chunk_s=mean(baseline_times),
        stream_mean_chunk_s=mean(stream_times),
        baseline_hits_total=baseline_hits_total,
        stream_hits_total=stream_hits_total,
        matched_hits=matched,
        recall_proxy=recall_proxy,
        precision_proxy=precision_proxy,
        mismatches=mismatches,
        baseline_counter=dict(baseline_counter),
        stream_counter=dict(stream_counter),
    )


@pytest.mark.slow
def test_stream_matcher_large_regression_benchmark():
    if os.getenv("IJAZA_RUN_LARGE_BENCHMARK") != "1":
        pytest.skip("Set IJAZA_RUN_LARGE_BENCHMARK=1 to run slow large benchmark.")

    res = _run_large_regression_benchmark(CHUNKS_PRE_ENDING_42)

    print("\n=== Large Benchmark Metrics ===")
    print(f"chunks={len(CHUNKS_PRE_ENDING_42)}")
    print(f"baseline_total_s={res.baseline_total_s:.3f}")
    print(f"stream_total_s={res.stream_total_s:.3f}")
    print(f"speedup_x={res.speedup_x:.1f}")
    print(f"baseline_mean_chunk_s={res.baseline_mean_chunk_s:.3f}")
    print(f"stream_mean_chunk_s={res.stream_mean_chunk_s:.4f}")
    print(f"baseline_hits_total={res.baseline_hits_total} {res.baseline_counter}")
    print(f"stream_hits_total={res.stream_hits_total} {res.stream_counter}")
    print(f"matched_hits={res.matched_hits}")
    print(f"recall_proxy={res.recall_proxy:.3f}")
    print(f"precision_proxy={res.precision_proxy:.3f}")
    print(f"mismatch_count={len(res.mismatches)}")
    for idx, b, s in res.mismatches[:10]:
        print(f"mismatch_chunk_{idx}: baseline={b} stream={s}")

    # Guardrails based on current benchmark behavior:
    # keep strong latency benefit and preserve improved proxy accuracy.
    assert res.speedup_x >= 120.0
    assert res.recall_proxy >= 0.85
    assert res.precision_proxy >= 0.88
