
import math
import re
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
CALCULATORS_TS = ROOT / "hdyc-svelte" / "src" / "lib" / "data" / "calculators.ts"

def _js_fmt(n: float) -> str:
    """Mimics the fmt() function in engine.ts"""
    if not math.isfinite(n):
        return str(n)
    if n == 0:
        return "0"
    if abs(n) < 1e-6:
        return f"{n:.6e}".replace("e-0", "e-").replace("e+0", "e+")
    
    # engine.ts uses parseFloat(n.toFixed(6)).toString()
    rounded = round(n, 6)
    if rounded == 0: # Handle -0.0
        return "0"
    if rounded == int(rounded):
        return str(int(rounded))
    return str(rounded)

def _js_fmt_precise(n: float) -> str:
    """Mimics formatExampleValue in QuickConversionExample.svelte"""
    if n is None or math.isnan(n):
        return "—"
    if not math.isfinite(n):
        return str(n)
    if n == 0:
        return "0"
    
    rounded = round(n, 6)
    if rounded != 0:
        if rounded == int(rounded):
            return str(int(rounded))
        return str(rounded)
    
    # Precise version for very small numbers
    precise = f"{n:.12f}".rstrip('0').rstrip('.')
    return precise if precise else "0"

class TestCalculatorsConsistency(unittest.TestCase):
    def test_standard_calculators_consistency(self):
        text = CALCULATORS_TS.read_text(encoding="utf-8")
        
        # Extract the calculators array content
        match = re.search(r"export const calculators: CalculatorDef\[\] = \[(.*?)\];", text, re.S)
        self.assertTrue(match, "Could not find calculators array in calculators.ts")
        
        body = match.group(1)
        # Split by '{"slug":' to avoid splitting on nested braces
        raw_entries = body.split('{"slug":')
        
        errors = []
        for raw_entry in raw_entries:
            if not raw_entry.strip():
                continue
            entry = '{"slug":' + raw_entry
            slug_match = re.search(r'"slug": "(.*?)"', entry)
            if not slug_match:
                continue
            slug = slug_match.group(1)
            
            type_match = re.search(r'"type": "(.*?)"', entry)
            if not type_match or type_match.group(1) != "standard":
                continue
            
            # Use non-greedy search for factor/offset and handle potential whitespace
            factor_match = re.search(r'"factor":\s*([0-9.eE+-]+)', entry)
            offset_match = re.search(r'"offset":\s*([0-9.eE+-]+)', entry)
            
            factor = float(factor_match.group(1)) if factor_match else 1.0
            offset = float(offset_match.group(1)) if offset_match else 0.0
            
            # 1. Formula Hint vs Chart Row 1 Consistency
            # Logic: solve(config, 1, "1") -> val2 = fmt(1 * factor + offset)
            row_one_output = _js_fmt(1.0 * factor + offset)
            
            # 2. How to convert Examples Consistency (Inverse)
            if factor != 0:
                reverse_val = (1.0 - offset) / factor
                formatted_reverse = _js_fmt_precise(reverse_val)
                
                # Specific check for Réaumur to Kelvin (User request)
                if slug == "reaumur-to-kelvin":
                    if formatted_reverse != "-217.72":
                        errors.append(f"[{slug}] Reverse example mismatch: expected -217.72, got {formatted_reverse}")
                    if row_one_output != "274.4":
                        errors.append(f"[{slug}] Chart row 1 mismatch: expected 274.4, got {row_one_output}")

                # Specific check for Feet per minute to Knots (Previous bug fix)
                if slug == "feet-per-minute-to-knots":
                    if row_one_output != "0.009875":
                        errors.append(f"[{slug}] Chart row 1 mismatch: expected 0.009875, got {row_one_output}")
                    if formatted_reverse != "101.268504":
                        errors.append(f"[{slug}] Reverse example mismatch: expected 101.268504, got {formatted_reverse}")

        if errors:
            self.fail("\n" + "\n".join(errors))

if __name__ == "__main__":
    unittest.main()
