#!/usr/bin/env python3
"""
Circular Buffer - Step-by-Step Tutorial
========================================
Follow the examples or type your own commands!
"""

from circular_buffer import cb_init, cb_write, cb_copy_span, cb_w_abs, cb_overflows, cb_fill_bytes, cb_fill_pct, Status


def show_buffer(buf, label="Buffer"):
    """Simple buffer visualization."""
    w_abs = cb_w_abs(buf)
    w_overflow = cb_overflows(buf)
    fill_pct = cb_fill_pct(buf)
    fill = cb_fill_bytes(buf)
    pos = w_abs % buf.capacity
    
    print(f"\n  {label}:")
    print("  ", end="")
    for i in range(buf.capacity):
        b = buf.buffer[i]
        if b == 0:
            print("[ ]", end="")
        else:
            c = chr(b) if 32 <= b < 127 else f"{b:02X}"
            print(f"[{c}]", end="")
    
    print(f"  ← capacity={buf.capacity}")
    print("  ", end="")
    for i in range(buf.capacity):
        print(" ↑ " if i == pos else "   ", end="")
    print(f"  ← write position={pos}")
    print(f"  Fill: {fill}/{buf.capacity} bytes | Total written: {w_abs} | Percent Full: {fill_pct}\n")
    print(f"  Overflow Count : {w_overflow} \n")


def tutorial_mode():
    """Guided tutorial."""
    print("\n" + "="*70)
    print("  TUTORIAL MODE - Follow Along!")
    print("="*70 + "\n")
    
    # Create small buffer
    capacity = 8
    print(f"Step 1: Create buffer with capacity={capacity}")
    status, buf = cb_init(capacity)
    print(f"  → Created!")
    show_buffer(buf, "Empty Buffer")
    
    input("Press ENTER to continue...")
    
    # Write ABC
    print("\nStep 2: Write 'ABC'")
    data = b"ABC"
    print(f"  → cb_write(buffer, {data})")
    st, written = cb_write(buf, data)
    print(f"  → Wrote {written} bytes")
    show_buffer(buf, "After Writing 'ABC'")
    
    input("Press ENTER to continue...")
    
    # Write more
    print("\nStep 3: Write 'DEFG'")
    data = b"DEFG"
    print(f"  → cb_write(buffer, {data})")
    st, written = cb_write(buf, data)
    print(f"  → Wrote {written} bytes")
    show_buffer(buf, "After Writing 'DEFG'")
    print("  Notice: Buffer is full! (7/8 bytes)")
    
    input("Press ENTER to continue...")
    
    # Read data
    print("\nStep 4: Read all data")
    w_abs = cb_w_abs(buf)
    print(f"  → cb_copy_span(buffer, 0, {w_abs})")
    st, data = cb_copy_span(buf, 0, w_abs)
    print(f"  → Read: {data}")
    print(f"  → Decoded: '{data.decode()}'")
    show_buffer(buf, "Buffer Still Has Data")
    print("  Note: Reading doesn't remove data!")
    
    input("Press ENTER to continue...")
    
    # Overflow
    print("\nStep 5: Write more data than capacity (OVERFLOW!)")
    data = b"HIJKL"
    print(f"  → cb_write(buffer, {data}) - that's 5 more bytes!")
    print(f"  → Buffer is full, so oldest data will be overwritten...")
    st, written = cb_write(buf, data)
    print(f"  → Wrote {written} bytes")
    show_buffer(buf, "After Overflow")
    print("  Notice: 'ABC' got overwritten! Oldest data lost!")
    print("  Buffer now has: 'DEFGHIJK' (last 8 bytes)")
    
    input("Press ENTER to continue...")
    
    # Read after overflow
    print("\nStep 6: Read data after overflow")
    w_abs = cb_w_abs(buf)
    start = w_abs - capacity  # Only keep what fits
    print(f"  → cb_copy_span(buffer, {start}, {w_abs})")
    st, data = cb_copy_span(buf, start, w_abs)
    print(f"  → Read: {data}")
    print(f"  → Decoded: '{data.decode()}'")
    print("\n  ✅ This is how circular buffer works!")
    print("     • Fixed size (no growing)")
    print("     • Drop oldest when full")
    print("     • Keep most recent data")


