# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['MarkdownProcessor', 'MarkdownWatcher', 'literati', 'md_to_py']

# %% ../nbs/00_core.ipynb 4
from fastcore.basics import *
from fastcore.foundation import *
from fastcore.test import *
from fastcore.script import call_parse, Param

from pathlib import Path
import re, time
import threading

from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler


class MarkdownProcessor:
    """Handles the processing of markdown files to extract code blocks"""
    def __init__(self, output_dir='py'):
        self.output_dir = Path(output_dir)
    
    def should_process(self, path):
        "Check if the markdown file should be processed"
        return path.suffix == '.md' and path.name.lower() != 'readme.md'
    
    def extract_code(self, md_content):
        "Extract code blocks from markdown content"
        pattern = r'`{3}[\w\s]*\n(.*?)`{3}|`([^`]+)`'
        code_blocks = []
        for match in re.finditer(pattern, md_content, re.DOTALL):
            code = match.group(1) or match.group(2)
            if code: code_blocks.append(code)
        return '\n'.join(code_blocks)
    
    def process_file(self, md_path):
        "Process a markdown file and save extracted code"
        if not self.should_process(Path(md_path)): return None
        
        content = Path(md_path).read_text()
        code = self.extract_code(content)
        if code:  # only create an output file if any code was extracted
            self.output_dir.mkdir(exist_ok=True)
            py_path = self.output_dir/f"{Path(md_path).stem}.py"
            py_path.write_text(code)
            return py_path
        return None

    def process_directory(self, input_dir):
        "Process all markdown files in the given directory"
        input_path = Path(input_dir)
        if not input_path.exists():
            raise ValueError(f"Directory {input_dir} does not exist")
        
        processed_files_containing_code = []
        for md_file in input_path.glob('**/*.md'):  # includes subdirectories
            if result := self.process_file(md_file):
                processed_files_containing_code.append(result)
    
        return processed_files_containing_code

# %% ../nbs/00_core.ipynb 16
class MarkdownWatcher(FileSystemEventHandler):
    """Watches for markdown file changes and triggers processing"""
    def __init__(self, processor):
        self.processor = processor
    
    def on_modified(self, event):
        self.processor.process_file(event.src_path)
        
    def on_created(self, event):
        self.processor.process_file(event.src_path)

# %% ../nbs/00_core.ipynb 20
@call_parse
def literati(path:Param("Directory to monitor", str)='.', 
             output_dir:Param("Output directory for Python files", str)='py'):
    "Monitor markdown files and extract code blocks to Python files"
    processor = MarkdownProcessor(output_dir=output_dir)
    
    # Process existing files first
    processor.process_directory(path)
    
    handler = MarkdownWatcher(processor)
    
    observer = Observer()
    observer.schedule(handler, path, recursive=False)
    observer.start()
    
    print(f"G'day! Monitoring {path} for markdown files...")
    print(f"Python files will be saved to {output_dir}/")
    print("Optimizing the servo run... (Press Ctrl+C to stop)")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
        observer.join()
    
    return observer

@call_parse
def md_to_py(
    input_dir: Param("Input directory containing markdown files", str),
    output_dir: Param("Output directory for Python files", str)='py'
):
    "Convert markdown files in input_dir to Python files in output_dir"
    processor = MarkdownProcessor(output_dir=output_dir)
    processed = processor.process_directory(input_dir)
    print(f"Processed {len(processed)} files:")
    for file in processed:
        print(f"  {file}")
