"""
PyWasot Feature Demo
=====================

This playground demonstrates all the powerful features of pywasot,
the Python bindings for the Wasot markup language.

Run with: python playground.py
"""

import pywasot


# =============================================================================
# Sample Document
# =============================================================================

SAMPLE_DOC = """
.article
..meta
...title Building Modern Apps
...author Jane Smith
...date 2024-01-15
..content
...section :intro
....heading Introduction
....paragraph
Welcome to this guide on building modern applications.
We'll cover architecture, testing, and deployment.
...section :architecture
....heading Architecture Patterns
....paragraph
Modern apps use several key patterns:
....list
.....item
Microservices for scalability
.....item
Event-driven for loose coupling
.....item
API-first for flexibility
...section :testing
....heading Testing Strategies
....paragraph
A solid testing pyramid includes:
....list
.....item :unit
Unit tests (fast, isolated)
.....item :integration
Integration tests (API boundaries)
.....item :e2e
End-to-end tests (user flows)
..footer
...copyright 2024 Example Corp
"""


def header(title: str) -> None:
    """Print a section header."""
    print()
    print("=" * 60)
    print(f"  {title}")
    print("=" * 60)
    print()


def subheader(title: str) -> None:
    """Print a subsection header."""
    print(f"\n--- {title} ---\n")


# =============================================================================
# 1. Basic Parsing and Navigation
# =============================================================================

def demo_parsing_navigation():
    header("1. Parsing and Navigation")

    # Parse content - this is the main entry point
    root = pywasot.parse(SAMPLE_DOC)
    print(f"Parsed document: {root!r}")

    subheader("Accessing children via []")
    print(f"root['meta'] = {root['meta']!r}")
    print(f"root['meta']['title'].inline_text = {root['meta']['title'].inline_text!r}")
    print(f"root['meta']['author'].inline_text = {root['meta']['author'].inline_text!r}")

    subheader("Chained [] access")
    intro = root['content']['section']
    print(f"First section: {intro!r}")
    print(f"Its heading: {intro['heading']!r}")
    print(f"Its paragraph text: {intro['paragraph'].text!r}")

    subheader("Using .get() for safe access")
    print(f"root.get('meta') = {root.get('meta')!r}")
    print(f"root.get('nonexistent') = {root.get('nonexistent')}")
    print(f"root.get('nonexistent', 'default') = {root.get('nonexistent', 'default')!r}")

    subheader("Sibling navigation")
    print(f"intro.next_sibling = {intro.next_sibling!r}")
    arch = intro.next_sibling
    print(f"arch.previous_sibling = {arch.previous_sibling!r}")
    print(f"arch.next_sibling = {arch.next_sibling!r}")


# =============================================================================
# 2. Finding Elements
# =============================================================================

def demo_finding():
    header("2. Finding Elements")

    root = pywasot.parse(SAMPLE_DOC)

    subheader("find_one() - First match")
    first_para = root.find_one('paragraph')
    print(f"First paragraph: {first_para!r}")
    print(f"Text: {first_para.text!r}")

    subheader("find() - All matches")
    all_sections = root.find('section')
    print(f"Found {len(all_sections)} sections:")
    for section in all_sections:
        print(f"  - {section.id}: {section['heading'].inline_text}")

    subheader("find_one() with ID filter")
    testing = root.find_one('section#testing')
    print(f"Testing section: {testing!r}")

    subheader("find() nested")
    all_items = root.find('item')
    print(f"All list items ({len(all_items)}):")
    for item in all_items:
        print(f"  - [{item.id or 'no-id'}] {item.text}")


# =============================================================================
# 3. CSS-Like Selectors
# =============================================================================

def demo_selectors():
    header("3. CSS-Like Selectors")

    root = pywasot.parse(SAMPLE_DOC)

    subheader("Type selector")
    headings = root.find('heading')
    print(f"All headings: {headings!r}")

    subheader("ID selector")
    intro = root.find_one('#intro')
    print(f"#intro: {intro!r}")

    subheader("Direct child selector (>)")
    direct_items = root.find('list > item')
    print(f"Direct list items: {len(direct_items)} found")

    subheader("Descendant selector (space)")
    nested = root.find('section paragraph')
    print(f"Paragraphs in sections: {len(nested)} found")

    subheader("Combined: type#id")
    unit_item = root.find_one('item#unit')
    print(f"item#unit: {unit_item!r}")
    if unit_item:
        print(f"  text: {unit_item.text}")


