# MarkiTect Plugin System

The MarkiTect Plugin System provides a flexible and extensible architecture for adding custom functionality to MarkiTect. Plugins can extend processors, formatters, validators, exporters, and more.

## Plugin Types

### Supported Plugin Types

- **Processor**: Content processors (markdown, text transformation, etc.)
- **Formatter**: Output formatters (JSON, YAML, tables, etc.)
- **Validator**: Content validators (schema validation, lint checking, etc.)
- **Exporter**: Export handlers (PDF, HTML, etc.)
- **Generator**: Content generators (templates, stubs, etc.)
- **Importer**: Import handlers (various formats)
- **Transformer**: Content transformers (data manipulation, etc.)
- **Extension**: General extensions (any functionality)
- **Backend**: Storage/API backends (databases, APIs, etc.)
- **Command**: CLI command extensions

## Quick Start

### Creating a Simple Plugin

```python
from markitect.plugins import BasePlugin, PluginMetadata, PluginType, register_plugin

@register_plugin("my_processor")
class MyProcessor(ProcessorPlugin):
    @property
    def metadata(self) -> PluginMetadata:
        return PluginMetadata(
            name="my_processor",
            version="1.0.0",
            description="My custom processor",
            author="Your Name",
            plugin_type=PluginType.PROCESSOR
        )

    def process(self, content: str, **kwargs) -> str:
        # Your processing logic here
        return content.upper()
```

### Using Plugins via CLI

```bash
# List all available plugins
markitect plugin-list

# Load a specific plugin
markitect plugin-load my_processor

# Get plugin information
markitect plugin-info my_processor

# Discover new plugins
markitect plugin-discover --refresh
```

### Using Plugins Programmatically

```python
from markitect.plugins import PluginManager

# Initialize plugin manager
manager = PluginManager()

# Discover and load plugins
manager.discover_plugins()
processor = manager.load_plugin("my_processor")

# Use the plugin
if processor:
    result = processor.process("hello world")
    print(result)  # HELLO WORLD
```

## Plugin Development Guide

### 1. Choose Base Class

Select the appropriate base class for your plugin:

```python
from markitect.plugins.base import (
    ProcessorPlugin,    # For content processing
    FormatterPlugin,    # For output formatting
    ValidatorPlugin,    # For content validation
    ExporterPlugin,     # For export functionality
    CommandPlugin,      # For CLI commands
    BasePlugin          # For general extensions
)
```

### 2. Implement Required Methods

Each plugin type has specific methods you must implement:

#### ProcessorPlugin

```python
class MyProcessor(ProcessorPlugin):
    def process(self, content: str, **kwargs) -> str:
        """Process content and return result."""
        return processed_content

    def can_process(self, content: str, **kwargs) -> bool:
        """Check if this processor can handle the content."""
        return True  # or your logic
```

#### FormatterPlugin

```python
class MyFormatter(FormatterPlugin):
    def format(self, data: Any, **kwargs) -> str:
        """Format data to string representation."""
        return formatted_string

    def get_file_extension(self) -> str:
        """Get file extension for this format."""
        return '.txt'
```

#### ValidatorPlugin

```python
class MyValidator(ValidatorPlugin):
    def validate(self, content: str, **kwargs) -> List[str]:
        """Validate content and return list of errors."""
        errors = []
        # Your validation logic
        return errors
```

### 3. Add Metadata

```python
@property
def metadata(self) -> PluginMetadata:
    return PluginMetadata(
        name="plugin_name",
        version="1.0.0",
        description="Plugin description",
        author="Your Name",
        plugin_type=PluginType.PROCESSOR,  # Choose appropriate type
        dependencies=["optional", "list", "of", "dependencies"],
        markitect_version=">=0.1.0"
    )
```

### 4. Register Plugin

Use the decorator for automatic registration:

```python
@register_plugin("plugin_name")
class MyPlugin(BasePlugin):
    # Implementation
```

Or register manually:

```python
from markitect.plugins import plugin_registry

plugin_registry.register(MyPlugin, "plugin_name")
```

## Configuration

### Plugin Configuration File

Create a configuration file (`.markitect/plugins.yml`) to manage plugins:

```yaml
plugin_directories:
  - "plugins"
  - ".markitect/plugins"
  - "~/.markitect/plugins"

auto_discover: true
auto_load_enabled: true

plugins:
  my_processor:
    enabled: true
    config:
      option1: value1
      option2: value2

  json_formatter:
    enabled: true
    config:
      indent: 4
```

### Plugin Configuration in Code

