"""Tests for the environment file parser."""

import tempfile
from pathlib import Path

import pytest

from kvenv.parser import (
    EnvParseError,
    _is_valid_env_var_name,
    _trim,
    _unquote,
    parse_env_file,
)


class TestTrim:
    def test_trim_spaces(self):
        assert _trim("  hello  ") == "hello"

    def test_trim_tabs(self):
        assert _trim("\t\thello\t\t") == "hello"

    def test_trim_mixed(self):
        assert _trim("  \t hello \t  ") == "hello"

    def test_trim_empty(self):
        assert _trim("") == ""


class TestUnquote:
    def test_double_quotes(self):
        assert _unquote('"hello"') == "hello"

    def test_single_quotes(self):
        assert _unquote("'hello'") == "hello"

    def test_no_quotes(self):
        assert _unquote("hello") == "hello"

    def test_mismatched_quotes(self):
        assert _unquote('"hello\'') == "\"hello'"

    def test_empty_quoted(self):
        assert _unquote('""') == ""

    def test_single_char(self):
        assert _unquote('"') == '"'


class TestValidEnvVarName:
    def test_valid_simple(self):
        assert _is_valid_env_var_name("FOO") is True

    def test_valid_with_underscore(self):
        assert _is_valid_env_var_name("FOO_BAR") is True

    def test_valid_with_numbers(self):
        assert _is_valid_env_var_name("FOO123") is True

    def test_valid_starts_with_underscore(self):
        assert _is_valid_env_var_name("_FOO") is True

    def test_invalid_starts_with_number(self):
        assert _is_valid_env_var_name("123FOO") is False

    def test_invalid_contains_dash(self):
        assert _is_valid_env_var_name("FOO-BAR") is False

    def test_invalid_contains_space(self):
        assert _is_valid_env_var_name("FOO BAR") is False

    def test_invalid_empty(self):
        assert _is_valid_env_var_name("") is False


class TestParseEnvFile:
    def test_simple_key_value(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("FOO=bar\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 1
            assert entries[0].key == "FOO"
            assert entries[0].value == "bar"
            assert entries[0].is_keyvault_ref is False

    def test_comments_ignored(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("# This is a comment\n")
            f.write("FOO=bar\n")
            f.write("  # Indented comment\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 1
            assert entries[0].key == "FOO"

    def test_blank_lines_ignored(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("FOO=bar\n")
            f.write("\n")
            f.write("BAZ=qux\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 2

    def test_export_prefix(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("export FOO=bar\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 1
            assert entries[0].key == "FOO"
            assert entries[0].value == "bar"

    def test_quoted_double(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write('FOO="bar baz"\n')
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert entries[0].value == "bar baz"

    def test_quoted_single(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("FOO='bar baz'\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert entries[0].value == "bar baz"

    def test_value_with_equals(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("CONNECTION_STRING=Server=localhost;Database=test\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert entries[0].value == "Server=localhost;Database=test"

    def test_keyvault_ref_with_vault(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("SECRET=kv://my-vault/my-secret\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert entries[0].is_keyvault_ref is True
            assert entries[0].vault_name == "my-vault"
            assert entries[0].secret_name == "my-secret"

    def test_keyvault_ref_default_vault(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("SECRET=kv://my-secret\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name), default_vault="default-vault"))
            assert entries[0].is_keyvault_ref is True
            assert entries[0].vault_name == "default-vault"
            assert entries[0].secret_name == "my-secret"

    def test_keyvault_ref_no_default_vault(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("SECRET=kv://my-secret\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert entries[0].is_keyvault_ref is True
            assert entries[0].vault_name is None
            assert entries[0].secret_name == "my-secret"

    def test_keyvault_ref_missing_secret_raises(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("SECRET=kv://\n")
            f.flush()

            with pytest.raises(EnvParseError) as exc_info:
                list(parse_env_file(Path(f.name)))
            assert "missing secret name" in str(exc_info.value).lower()

    def test_file_not_found(self):
        with pytest.raises(FileNotFoundError):
            list(parse_env_file(Path("/nonexistent/.env")))

    def test_invalid_var_name_ignored(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("123INVALID=foo\n")
            f.write("VALID=bar\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 1
            assert entries[0].key == "VALID"

    def test_malformed_line_ignored(self):
        with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
            f.write("NO_EQUALS_SIGN\n")
            f.write("VALID=bar\n")
            f.flush()

            entries = list(parse_env_file(Path(f.name)))
            assert len(entries) == 1
            assert entries[0].key == "VALID"
