from pathlib import Path
import json, re, sys

ROOT = Path(__file__).resolve().parents[2]
checks = []

def require(path, text):
    body=(ROOT/path).read_text(encoding='utf-8-sig')
    ok=text in body
    checks.append((ok, f'{path}: {text}'))

def require_regex(path, pattern):
    body=(ROOT/path).read_text(encoding='utf-8-sig')
    ok=re.search(pattern, body, re.M|re.S) is not None
    checks.append((ok, f'{path}: /{pattern}/'))

factory='MASSystem/Application/Facade/MASApplicationWindowControls.ControlFactory.Inputs.vb'
require(factory, 'Public Function AddComboBox(Optional items As IEnumerable(Of String) = Nothing,')
require(factory, 'Public Function AddSlider(Optional minimum As Double = 0.0,')
require(factory, 'Public Function AddTextBox(Optional text As String = Nothing,')
require(factory, 'Public Function AddSearchTextBox(Optional text As String = Nothing,')

require('Component/Inputs/TextBox/Controls/MASTextBox/MASTextBox.vb', 'Public Function WithText(value As String) As MASTextBox')
require('Component/Inputs/TextBox/Controls/MASTextBox/MASTextBoxTextPolicy.vb', 's = s.Replace(vbCrLf, " ")')
require('Component/Inputs/TextBox/Controls/MASSearchTextBox/MASSearchTextBoxPolicy.vb', 'Return "Search..."')
require('Component/Inputs/TextBox/Controls/MASSearchTextBox/MASSearchTextBox.Advanced.vb', 'Public Event SearchCommitted As EventHandler')
require('Component/Inputs/TextBox/Controls/MASSearchTextBox/MASSearchTextBox.Advanced.vb', 'Public Function BindToDataGrid(grid As MASDataGrid) As MASSearchTextBox')

require('Component/Inputs/ComboBox/MASComboBox.Items.vb', '_selectedIndex = If(_items.Count > 0, 0, -1)')
require('Component/Inputs/ComboBox/MASComboBox.Properties.vb', 'Public ReadOnly Property SelectedText As String')
require('Component/Inputs/ComboBox/MASComboBox.vb', 'Public Event SelectionChanged As EventHandler')

require('Component/Tokens/Component/SliderTokens.vb', 'Friend Const DefaultMinimum As Double = 0.0')
require('Component/Tokens/Component/SliderTokens.vb', 'Friend Const DefaultMaximum As Double = 100.0')
require('Component/Tokens/Component/SliderTokens.vb', 'Friend Const DefaultStep As Double = 1.0')
require('Component/Tokens/Component/SliderTokens.vb', 'Friend Const DefaultTickFrequency As Double = 10.0')
require('Component/Inputs/Slider/MASSlider.vb', 'Public Event ValueChanged As EventHandler')
require('Component/Inputs/Slider/MASSlider.vb', 'Public Event RangeChanged As EventHandler')
require('Component/Inputs/Slider/MASSliderRangePolicy.vb', 'If maximum < minimum Then')
require('Component/Inputs/Slider/MASSliderRangePolicy.vb', 'MidpointRounding.AwayFromZero')

baseline=json.loads((ROOT/'eng/tests/Nexamas.UI.PublicApiClassificationBaseline.json').read_text(encoding='utf-8-sig'))
items=baseline if isinstance(baseline,list) else baseline.get('types', baseline.get('entries', []))
# fallback recursive extraction
found={}
def walk(x):
    if isinstance(x,dict):
        if 'name' in x and 'category' in x: found[x['name']]=x['category']
        for v in x.values(): walk(v)
    elif isinstance(x,list):
        for v in x: walk(v)
walk(baseline)
for name in ('MASTextBox','MASSearchTextBox','MASComboBox','MASSlider'):
    checks.append((found.get(name)=='Advanced', f'classification {name}=Advanced'))

# Relative markdown links in modified pages.
for rel in ('docs/reference/api/README.md','docs/recipes/inputs.md'):
    body=(ROOT/rel).read_text(encoding='utf-8-sig')
    base=(ROOT/rel).parent
    for target in re.findall(r'\[[^\]]+\]\(([^)]+)\)', body):
        if '://' in target or target.startswith('#'): continue
        target=target.split('#',1)[0]
        checks.append(((base/target).resolve().exists(), f'{rel} link {target}'))

failed=[msg for ok,msg in checks if not ok]
for ok,msg in checks:
    print(('PASS' if ok else 'FAIL') + ': ' + msg)
print(f'\nAssertions: {len(checks)-len(failed)} passed, {len(failed)} failed')
if failed: sys.exit(1)
