"""
HiveMind MCP Server - Generator
Generate hivemind.md and flowchart.mmd from structure and AI context.
"""

import os
from pathlib import Path
from typing import Dict, List, Optional, Any
from datetime import datetime
import aiofiles

from config import HIVEMIND_FILENAME, FLOWCHART_FILENAME, get_complexity_label
from utils import (
    sanitize_filename,
    create_anchor,
    format_list,
    format_code_block,
    get_relative_path,
    truncate_string,
)


async def generate_hivemind(
    structure: Dict[str, Any],
    ai_context: Optional[Dict[str, Any]] = None
) -> str:
    """
    Generate hivemind.md content from structure and AI context.
    
    Args:
        structure: Parsed structure dictionary from parser.analyze_directory()
        ai_context: Optional AI-provided context dictionary
        
    Returns:
        Formatted markdown string
    """
    ai_context = ai_context or {}
    sections = []
    
    # Header
    dir_name = structure.get('name', 'Unknown')
    sections.append(f"# {dir_name}")
    sections.append("")
    
    # ============================================================
    # AI Context Sections (above the line)
    # ============================================================
    
    # 🎯 What This Does
    if ai_context.get('context'):
        sections.append("## What This Does")
        sections.append(ai_context['context'])
        sections.append("")
    
    # 👤 User Requirements
    if ai_context.get('user_requirements'):
        sections.append("## User Requirements")
        sections.append(ai_context['user_requirements'])
        sections.append("")
    
    # ⚠️ Important Notes
    if ai_context.get('warnings'):
        sections.append("## Important Notes")
        sections.append(ai_context['warnings'])
        sections.append("")
    
    # 🔮 Next Steps
    if ai_context.get('next_steps'):
        sections.append("## Next Steps")
        sections.append(ai_context['next_steps'])
        sections.append("")
    
    # 💡 How It Works
    if ai_context.get('how_it_works'):
        sections.append("## How It Works")
        sections.append(ai_context['how_it_works'])
        sections.append("")
    
    # ============================================================
    # Separator
    # ============================================================
    sections.append("---")
    sections.append("")
    
    # ============================================================
    # Dry Logic Sections (below the line)
    # ============================================================
    
    # 📁 Files at This Level
    files = structure.get('files', [])
    if files:
        sections.append("## Files at This Level")
        for f in files:
            name = f.get('name', 'unknown')
            lines = f.get('lines', 0)
            sections.append(f"- `{name}` ({lines} lines)")
        sections.append("")
    
    # ⚙️ Functions Defined
    functions = structure.get('all_functions', [])
    if functions:
        sections.append("## Functions Defined")
        sections.append("")
        
        for func in functions:
            name = func.get('name', 'unknown')
            params = func.get('params', '()')
            return_type = func.get('return_type', 'void')
            
            # Function signature
            sections.append(f"### `{name}{params}: {return_type}`")
            
            # Details
            file_name = Path(func.get('file_path', '')).name if func.get('file_path') else 'unknown'
            start = func.get('start_line', 0)
            end = func.get('end_line', 0)
            sections.append(f"- **Location**: {file_name}:{start}-{end}")
            sections.append(f"- **Async**: {'Yes' if func.get('async') else 'No'}")
            sections.append(f"- **Exported**: {'Yes' if func.get('exported') else 'No'}")
            sections.append(f"- **Complexity**: {func.get('complexity_label', 'Low')}")
            
            if func.get('docstring'):
                sections.append(f"- **Description**: {truncate_string(func['docstring'], 100)}")
            
            sections.append("")
    
    # 📦 Dependencies
    imports = structure.get('all_imports', [])
    if imports:
        sections.append("## Dependencies")
        sections.append("")
        
        external = []
        internal = []
        
        for imp in imports:
            module = imp.get('module', '')
            names = ', '.join(imp.get('imports', []))
            
            if module.startswith('.') or module.startswith('@/') or module.startswith('~/'):
                internal.append(f"- `{module}` - {names or 'namespace'}")
            else:
                external.append(f"- `{module}` - {names or 'namespace'}")
        
        if external:
            sections.append("### External")
            sections.extend(external)
            sections.append("")
        
        if internal:
            sections.append("### Internal")
            sections.extend(internal)
            sections.append("")
    
    # 📤 Exports
    exports = structure.get('all_exports', [])
    if exports:
        sections.append("## Exports")
        sections.append("")
        
        export_lines = []
        for exp in exports:
            name = exp.get('name', '')
            exp_type = exp.get('type', 'named')
            is_default = exp.get('is_default', False)
            
            if is_default:
                export_lines.append(f"export default {name}")
            else:
                export_lines.append(f"export {exp_type} {name}")
        
        if export_lines:
            sections.append(format_code_block('\n'.join(export_lines), 'typescript'))
            sections.append("")
    
    # Classes
    classes = structure.get('all_classes', [])
    if classes:
        sections.append("## Classes")
        sections.append("")
        
        for cls in classes:
            name = cls.get('name', 'Unknown')
            extends = cls.get('extends')
            sections.append(f"### `{name}`" + (f" extends `{extends}`" if extends else ""))
            sections.append(f"- **Lines**: {cls.get('start_line', 0)}-{cls.get('end_line', 0)}")
            sections.append(f"- **Exported**: {'Yes' if cls.get('exported') else 'No'}")
            
            methods = cls.get('methods', [])
            if methods:
                sections.append(f"- **Methods**: {len(methods)}")
                for m in methods[:5]:  # Limit to 5 methods shown
                    sections.append(f"  - `{m.get('name', '')}()`")
                if len(methods) > 5:
                    sections.append(f"  - _...and {len(methods) - 5} more_")
            sections.append("")
    
    # Types (TypeScript)
    types = structure.get('all_types', [])
    if types:
        sections.append("## Types & Interfaces")
        sections.append("")
        
        for t in types:
            kind = t.get('kind', 'type')
            name = t.get('name', 'Unknown')
            sections.append(f"- `{kind} {name}` (line {t.get('start_line', 0)})")
        sections.append("")
    
    # 🔗 Connections
    connections = structure.get('connections', {})
    uses = connections.get('uses', [])
    used_by = connections.get('used_by', [])
    
    if uses or used_by:
        sections.append("## Connections")
        sections.append("")
        
        if used_by:
            sections.append("### Used By (Downstream)")
            for dep in used_by:
                anchor = create_anchor(Path(dep))
                sections.append(f"- `{anchor}`")
            sections.append("")
        
        if uses:
            sections.append("### Uses (Upstream)")
            for dep in uses:
                anchor = create_anchor(Path(dep))
                sections.append(f"- `{anchor}`")
            sections.append("")
    
    # Navigation
    sections.append("## Navigation")
    sections.append("")
    
    current_path = Path(structure.get('path', ''))
    parent = structure.get('parent')
    children = structure.get('children', [])
    
    # Parent link
    if parent:
        parent_path = Path(parent)
        rel_path = get_relative_path(current_path, parent_path)
        anchor = create_anchor(parent_path)
        sections.append(f"- **Parent**: [{parent_path.name}]({rel_path}/hivemind.md) `{anchor}`")
    
    # Children links
    if children:
        sections.append("- **Children**:")
        for child in children:
            child_path = Path(child)
            rel_path = get_relative_path(current_path, child_path)
            anchor = create_anchor(child_path)
            sections.append(f"  - [{child_path.name}]({rel_path}/hivemind.md) `{anchor}`")
    
    # Current anchor
    current_anchor = create_anchor(current_path)
    sections.append(f"- **Anchor**: `{current_anchor}`")
    sections.append("")
    
    # 📊 Metrics
    metrics = structure.get('metrics', {})
    sections.append("## Metrics")
    sections.append("")
    sections.append(f"- **Total Lines**: {metrics.get('total_lines', 0)}")
    sections.append(f"- **Total Files**: {metrics.get('total_files', 0)}")
    sections.append(f"- **Functions**: {metrics.get('total_functions', 0)}")
    sections.append(f"- **Classes**: {metrics.get('total_classes', 0)}")
    sections.append(f"- **Types**: {metrics.get('total_types', 0)}")
    sections.append(f"- **Avg Complexity**: {metrics.get('complexity_label', 'Low')} ({metrics.get('avg_complexity', 1.0)})")
    sections.append(f"- **Last Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M')}")
    sections.append("")
    
    return '\n'.join(sections)