# =============================================================================
# 4. Text Extraction
# =============================================================================

def demo_text_extraction():
    header("4. Text Extraction")

    root = pywasot.parse(SAMPLE_DOC)

    subheader(".text - All nested text")
    intro = root.find_one('#intro')
    print(f"Intro section text:\n{intro.text}")

    subheader(".inline_text - Block's inline text")
    print(f"Title inline_text: {root['meta']['title'].inline_text!r}")
    print(f"Author inline_text: {root['meta']['author'].inline_text!r}")

    subheader(".strings - Iterator of all strings")
    arch = root.find_one('#architecture')
    print("Architecture section strings:")
    for i, s in enumerate(arch.strings):
        if i < 5:  # Limit output
            print(f"  {i}: {s!r}")

    subheader(".stripped_strings - Non-empty strings")
    print("Stripped strings (first 5):")
    for i, s in enumerate(arch.stripped_strings):
        if i < 5:
            print(f"  {i}: {s!r}")

    subheader(".get_text() - With options")
    testing = root.find_one('#testing')
    print(f"Joined with ' | ':\n  {testing.get_text(' | ', strip=True)}")


# =============================================================================
# 5. Dict/List-Like Access
# =============================================================================

def demo_dict_list_access():
    header("5. Dict/List-Like Access")

    root = pywasot.parse(SAMPLE_DOC)

    subheader("List-like: index access")
    print(f"root[0] = {root[0]!r}")  # First child (meta)
    print(f"root[1] = {root[1]!r}")  # Second child (content)
    print(f"root[-1] = {root[-1]!r}")  # Last child (footer)

    subheader("List-like: slicing")
    print(f"root[0:2] = {root[0:2]!r}")

    subheader("Dict-like: child by type name")
    print(f"root['meta'] = {root['meta']!r}")
    print(f"root['content']['section'] = {root['content']['section']!r}")

    subheader("Dict-like: special keys")
    meta = root['meta']
    print(f"meta['children'] = {meta['children']!r}")
    print(f"meta['blocks'] = {meta['blocks']!r}")

    subheader("Iteration")
    print("Iterating root['content']:")
    for child in root['content']:
        print(f"  {child!r}")

    subheader("Membership test")
    print(f"'section' in root['content'] = {'section' in root['content']}")
    print(f"'missing' in root['content'] = {'missing' in root['content']}")


# =============================================================================
# 6. Tree Traversal
# =============================================================================

def demo_traversal():
    header("6. Tree Traversal")

    root = pywasot.parse(SAMPLE_DOC)

    subheader("Parent navigation")
    item = root.find_one('item')
    print(f"Item: {item!r}")
    print(f"  .parent = {item.parent!r}")
    print(f"  .parent.parent = {item.parent.parent!r}")

    subheader("Ancestors (all parents up to root)")
    print("Ancestors of first item:")
    for ancestor in item.parents:
        print(f"  {ancestor.type_name}")

    subheader("Root")
    print(f"item.root = {item.root!r}")

    subheader("Descendants (depth-first)")
    meta = root['meta']
    print(f"Descendants of {meta!r}:")
    for desc in meta.descendants:
        print(f"  {desc!r}")


# =============================================================================
# 7. JSON-Like API
# =============================================================================

def demo_json_api():
    header("7. JSON-Like API")

    subheader("loads() - Parse to dict")
    data = pywasot.loads("""
.config
..database
...host .. localhost
...port .. 5432
..cache
...enabled .. true
""")

    import json
    print("Parsed as dict:")
    print(json.dumps(data, indent=2))

    subheader("pywasot.dumps() - Convert back to Wasot")
    wasot_str = pywasot.dumps(data)
    print("Back to Wasot:")
    print(wasot_str)

    subheader("Modify and re-serialize")
    # Access children by index, then find by name
    database = data['children'][0]  # First child is 'database'
    # Modify the host entry (first child of database)
    database['children'][0] = {'name': 'host', 'args': ['production.db.example.com'], 'kwargs': {}, 'text': '', 'children': []}
    print("\nModified:")
    print(pywasot.dumps(data))


# =============================================================================
# 8. Event-Based Parsing
# =============================================================================

