"""
HiveMind MCP Server - Parser Tests
Unit tests for code structure extraction.
"""

import pytest
from pathlib import Path
import tempfile
import os

from parser import CodeParser, analyze_directory, FunctionInfo, ImportInfo


class TestCodeParser:
    """Tests for the CodeParser class."""
    
    def setup_method(self):
        """Set up test fixtures."""
        self.parser = CodeParser()
    
    def test_parser_initialization(self):
        """Test that parser initializes correctly."""
        assert self.parser is not None
        # Check if parsers are available (depends on tree-sitter installation)
        assert isinstance(self.parser.parsers, dict)
    
    def test_parse_python_file(self):
        """Test parsing a Python file."""
        f = tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False)
        f.write('''
def hello_world():
    """Say hello."""
    print("Hello, World!")

async def fetch_data(url: str) -> dict:
    """Fetch data from URL."""
    return {}

class MyClass:
    def __init__(self):
        pass
    
    def method(self, arg: int) -> str:
        return str(arg)
''')
        f.close()  # Close before parsing (Windows compatibility)
            
        try:
            result = self.parser.parse_file(Path(f.name))
            
            assert 'functions' in result
            assert 'imports' in result
            assert 'classes' in result
            assert 'file_info' in result
            
            # Check functions were found
            func_names = [func['name'] for func in result['functions']]
            assert 'hello_world' in func_names or 'fetch_data' in func_names
            
        finally:
            os.unlink(f.name)
    
    def test_parse_typescript_file(self):
        """Test parsing a TypeScript file."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.ts', delete=False) as f:
            f.write('''
import { useState } from 'react';
import axios from 'axios';

export function calculateSum(a: number, b: number): number {
    return a + b;
}

export const fetchUser = async (id: string): Promise<User> => {
    const response = await axios.get(`/users/${id}`);
    return response.data;
};

interface User {
    id: string;
    name: string;
}

export default class UserService {
    private apiUrl: string;
    
    constructor(url: string) {
        this.apiUrl = url;
    }
    
    async getUser(id: string): Promise<User> {
        return fetchUser(id);
    }
}
''')
            f.flush()
            
            try:
                result = self.parser.parse_file(Path(f.name))
                
                assert 'functions' in result
                assert 'imports' in result
                assert 'exports' in result
                
                # Check imports were found
                import_modules = [imp['module'] for imp in result['imports']]
                assert 'react' in import_modules or 'axios' in import_modules
                
            finally:
                os.unlink(f.name)
    
    def test_parse_empty_file(self):
        """Test parsing an empty file."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
            f.write('')
            f.flush()
            
            try:
                result = self.parser.parse_file(Path(f.name))
                
                assert result['functions'] == []
                assert result['imports'] == []
                
            finally:
                os.unlink(f.name)
    
    def test_parse_unsupported_extension(self):
        """Test parsing file with unsupported extension."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.xyz', delete=False) as f:
            f.write('some content')
            f.flush()
            
            try:
                result = self.parser.parse_file(Path(f.name))
                
                # Should return empty result without error
                assert result['functions'] == []
                
            finally:
                os.unlink(f.name)


class TestAnalyzeDirectory:
    """Tests for the analyze_directory function."""
    
    def test_analyze_simple_directory(self):
        """Test analyzing a simple directory."""
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create a simple Python file
            py_file = Path(tmpdir) / 'main.py'
            py_file.write_text('''
def main():
    print("Hello")

def helper(x: int) -> int:
    return x * 2
''')
            
            result = analyze_directory(Path(tmpdir))
            
            assert result['name'] == Path(tmpdir).name
            assert result['path'] == str(Path(tmpdir).resolve())
            assert len(result['files']) >= 1
            assert result['metrics']['total_files'] >= 1
    
    def test_analyze_directory_with_children(self):
        """Test analyzing directory with subdirectories."""
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create subdirectory
            subdir = Path(tmpdir) / 'submodule'
            subdir.mkdir()
            
            # Create file in subdir
            (subdir / 'module.py').write_text('def func(): pass')
            
            result = analyze_directory(Path(tmpdir))
            
            assert len(result['children']) >= 1
            assert str(subdir) in result['children']
    
    def test_analyze_ignores_node_modules(self):
        """Test that node_modules is ignored."""
        with tempfile.TemporaryDirectory() as tmpdir:
            # Create node_modules
            node_modules = Path(tmpdir) / 'node_modules'
            node_modules.mkdir()
            (node_modules / 'package.json').write_text('{}')
            
            result = analyze_directory(Path(tmpdir))
            
            # node_modules should not be in children
            for child in result['children']:
                assert 'node_modules' not in child


class TestDataClasses:
    """Tests for data classes."""
    
    def test_function_info_to_dict(self):
        """Test FunctionInfo conversion to dict."""
        func = FunctionInfo(
            name='testFunc',
            params='(a: int, b: str)',
            return_type='bool',
            start_line=10,
            end_line=20,
            is_async=True,
            exported=True,
            complexity=5,
        )
        
        d = func.to_dict()
        
        assert d['name'] == 'testFunc'
        assert d['params'] == '(a: int, b: str)'
        assert d['return_type'] == 'bool'
        assert d['async'] is True
        assert d['exported'] is True
        assert d['complexity'] == 5
    
    def test_import_info_to_dict(self):
        """Test ImportInfo conversion to dict."""
        imp = ImportInfo(
            module='react',
            imports=['useState', 'useEffect'],
            is_default=False,
            is_namespace=False,
        )
        
        d = imp.to_dict()
        
        assert d['module'] == 'react'
        assert 'useState' in d['imports']
        assert d['is_default'] is False


if __name__ == '__main__':
    pytest.main([__file__, '-v'])