async def generate_flowchart(structure: Dict[str, Any]) -> str:
    """
    Generate Mermaid flowchart from structure.
    
    Args:
        structure: Parsed structure dictionary
        
    Returns:
        Mermaid diagram string
    """
    lines = []
    lines.append("graph TD")
    lines.append("")
    
    # Current directory as central node
    current_name = structure.get('name', 'current')
    current_id = sanitize_filename(current_name)
    lines.append(f"    %% Current directory as central node")
    lines.append(f"    {current_id}[{current_name}]")
    lines.append("")
    
    # Parent link
    parent = structure.get('parent')
    if parent:
        parent_name = Path(parent).name
        parent_id = sanitize_filename(f"parent_{parent_name}")
        lines.append(f"    %% Parent link")
        lines.append(f"    {parent_id}[{parent_name}] --> {current_id}")
        lines.append("")
    
    # Children links
    children = structure.get('children', [])
    if children:
        lines.append(f"    %% Children")
        for child in children:
            child_name = Path(child).name
            child_id = sanitize_filename(f"child_{child_name}")
            lines.append(f"    {current_id} --> {child_id}[{child_name}]")
        lines.append("")
    
    # Upstream dependencies (things this imports)
    connections = structure.get('connections', {})
    uses = connections.get('uses', [])
    if uses:
        lines.append(f"    %% Upstream dependencies (things this imports)")
        for i, dep in enumerate(uses[:5]):  # Limit to 5
            dep_name = Path(dep).name
            dep_id = sanitize_filename(f"dep_{dep_name}_{i}")
            lines.append(f"    {dep_id}[{dep_name}] --> {current_id}")
        lines.append("")
    
    # Downstream usage (things that import this)
    used_by = connections.get('used_by', [])
    if used_by:
        lines.append(f"    %% Downstream usage (things that import this)")
        for i, dep in enumerate(used_by[:5]):  # Limit to 5
            dep_name = Path(dep).name
            dep_id = sanitize_filename(f"user_{dep_name}_{i}")
            lines.append(f"    {current_id} --> {dep_id}[{dep_name}]")
        lines.append("")
    
    # Styling
    lines.append("    %% Styling for visual clarity")
    lines.append("    classDef currentNode fill:#4f46e5,stroke:#333,stroke-width:3px,color:#fff")
    lines.append("    classDef parentNode fill:#64748b,stroke:#333,stroke-width:2px,color:#fff")
    lines.append("    classDef childNode fill:#10b981,stroke:#333,stroke-width:2px,color:#fff")
    lines.append("    classDef upstreamNode fill:#f59e0b,stroke:#333,stroke-width:2px,color:#fff")
    lines.append("    classDef downstreamNode fill:#06b6d4,stroke:#333,stroke-width:2px,color:#fff")
    lines.append("")
    
    # Apply styles
    lines.append(f"    class {current_id} currentNode")
    
    if parent:
        parent_name = Path(parent).name
        parent_id = sanitize_filename(f"parent_{parent_name}")
        lines.append(f"    class {parent_id} parentNode")
    
    if children:
        child_ids = [sanitize_filename(f"child_{Path(c).name}") for c in children]
        lines.append(f"    class {','.join(child_ids)} childNode")
    
    if uses:
        dep_ids = [sanitize_filename(f"dep_{Path(d).name}_{i}") for i, d in enumerate(uses[:5])]
        lines.append(f"    class {','.join(dep_ids)} upstreamNode")
    
    if used_by:
        user_ids = [sanitize_filename(f"user_{Path(d).name}_{i}") for i, d in enumerate(used_by[:5])]
        lines.append(f"    class {','.join(user_ids)} downstreamNode")
    
    return '\n'.join(lines)