def demo_events():
    header("8. Event-Based Parsing")

    content = """.section :demo
..paragraph
Hello, events!
..list
...item
First
...item
Second
"""

    subheader("Iterating events with iter_events()")
    indent = 0
    for event in pywasot.iter_events(content):
        match event:
            case _ if type(event).__name__ == 'BlockStarted':
                print(f"{'  '*indent}BlockStarted: .{event.type_name}")
                indent += 1
            case _ if type(event).__name__ == 'Text':
                print(f"{'  '*indent}Text: {event.content!r}")
            case _ if type(event).__name__ == 'BlockFinished':
                indent = max(0, indent - 1)
                print(f"{'  '*indent}BlockFinished")
            case _:
                print(f"{'  '*indent}{type(event).__name__}")

    subheader("Block.iter_events() - events from tree")
    root = pywasot.parse(content)
    print("Events stored in tree (first 8):")
    for i, event in enumerate(root.iter_events()):
        if i >= 8:
            print("  ...")
            break
        print(f"  {type(event).__name__}")

    subheader("str(block) - formatted event stream")
    small_root = pywasot.parse(""".example :id
..child
text content
""")
    print(small_root)

    subheader("to_events() - iterate events from tree")
    print("Events:")
    for event in small_root.to_events():
        print(f"  {type(event).__name__}")

    subheader("to_jsonl() - JSON lines output")
    print("JSON Lines (first 3):")
    for i, line in enumerate(small_root.to_jsonl()):
        if i >= 3:
            print("  ...")
            break
        print(f"  {line}")


# =============================================================================
# 9. Creating Documents Programmatically
# =============================================================================

def demo_programmatic():
    header("9. Creating Documents Programmatically")

    subheader("Building a tree manually")

    # Create root
    root = pywasot.Block.create('root')

    # Add header section
    header_block = pywasot.Block.create('header')
    title = pywasot.Block.create('title', args=['My Generated Doc'])
    header_block.append(title)
    root.append(header_block)

    # Add content
    content = pywasot.Block.create('content')
    para = pywasot.Block.create('paragraph')
    para.append(pywasot.TextNode.create('This document was created programmatically!'))
    content.append(para)
    root.append(content)

    print(f"Created: {root!r}")
    print(f"Children: {list(root)!r}")
    print()
    print("As Wasot:")
    print(root.to_wasot())

    subheader("Converted to dict")
    print(root.to_dict())


# =============================================================================
# 10. Real-World Example: Config File
# =============================================================================

def demo_config_example():
    header("10. Real-World Example: Config Parser")

    config_doc = """
.config
..app
...title MyAwesomeApp :id123
...version 2.1.0 .. tmp
...debug false
..database
...primary
....host db.example.com
....port 5432
....db_name .. myapp_prod
...replica
....host db-replica.example.com
....port 5432
....db_name myapp_prod .. prod=true
..features
...dark_mode enabled
...beta_features disabled
"""

    config = pywasot.parse(config_doc)

    subheader("Accessing config values via []")
    print(f"App title:   {config['app']['title'].inline_text}")
    print(f"App version: {config['app']['version'].inline_text}")
    print(f"Debug mode:  {config['app']['debug'].inline_text}")

    subheader("Database configuration")
    db = config['database']
    print(f"Primary DB:  {db['primary']['host'].inline_text}:{db['primary']['port'].inline_text}")
    print(f"Replica DB:  {db['replica']['host'].inline_text}:{db['replica']['port'].inline_text}")

    subheader("Feature flags")
    for feature in config['features'].blocks:
        print(f"  {feature.type_name}: {feature.inline_text}")

    subheader("Using .get() for safe access")
    print(f"config.get('app') = {config.get('app')!r}")
    print(f"config.get('nonexistent') = {config.get('nonexistent')}")


# =============================================================================
# Main
# =============================================================================

def main():
    print()
    print("*" * 60)
    print("*" + " " * 58 + "*")
    print("*" + "        PyWasot Feature Demonstration".center(58) + "*")
    print("*" + " " * 58 + "*")
    print("*" * 60)

    demo_parsing_navigation()
    demo_finding()
    demo_selectors()
    demo_text_extraction()
    demo_dict_list_access()
    demo_traversal()
    demo_json_api()
    demo_events()
    demo_programmatic()
    demo_config_example()

    header("Demo Complete!")
    print("Explore pywasot with:")
    print("  - pywasot.parse(source)       : Parse to tree (string, path, or file)")
    print("  - pywasot.iter_events(source) : Iterate parsing events")
    print("  - pywasot.loads(content)      : Parse to dict (JSON-like)")
    print()
    print("Access children via [] or .get():")
    print("  - doc['meta']['title'].inline_text")
    print("  - doc.get('meta')")
    print()

if __name__ == '__main__':
    main()