def playground_mode():
    """Free-form playground."""
    print("\n" + "="*70)
    print("  PLAYGROUND MODE - Type Your Own Commands!")
    print("="*70 + "\n")
    
    print("Commands:")
    print("  w <text>   - Write text (e.g., 'w HELLO')")
    print("  r          - Read all data")
    print("  r <n>      - Read last n bytes")
    print("  s          - Show status")
    print("  c          - Clear (reset) buffer")
    print("  q          - Quit")
    print()
    
    # Create buffer
    capacity = 12
    status, buf = cb_init(capacity)
    print(f"Created buffer: capacity={capacity}")
    show_buffer(buf, "Initial State")
    
    while True:
        try:
            cmd = input("cmd> ").strip()
            
            if not cmd:
                continue
            
            parts = cmd.split(maxsplit=1)
            action = parts[0].lower()
            
            if action == 'q':
                print("Goodbye!\n")
                break
            
            elif action == 'w':
                if len(parts) < 2:
                    print("Usage: w <text>")
                    continue
                text = parts[1]
                data = text.encode('ascii')
                print(f"\nWriting: {data} ('{text}')")
                st, written = cb_write(buf, data)
                print(f"Wrote: {written} bytes")
                show_buffer(buf)
            
            elif action == 'r':
                w_abs = cb_w_abs(buf)
                if w_abs == 0:
                    print("\nBuffer is empty!")
                    continue
                
                if len(parts) > 1:
                    try:
                        n = int(parts[1])
                        start = max(0, w_abs - n)
                    except:
                        print("Invalid number")
                        continue
                else:
                    start = max(0, w_abs - capacity)
                
                st, data = cb_copy_span(buf, start, w_abs)
                print(f"\nRead: {data}")
                print(f"Text: '{data.decode('ascii', errors='replace')}'")
            
            elif action == 's':
                show_buffer(buf, "Current State")
            
            elif action == 'c':
                buf.buffer[:] = b'\x00' * capacity
                buf.write_absolute = 0
                buf.overflows = 0
                print("\nBuffer cleared!")
                show_buffer(buf)
            
            else:
                print(f"Unknown command: {action}")
        
        except KeyboardInterrupt:
            print("\n\nGoodbye!\n")
            break
        except EOFError:
            print("\n\nGoodbye!\n")
            break
        except Exception as e:
            print(f"Error: {e}")


def quick_test():
    """Quick automated test you can watch."""
    print("\n" + "="*70)
    print("  QUICK TEST - Watch What Happens!")
    print("="*70 + "\n")
    
    import time
    
    status, buf = cb_init(10)
    print("Created buffer: capacity=10")
    show_buffer(buf)
    time.sleep(1)
    
    print("Writing: ABC")
    cb_write(buf, b"ABC")
    show_buffer(buf)
    time.sleep(1)
    
    print("Writing: DEFGH")
    cb_write(buf, b"DEFGH")
    show_buffer(buf)
    time.sleep(1)
    
    print("Writing: IJKLM (OVERFLOW!)")
    cb_write(buf, b"IJKLM")
    show_buffer(buf)
    print("Notice: Oldest data (ABC) was overwritten!")
    time.sleep(1)
    
    w_abs = cb_w_abs(buf)
    st, data = cb_copy_span(buf, w_abs - 10, w_abs)
    print(f"\nFinal data: {data.decode()}")
    print("That's the last 10 bytes written!\n")


def main():
    """Main menu."""
    print("\n" + "="*70)
    print("  CIRCULAR BUFFER - LEARNING PLAYGROUND")
    print("="*70)
    print("\nChoose a mode:")
    print("  1. Tutorial (step-by-step guided)")
    print("  2. Playground (type your own commands)")
    print("  3. Quick Test (watch automated demo)")
    print("  q. Quit")
    print()
    
    choice = input("Select [1/2/3/q]: ").strip()
    
    if choice == '1':
        tutorial_mode()
    elif choice == '2':
        playground_mode()
    elif choice == '3':
        quick_test()
    elif choice.lower() == 'q':
        print("\nGoodbye!\n")
    else:
        print("\nInvalid choice. Goodbye!\n")


if __name__ == "__main__":
    main()