async def write_files(
    dir_path: Path,
    hivemind_content: str,
    flowchart_content: str,
) -> Dict[str, Any]:
    """
    Write hivemind.md and flowchart.mmd to directory.
    
    Args:
        dir_path: Directory to write files to
        hivemind_content: Content for hivemind.md
        flowchart_content: Content for flowchart.mmd
        
    Returns:
        Dictionary with write status and file paths
    """
    result = {
        'success': True,
        'files_written': [],
        'errors': [],
    }
    
    # Ensure directory exists
    dir_path = Path(dir_path)
    try:
        dir_path.mkdir(parents=True, exist_ok=True)
    except Exception as e:
        result['success'] = False
        result['errors'].append(f"Failed to create directory: {e}")
        return result
    
    # Write hivemind.md
    hivemind_path = dir_path / HIVEMIND_FILENAME
    try:
        async with aiofiles.open(hivemind_path, 'w', encoding='utf-8') as f:
            await f.write(hivemind_content)
        result['files_written'].append(str(hivemind_path))
    except Exception as e:
        result['success'] = False
        result['errors'].append(f"Failed to write {HIVEMIND_FILENAME}: {e}")
    
    # Write flowchart.mmd
    flowchart_path = dir_path / FLOWCHART_FILENAME
    try:
        async with aiofiles.open(flowchart_path, 'w', encoding='utf-8') as f:
            await f.write(flowchart_content)
        result['files_written'].append(str(flowchart_path))
    except Exception as e:
        result['success'] = False
        result['errors'].append(f"Failed to write {FLOWCHART_FILENAME}: {e}")
    
    return result


async def generate_and_write(
    structure: Dict[str, Any],
    ai_context: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """
    Generate documentation and write to directory.
    
    Convenience function that combines generation and writing.
    
    Args:
        structure: Parsed structure dictionary
        ai_context: Optional AI context
        
    Returns:
        Result dictionary with status and details
    """
    dir_path = Path(structure.get('path', '.'))
    
    # Generate content
    hivemind_content = await generate_hivemind(structure, ai_context)
    flowchart_content = await generate_flowchart(structure)
    
    # Write files
    result = await write_files(dir_path, hivemind_content, flowchart_content)
    
    # Add summary
    result['directory'] = str(dir_path)
    result['hivemind_lines'] = len(hivemind_content.split('\n'))
    result['flowchart_lines'] = len(flowchart_content.split('\n'))
    
    return result
