#!/usr/bin/env python3
"""
Tests for CLI module
"""

import sys

# Add project root to path
sys.path.insert(0, ".")

import sys
import tempfile
from io import StringIO
from pathlib import Path

import pytest

from tree_sitter_analyzer.cli_main import main


class TestCLI:
    """Test cases for CLI functionality"""

    def test_show_query_languages(self, monkeypatch):
        """Test --show-query-languages option"""
        monkeypatch.setattr(sys, "argv", ["cli", "--show-query-languages"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass  # Expected for some CLI commands

        output = mock_stdout.getvalue()
        assert "Languages with query support" in output
        assert "java" in output
        assert "javascript" in output
        assert "python" in output

    def test_show_supported_languages(self, monkeypatch):
        """Test --show-supported-languages option"""
        monkeypatch.setattr(sys, "argv", ["cli", "--show-supported-languages"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        assert "Supported languages" in output

    def test_show_supported_extensions(self, monkeypatch):
        """Test --show-supported-extensions option"""
        monkeypatch.setattr(sys, "argv", ["cli", "--show-supported-extensions"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        assert "Supported file extensions" in output

    def test_show_common_queries(self, monkeypatch):
        """Test --show-common-queries option"""
        monkeypatch.setattr(sys, "argv", ["cli", "--show-common-queries"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        assert "Common queries across multiple languages" in output
        # Check for some common query names
        assert any(
            query in output
            for query in [
                "class_names",
                "method_names",
                "imports",
                "all_declarations",
            ]
        )

    def test_list_queries_with_language(self, monkeypatch):
        """Test --list-queries with --language option"""
        monkeypatch.setattr(
            sys, "argv", ["cli", "--list-queries", "--language", "java"]
        )
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        assert "java" in output.lower()

    def test_list_queries_without_language(self, monkeypatch):
        """Test --list-queries without language specification"""
        monkeypatch.setattr(sys, "argv", ["cli", "--list-queries"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        assert "Supported languages" in output

    def test_describe_query_with_language(self, monkeypatch):
        """Test --describe-query with --language option"""
        monkeypatch.setattr(
            sys, "argv", ["cli", "--describe-query", "class", "--language", "java"]
        )
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()

        assert "class" in output
        output = mock_stdout.getvalue()
        # This should show an error message since no language is specified
        # The error goes to stderr, so check that stdout is empty

        assert "java" in output.lower()

    def test_describe_query_without_language(self, monkeypatch):
        """Test --describe-query without language specification"""
        monkeypatch.setattr(sys, "argv", ["cli", "--describe-query", "class"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        # This should show an error message since no language is specified
        # The error goes to stderr, so check that stdout is empty
        _ = mock_stdout.getvalue()

    def test_analyze_java_file(self, monkeypatch):
        """Test analyzing a Java file"""
        # Create a temporary Java file
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                ["cli", temp_path, "--project-root", temp_dir, "--advanced"],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should contain some analysis results
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_analyze_with_query_key(self, monkeypatch):
        """Test analyzing file with specific query"""
        # Create a temporary Java file
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                [
                    "cli",
                    temp_path,
                    "--query-key",
                    "classes",
                    "--project-root",
                    temp_dir,
                ],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should contain class name analysis
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_analyze_with_custom_query(self, monkeypatch):
        """Test analyzing file with custom query string"""
        # Create a temporary Java file
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            custom_query = "(class_declaration name: (identifier) @class-name)"
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                [
                    "cli",
                    temp_path,
                    "--query-string",
                    custom_query,
                    "--project-root",
                    temp_dir,
                ],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should contain query results
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_language_detection(self, monkeypatch):
        """Test automatic language detection"""
        # Create a temporary Python file
        python_code = """
def hello_world():
    print("Hello, World!")

if __name__ == "__main__":
    hello_world()
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".py", delete=False, encoding="utf-8"
        ) as f:
            f.write(python_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                ["cli", temp_path, "--project-root", temp_dir, "--advanced"],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should automatically detect Python and analyze
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_explicit_language_override(self, monkeypatch):
        """Test explicit language specification"""
        # Create a temporary file with .txt extension but Java content
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".txt", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                ["cli", temp_path, "--language", "java", "--project-root", temp_dir],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should treat file as Java despite .txt extension
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_unsupported_file_extension(self, monkeypatch):
        """Test handling of unsupported file extensions"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".xyz", delete=False, encoding="utf-8"
        ) as f:
            f.write("some content")
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys, "argv", ["cli", temp_path, "--project-root", temp_dir]
            )
            mock_stderr = StringIO()
            monkeypatch.setattr("sys.stderr", mock_stderr)

            try:
                main()
            except SystemExit:
                pass

            error_output = mock_stderr.getvalue()
            # Should contain error message about unsupported extension
            assert "Could not determine language for file" in error_output
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_nonexistent_file(self, monkeypatch):
        """Test handling of nonexistent files"""
        nonexistent_path = "/path/that/does/not/exist.java"
        monkeypatch.setattr(
            sys, "argv", ["cli", nonexistent_path, "--project-root", "/tmp"]
        )
        mock_stderr = StringIO()
        monkeypatch.setattr("sys.stderr", mock_stderr)

        try:
            main()
        except SystemExit:
            pass

        error_output = mock_stderr.getvalue()
        # Should contain error message about invalid file path (security validation)
        assert "Invalid file path" in error_output

    def test_output_format_json(self, monkeypatch):
        """Test JSON output format"""
        # Create a temporary Java file
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                [
                    "cli",
                    temp_path,
                    "--output-format",
                    "json",
                    "--advanced",
                    "--project-root",
                    temp_dir,
                ],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should contain JSON formatted output
            assert "{" in output or "[" in output
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_output_format_text(self, monkeypatch):
        """Test text output format"""
        # Create a temporary Java file
        java_code = """
public class TestClass {
    public void testMethod() {
        System.out.println("Hello, World!");
    }
}
"""
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                [
                    "cli",
                    temp_path,
                    "--output-format",
                    "text",
                    "--project-root",
                    temp_dir,
                    "--advanced",
                ],
            )
            mock_stdout = StringIO()
            monkeypatch.setattr("sys.stdout", mock_stdout)

            try:
                main()
            except SystemExit:
                pass

            output = mock_stdout.getvalue()
            # Should contain text formatted output
            assert len(output) > 0
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()


class TestCLIEdgeCases:
    """Test edge cases and error conditions"""

    def test_no_arguments(self, monkeypatch):
        """Test CLI with no arguments"""
        monkeypatch.setattr(sys, "argv", ["cli"])
        mock_stderr = StringIO()
        monkeypatch.setattr("sys.stderr", mock_stderr)

        try:
            main()
        except SystemExit:
            pass

        error_output = mock_stderr.getvalue()
        # Should show help or error message
        assert len(error_output) > 0

    def test_invalid_query_key(self, monkeypatch):
        """Test with invalid query key"""
        # Create a temporary Java file
        java_code = "public class TestClass {}"
        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".java", delete=False, encoding="utf-8"
        ) as f:
            f.write(java_code)
            temp_path = f.name

        try:
            temp_dir = str(Path(temp_path).parent)
            monkeypatch.setattr(
                sys,
                "argv",
                [
                    "cli",
                    temp_path,
                    "--query-key",
                    "invalid_query_key",
                    "--project-root",
                    temp_dir,
                ],
            )
            mock_stderr = StringIO()
            monkeypatch.setattr("sys.stderr", mock_stderr)

            try:
                main()
            except SystemExit:
                pass

            error_output = mock_stderr.getvalue()
            # Should contain error about invalid query
            assert "not found" in error_output
        finally:
            # Clean up
            temp_file = Path(temp_path)
            if temp_file.exists():
                temp_file.unlink()

    def test_help_option(self, monkeypatch):
        """Test help option"""
        monkeypatch.setattr(sys, "argv", ["cli", "--help"])
        mock_stdout = StringIO()
        monkeypatch.setattr("sys.stdout", mock_stdout)

        try:
            main()
        except SystemExit:
            pass

        output = mock_stdout.getvalue()
        # Should contain help text
        assert "usage" in output.lower()


if __name__ == "__main__":
    pytest.main([__file__])
