# Copyright 2025 Vijaykumar Singh <singhvjd@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Java language plugin."""

from pathlib import Path
from typing import Optional

from victor.languages.base import (
    BaseLanguagePlugin,
    BuildSystem,
    CommentStyle,
    Formatter,
    LanguageCapabilities,
    LanguageConfig,
    Linter,
    QueryPattern,
    TestRunner,
    TreeSitterQueries,
)


class JavaPlugin(BaseLanguagePlugin):
    """Java language plugin.

    Supports:
    - Testing: JUnit, Maven Surefire, Gradle Test
    - Formatting: google-java-format
    - Linting: checkstyle, SpotBugs
    - Building: Maven, Gradle
    """

    def _create_config(self) -> LanguageConfig:
        return LanguageConfig(
            name="java",
            display_name="Java",
            aliases=["jav"],
            extensions=[".java"],
            filenames=["pom.xml", "build.gradle", "build.gradle.kts"],
            shebangs=[],
            comment_style=CommentStyle.C_STYLE,
            line_comment="//",
            block_comment_start="/*",
            block_comment_end="*/",
            string_delimiters=['"'],
            indent_size=4,
            use_tabs=False,
            package_managers=["maven", "gradle"],
            build_systems=["maven", "gradle"],
            test_frameworks=["junit", "testng"],
            language_server="jdtls",
            language_server_name="Eclipse JDT Language Server",
            tree_sitter_language="java",
        )

    def _create_capabilities(self) -> LanguageCapabilities:
        return LanguageCapabilities(
            supports_syntax_analysis=True,
            supports_semantic_analysis=True,
            supports_type_checking=True,
            supports_rename=True,
            supports_extract_function=True,
            supports_inline=True,
            supports_organize_imports=True,
            supports_test_discovery=True,
            supports_test_execution=True,
            supports_coverage=True,
            supports_debugging=True,
            supports_breakpoints=True,
            supports_step_debugging=True,
            supports_formatting=True,
            supports_linting=True,
            supports_completion=True,
        )

    def _create_tree_sitter_queries(self) -> TreeSitterQueries:
        """Create tree-sitter queries for Java symbol/call extraction."""
        return TreeSitterQueries(
            symbols=[
                QueryPattern("class", "(class_declaration name: (identifier) @name)"),
                QueryPattern("class", "(interface_declaration name: (identifier) @name)"),
                QueryPattern("function", "(method_declaration name: (identifier) @name)"),
            ],
            calls="""
                (method_invocation name: (identifier) @callee)
                (object_creation_expression type: (type_identifier) @callee)
                (super_method_invocation name: (identifier) @callee)
            """,
            references="""
                (method_invocation name: (identifier) @name)
                (method_invocation object: (identifier) @name)
                (field_access field: (identifier) @name)
            """,
            inheritance="""
                (class_declaration
                    name: (identifier) @child
                    super_classes: (superclass (type_identifier) @base))
            """,
            implements="""
                (class_declaration
                    name: (identifier) @child
                    interfaces: (super_interfaces (type_list (type_identifier) @interface)))
                (interface_declaration
                    name: (identifier) @child
                    interfaces: (super_interfaces (type_list (type_identifier) @interface)))
            """,
            composition="""
                (class_declaration
                    name: (identifier) @owner
                    body: (class_body
                        (field_declaration
                            type: (type_identifier) @type)))
            """,
            enclosing_scopes=[
                ("method_declaration", "name"),
                ("class_declaration", "name"),
                ("interface_declaration", "name"),
            ],
        )

    def get_test_runner(self, project_root: Path) -> Optional[TestRunner]:
        """Get Maven or Gradle test runner."""
        # Check for Gradle
        if (project_root / "build.gradle").exists() or (project_root / "build.gradle.kts").exists():
            return TestRunner(
                name="gradle test",
                command=["./gradlew", "test"],
                file_pattern="*Test.java",
                run_args=["--info"],
                coverage_args=["jacocoTestReport"],
                parallel_args=["--parallel"],
            )

        # Check for Maven
        if (project_root / "pom.xml").exists():
            return TestRunner(
                name="maven test",
                command=["mvn", "test"],
                file_pattern="*Test.java",
                run_args=["-Dtest=*"],
                coverage_args=["jacoco:report"],
            )

        return None

    def get_formatter(self, project_root: Path) -> Optional[Formatter]:
        """Get google-java-format formatter."""
        return Formatter(
            name="google-java-format",
            command=["google-java-format", "--replace", "src/**/*.java"],
            check_args=["--dry-run", "--set-exit-if-changed"],
        )

    def get_linter(self, project_root: Path) -> Optional[Linter]:
        """Get checkstyle linter."""
        # Check for Gradle
        if (project_root / "build.gradle").exists():
            return Linter(
                name="checkstyle",
                command=["./gradlew", "checkstyleMain"],
                config_file="config/checkstyle/checkstyle.xml",
            )

        # Check for Maven
        if (project_root / "pom.xml").exists():
            return Linter(
                name="checkstyle",
                command=["mvn", "checkstyle:check"],
                config_file="checkstyle.xml",
            )

        return None

    def get_build_system(self, project_root: Path) -> Optional[BuildSystem]:
        """Get Maven or Gradle build system."""
        # Check for Gradle
        if (project_root / "build.gradle").exists() or (project_root / "build.gradle.kts").exists():
            return BuildSystem(
                name="gradle",
                build_command=["./gradlew", "build"],
                run_command=["./gradlew", "run"],
                clean_command=["./gradlew", "clean"],
                install_command=["./gradlew", "install"],
                manifest_file="build.gradle",
            )

        # Check for Maven
        if (project_root / "pom.xml").exists():
            return BuildSystem(
                name="maven",
                build_command=["mvn", "package"],
                run_command=["mvn", "exec:java"],
                clean_command=["mvn", "clean"],
                install_command=["mvn", "install"],
                manifest_file="pom.xml",
            )

        return None
