"""Unit tests for VueTscPlugin temp tsconfig functionality."""

from __future__ import annotations

import json
from pathlib import Path

from assertpy import assert_that

from lintro.tools.definitions.vue_tsc import VueTscPlugin

# =============================================================================
# Tests for JSONC tsconfig parsing (issue #570)
# =============================================================================


def test_create_temp_tsconfig_preserves_type_roots_from_jsonc_base(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify typeRoots are preserved when base tsconfig uses JSONC features.

    This is the primary scenario from issue #570: a tsconfig.json with
    comments and trailing commas should still have its typeRoots read
    and propagated into the temporary tsconfig.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text(
        """{
  // TypeScript config with JSONC features
  "compilerOptions": {
    "strict": true,
    /* Custom type roots for this project */
    "typeRoots": [
      "./custom-types",
      "./node_modules/@types",
    ],
  },
}""",
    )

    temp_path = vue_tsc_plugin._create_temp_tsconfig(
        base_tsconfig=base_tsconfig,
        files=["src/App.vue"],
        cwd=tmp_path,
    )

    try:
        content = json.loads(temp_path.read_text())
        # typeRoots should be resolved to absolute paths
        type_roots = content["compilerOptions"]["typeRoots"]
        assert_that(type_roots).is_length(2)
        assert_that(type_roots[0]).ends_with("custom-types")
        assert_that(type_roots[1]).ends_with("node_modules/@types")
    finally:
        temp_path.unlink(missing_ok=True)


def test_create_temp_tsconfig_no_type_roots_when_base_has_none(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify no typeRoots are added when the base config has none.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text('{"compilerOptions": {"strict": true}}')

    temp_path = vue_tsc_plugin._create_temp_tsconfig(
        base_tsconfig=base_tsconfig,
        files=["src/App.vue"],
        cwd=tmp_path,
    )

    try:
        content = json.loads(temp_path.read_text())
        assert_that(content["compilerOptions"]).does_not_contain_key("typeRoots")
    finally:
        temp_path.unlink(missing_ok=True)


def test_create_temp_tsconfig_ignores_non_list_type_roots(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify malformed typeRoots (non-list) are safely ignored.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text(
        '{"compilerOptions": {"typeRoots": "not-a-list"}}',
    )

    temp_path = vue_tsc_plugin._create_temp_tsconfig(
        base_tsconfig=base_tsconfig,
        files=["src/App.vue"],
        cwd=tmp_path,
    )

    try:
        content = json.loads(temp_path.read_text())
        assert_that(content["compilerOptions"]).does_not_contain_key("typeRoots")
    finally:
        temp_path.unlink(missing_ok=True)


def test_create_temp_tsconfig_filters_non_string_type_roots(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify non-string entries in typeRoots are filtered out.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text(
        '{"compilerOptions": {"typeRoots": ["./valid-types", 123, null, true]}}',
    )

    temp_path = vue_tsc_plugin._create_temp_tsconfig(
        base_tsconfig=base_tsconfig,
        files=["src/App.vue"],
        cwd=tmp_path,
    )

    try:
        content = json.loads(temp_path.read_text())
        type_roots = content["compilerOptions"]["typeRoots"]
        assert_that(type_roots).is_length(1)
        assert_that(type_roots[0]).ends_with("valid-types")
    finally:
        temp_path.unlink(missing_ok=True)


def test_create_temp_tsconfig_fallback_honours_empty_typeroots(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify fallback preserves explicit empty typeRoots.

    When the base tsconfig explicitly sets ``typeRoots: []`` to disable
    automatic global type discovery, the fallback path must honour that
    intent and NOT inject the default ``node_modules/@types`` root.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    import tempfile
    from typing import Any
    from unittest.mock import patch

    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text(
        json.dumps(
            {
                "compilerOptions": {
                    "typeRoots": [],
                },
            },
        ),
    )

    original_mkstemp = tempfile.mkstemp
    call_count = 0

    def mock_mkstemp(**kwargs: Any) -> tuple[int, str]:
        nonlocal call_count
        call_count += 1
        if call_count == 1:
            raise OSError("Read-only filesystem")
        return original_mkstemp(**kwargs)

    with patch("tempfile.mkstemp", side_effect=mock_mkstemp):
        temp_path = vue_tsc_plugin._create_temp_tsconfig(
            base_tsconfig=base_tsconfig,
            files=["src/App.vue"],
            cwd=tmp_path,
        )

    try:
        content = json.loads(temp_path.read_text())
        type_roots = content["compilerOptions"]["typeRoots"]
        assert_that(type_roots).is_empty()
    finally:
        temp_path.unlink(missing_ok=True)


def test_create_temp_tsconfig_ignores_non_dict_compiler_options(
    vue_tsc_plugin: VueTscPlugin,
    tmp_path: Path,
) -> None:
    """Verify malformed compilerOptions (non-dict) are safely ignored.

    Args:
        vue_tsc_plugin: Plugin instance fixture.
        tmp_path: Pytest temporary directory.
    """
    base_tsconfig = tmp_path / "tsconfig.json"
    base_tsconfig.write_text('{"compilerOptions": "not-a-dict"}')

    temp_path = vue_tsc_plugin._create_temp_tsconfig(
        base_tsconfig=base_tsconfig,
        files=["src/App.vue"],
        cwd=tmp_path,
    )

    try:
        content = json.loads(temp_path.read_text())
        assert_that(content["compilerOptions"]).does_not_contain_key("typeRoots")
    finally:
        temp_path.unlink(missing_ok=True)
