import json
import tempfile
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

import pytest
from git import Repo

TREE_SITTER_REPOS: dict[str, tuple[str, str, str]] = {
    "c_sharp": (
        "https://github.com/tree-sitter/tree-sitter-c-sharp.git",
        "362a8a41b265056592a0c3771664a21d23a71392",
        "tree-sitter-c-sharp",
    ),
    "dart": (
        "https://github.com/UserNobody14/tree-sitter-dart.git",
        "e81af6ab94a728ed99c30083be72d88e6d56cf9e",
        "tree-sitter-dart",
    ),
    "go": (
        "https://github.com/tree-sitter/tree-sitter-go.git",
        "3c3775faa968158a8b4ac190a7fda867fd5fb748",
        "tree-sitter-go",
    ),
    "hcl": (
        "https://github.com/tree-sitter-grammars/tree-sitter-hcl.git",
        "fad991865fee927dd1de5e172fb3f08ac674d914",
        "tree-sitter-hcl",
    ),
    "java": (
        "https://github.com/tree-sitter/tree-sitter-java.git",
        "94703d5a6bed02b98e438d7cad1136c01a60ba2c",
        "tree-sitter-java",
    ),
    "javascript": (
        "https://github.com/tree-sitter/tree-sitter-javascript.git",
        "3a837b6f3658ca3618f2022f8707e29739c91364",
        "tree-sitter-javascript",
    ),
    "json": (
        "https://github.com/tree-sitter/tree-sitter-json.git",
        "ee35a6ebefcef0c5c416c0d1ccec7370cfca5a24",
        "tree-sitter-json",
    ),
    "kotlin": (
        "https://github.com/tree-sitter-grammars/tree-sitter-kotlin.git",
        "77dd60ea0a9003ce062c9728a513ffe1aaff8c82",
        "tree-sitter-kotlin",
    ),
    "php": (
        "https://github.com/tree-sitter/tree-sitter-php.git",
        "43aad2b9a98aa8e603ea0cf5bb630728a5591ad8",
        "tree-sitter-php",
    ),
    "python": (
        "https://github.com/tree-sitter/tree-sitter-python.git",
        "bffb65a8cfe4e46290331dfef0dbf0ef3679de11",
        "tree-sitter-python",
    ),
    "ruby": (
        "https://github.com/tree-sitter/tree-sitter-ruby.git",
        "71bd32fb7607035768799732addba884a37a6210",
        "tree-sitter-ruby",
    ),
    "scala": (
        "https://github.com/tree-sitter/tree-sitter-scala.git",
        "d3b9553b47d7ab413a146c4b6498e527265b966e",
        "tree-sitter-scala",
    ),
    "swift": (
        "https://github.com/alex-pinkus/tree-sitter-swift.git",
        "0bea296efe6ea1f67338de26b56e389688d0acb8",
        "tree-sitter-swift",
    ),
    "tsx": (
        "https://github.com/tree-sitter/tree-sitter-typescript.git",
        "f975a621f4e7f532fe322e13c4f79495e0a7b2e7",
        "tree-sitter-typescript",
    ),
    "yaml": (
        "https://github.com/tree-sitter-grammars/tree-sitter-yaml",
        "3975596d84650e8d8ab8ef3128b1b7f0fec324f8",
        "tree-sitter-yaml",
    ),
}

STATIC_NODE_TYPES_DIR = Path(__file__).resolve().parents[2] / "blends" / "static" / "node_types"


def _get_fields(repo_url: str, commit_hash: str, repo_name: str) -> dict[str, list[str]]:
    with tempfile.TemporaryDirectory() as tmpfile:
        repo_path = Path(tmpfile) / repo_name
        repo = Repo.clone_from(repo_url, repo_path)
        repo.git.checkout(commit_hash)
        if repo_name == "tree-sitter-php":
            node_types = repo_path / "php" / "src" / "node-types.json"
        elif repo_name == "tree-sitter-typescript":
            node_types = repo_path / "tsx" / "src" / "node-types.json"
        else:
            node_types = repo_path / "src" / "node-types.json"
        with node_types.open(encoding="utf-8") as handle:
            fields: dict[str, list[str]] = {
                node["type"]: list(field_names)
                for node in json.load(handle)
                if (field_names := node.get("fields", {}).keys())
                if field_names
            }
            return fields


@pytest.mark.blends_test_group("tree_unittesting")
def test_verify_static_fields() -> None:
    def process_grammar(grammar: str, src: tuple[str, str, str]) -> None:
        path = STATIC_NODE_TYPES_DIR / f"{grammar}-fields.json"
        expected_fields = _get_fields(src[0], src[1], src[2])
        current_fields: dict[str, list[str]] = {}

        if path.is_file():
            with path.open(encoding="utf-8") as file:
                current_fields = json.load(file)

        if expected_fields != current_fields:
            with path.open(encoding="utf-8", mode="w") as file:
                json.dump(expected_fields, file, indent=2)

        assert expected_fields == current_fields

    with ThreadPoolExecutor() as executor:
        futures = [
            executor.submit(process_grammar, grammar, src)
            for grammar, src in TREE_SITTER_REPOS.items()
        ]
        for future in futures:
            future.result()