```python
# Load plugin with configuration
config = {"option1": "value1", "option2": "value2"}
plugin = manager.load_plugin("my_processor", config)

# Access configuration in plugin
class MyProcessor(ProcessorPlugin):
    def process(self, content: str, **kwargs) -> str:
        option1 = self.config.get('option1', 'default')
        # Use configuration
        return processed_content
```

## Built-in Plugins

MarkiTect includes several built-in plugins:

### Formatters
- `json_formatter`: Format output as JSON
- `yaml_formatter`: Format output as YAML
- `table_formatter`: Format output as ASCII tables

### Processors
- `markdown_processor`: Process markdown content
- `text_processor`: Process generic text content

## Plugin Discovery

Plugins are discovered from:

1. **Built-in plugins**: `markitect.plugins.builtin.*`
2. **Local directories**: Configured plugin directories
3. **Installed packages**: Python packages with entry points (future)

### Plugin Directory Structure

```
plugins/
├── my_plugin.py          # Single file plugin
├── complex_plugin/       # Multi-file plugin
│   ├── __init__.py
│   ├── main.py
│   └── utils.py
└── another_plugin.py
```

## Advanced Features

### Plugin Dependencies

Specify dependencies in metadata:

```python
PluginMetadata(
    # ...
    dependencies=["requests", "pyyaml"],
    markitect_version=">=0.2.0"
)
```

### Plugin Initialization and Cleanup

```python
class MyPlugin(BasePlugin):
    def _initialize(self) -> None:
        """Called when plugin is loaded."""
        self.connection = setup_connection()

    def cleanup(self) -> None:
        """Called when plugin is unloaded."""
        if hasattr(self, 'connection'):
            self.connection.close()
```

### Configuration Validation

```python
def validate_config(self) -> List[str]:
    """Validate plugin configuration."""
    errors = []

    if 'required_option' not in self.config:
        errors.append("Missing required_option")

    return errors
```

### Command Plugins

Extend the CLI with custom commands:

```python
import click

class MyCommandPlugin(CommandPlugin):
    def get_commands(self) -> Dict[str, Any]:
        return {
            'my-command': self.my_command
        }

    @click.command()
    @click.argument('input_file')
    def my_command(self, input_file):
        """My custom command."""
        click.echo(f"Processing {input_file}")
```

## Best Practices

### 1. Error Handling

```python
def process(self, content: str, **kwargs) -> str:
    try:
        return self._do_processing(content)
    except Exception as e:
        # Log error but don't crash
        self.logger.error(f"Processing failed: {e}")
        return content  # Return original content
```

### 2. Configuration Defaults

```python
def _initialize(self) -> None:
    # Set defaults for configuration
    defaults = {
        'timeout': 30,
        'retries': 3,
        'format': 'json'
    }

    for key, value in defaults.items():
        if key not in self.config:
            self.config[key] = value
```

### 3. Graceful Degradation

```python
def can_process(self, content: str, **kwargs) -> bool:
    """Only claim we can process if we actually can."""
    try:
        # Test if content is processable
        return self._test_content(content)
    except Exception:
        return False
```

### 4. Documentation

Always provide clear documentation for your plugins:

```python
class MyProcessor(ProcessorPlugin):
    """
    Advanced text processor for MarkiTect.

    This processor provides advanced text transformation capabilities
    including normalization, cleanup, and format conversion.

    Configuration:
        normalize_whitespace (bool): Normalize whitespace (default: True)
        remove_comments (bool): Remove comment lines (default: False)
        encoding (str): Text encoding (default: 'utf-8')

    Example:
        processor = MyProcessor({
            'normalize_whitespace': True,
            'remove_comments': True
        })

        result = processor.process(content)
    """
```

## Testing Plugins

Create comprehensive tests for your plugins:

```python
import pytest
from markitect.plugins import plugin_registry

def test_my_processor():
    # Load plugin
    plugin = plugin_registry.get_plugin("my_processor")
    assert plugin is not None

    # Test processing
    result = plugin.process("test content")
    assert result == "expected result"

    # Test error handling
    result = plugin.process(None)
    assert result is not None
```

## Troubleshooting

### Common Issues

1. **Plugin not discovered**: Check plugin directory configuration
2. **Import errors**: Ensure all dependencies are installed
3. **Registration fails**: Check plugin class inheritance
4. **Plugin not loading**: Check `_initialize()` method

### Debug Mode

Enable verbose logging to debug plugin issues:

```bash
markitect --verbose plugin-list
markitect --verbose plugin-load my_plugin
```

### Plugin Validation

```bash
# Validate specific plugin
markitect plugin-info my_plugin

# Discover and validate all plugins
markitect plugin-discover --refresh
```