#!/usr/bin/env python3
"""
Test script to see how the text tokenizer encodes various sequence formats.

This tests encoding of:
- Simple arrays like [1,2,3]
- Value sequences like [v1,v2,...,v100] with different lengths
- Mixed negative values like [-1,-1,100,60,51,41]
- Character mixing like [15,12,10,x,1,3,4]
"""

import sys
import os

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from text_utils import tokenize_batch

# Test cases
test_sequences = []

# 1. Simple short sequences
test_sequences.append(("[1,2,3]", "Simple short sequence"))
test_sequences.append(("[10,20,30]", "Simple sequence with larger numbers"))

# 2. Value sequences with 10 different lengths (5 to 50 values)
for num_values in [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]:
    values = [str(i % 101) for i in range(num_values)]  # Values 0-100
    seq_str = f"[{','.join(values)}]"
    test_sequences.append((seq_str, f"Sequence with {num_values} values (0-100)"))

# 3. Mixed negative values
test_sequences.append(("[-1,-1,100,60,51,41]", "Sequence with negative values"))
test_sequences.append(("[-1,50,75,-1,25,-1]", "Alternating negatives and positives"))

# 4. Character mixing
test_sequences.append(("[15,12,10,x,1,3,4]", "Sequence with character 'x'"))
test_sequences.append(("[10,abc,20,30]", "Sequence with string 'abc'"))
test_sequences.append(("[5,10,?,20,25]", "Sequence with '?' character"))

# 5. Full range test: -1 to 100
full_range_values = ["-1"] + [str(i) for i in range(101)]  # -1, 0, 1, 2, ..., 100
full_range_str = f"[{','.join(full_range_values)}]"
test_sequences.append((full_range_str, "Full range from -1 to 100 (102 values)"))

# 6. Double-digit tokenization tests
test_sequences.append(("[61]", "Single value 61 in array"))
test_sequences.append(("[71]", "Single value 71 in array"))
test_sequences.append(("[61,71]", "Two values 61 and 71"))
test_sequences.append(("[6]", "Single digit 6 in array"))
test_sequences.append(("[1]", "Single digit 1 in array"))
test_sequences.append(("[7]", "Single digit 7 in array"))

# Tokenize and display results
print("=" * 100)
print("Text Tokenizer Encoding Tests")
print("=" * 100)
print()

tokenizer_fp = "/app2/suno/data/auk_v0/tokenizer_60k.json"

for seq_str, description in test_sequences:
    tokens = tokenize_batch([seq_str], tokenizer_fp=tokenizer_fp, pad_token_id=60001)[0]

    print(f"Description: {description}")
    print(f"Input:       {seq_str}")
    print(f"Tokens:      {tokens.tolist()}")
    print(f"Num tokens:  {len(tokens)}")
    print(f"Tokens/char: {len(tokens) / len(seq_str):.2f}")
    print()

print("=" * 100)
print("Summary:")
print("- Short sequences like [1,2,3] are compact")
print("- Longer sequences scale linearly with number of values")
print("- Negative values and special characters affect tokenization")
print("- Token count correlates with string length, not value count")
print("=" * 100)
print()

# Detailed assertion test for full range -1 to 100
print("=" * 100)
print("Detailed Token Analysis: Full Range [-1, 0, 1, ..., 100]")
print("=" * 100)
print()

# Tokenize the full range sequence
full_range_tokens = tokenize_batch([full_range_str], tokenizer_fp=tokenizer_fp, pad_token_id=60001)[
    0
].tolist()

print(f"Input: {full_range_str[:100]}... (truncated)")
print(f"Total tokens: {len(full_range_tokens)}")
print()

# Expected structure:
# [ (1 token) + -1 (2 tokens) + , (1 token) + 0 (1 token) + , (1 token) + ... + 100 (1 token) + ] (1 token)
# = 1 + 2 + (101 commas * 1) + (101 values: 0-100 each 1 token) + 1
# = 1 + 2 + 101 + 101 + 1 = 206 tokens expected

# Test individual value tokenization
print("Testing individual value tokenization:")
print()

# Test -1
minus_one_tokens = tokenize_batch(["-1"], tokenizer_fp=tokenizer_fp, pad_token_id=60001)[0].tolist()
print(f"  -1 encodes as: {minus_one_tokens} ({len(minus_one_tokens)} tokens)")
assert len(minus_one_tokens) == 2, f"-1 should use 2 tokens, got {len(minus_one_tokens)}"

# Test 0-100 (should each be single token)
failed_values = []
for i in range(101):
    value_tokens = tokenize_batch([str(i)], tokenizer_fp=tokenizer_fp, pad_token_id=60001)[0].tolist()
    if len(value_tokens) != 1:
        failed_values.append((i, len(value_tokens), value_tokens))

if failed_values:
    print()
    print(f"  ❌ FAILED: {len(failed_values)} values did not encode as single token:")
    for val, num_tokens, tokens in failed_values[:10]:  # Show first 10 failures
        print(f"     Value {val}: {num_tokens} tokens {tokens}")
    if len(failed_values) > 10:
        print(f"     ... and {len(failed_values) - 10} more")
else:
    print(f"  ✓ All values 0-100 encode as single token")

# Test comma
comma_tokens = tokenize_batch([","], tokenizer_fp=tokenizer_fp, pad_token_id=60001)[0].tolist()
print(f"  Comma ',' encodes as: {comma_tokens} ({len(comma_tokens)} token)")
assert len(comma_tokens) == 1, f"Comma should use 1 token, got {len(comma_tokens)}"

print()
print("Expected token count calculation:")
print(f"  [ bracket: 1 token")
print(f"  -1 value: 2 tokens")
print(f"  101 commas: 101 tokens")
print(f"  101 values (0-100): 101 tokens")
print(f"  ] bracket: 1 token")
print(f"  TOTAL EXPECTED: 206 tokens")
print()
print(f"Actual token count: {len(full_range_tokens)}")

if len(full_range_tokens) == 206:
    print("✓ Token count matches expected!")
else:
    print(f"❌ Token count mismatch! Expected 206, got {len(full_range_tokens)}")
    print(f"   Difference: {len(full_range_tokens) - 206}")

print("=" * 100)
