"""Tests for the validation module."""

import os
from pathlib import Path

import pytest

from prozes.modules.validation import (
    ValidationError,
    run_all_validations,
    validate_git_available,
    validate_project_name,
    validate_project_not_exists,
    validate_python_version,
    validate_venv_for_install_deps,
)


class TestValidateProjectName:
    """Tests for validate_project_name function."""

    def test_valid_name_simple(self):
        """Test valid simple project name."""
        valid, error = validate_project_name("my_project")
        assert valid is True
        assert error is None

    def test_valid_name_with_numbers(self):
        """Test valid name with numbers."""
        valid, error = validate_project_name("project123")
        assert valid is True
        assert error is None

    def test_valid_name_starts_with_underscore(self):
        """Test valid name starting with underscore."""
        valid, error = validate_project_name("_private_project")
        assert valid is True
        assert error is None

    def test_invalid_name_empty(self):
        """Test empty name is invalid."""
        valid, error = validate_project_name("")
        assert valid is False
        assert error is not None
        assert "empty" in error.lower()

    def test_invalid_name_starts_with_number(self):
        """Test name starting with number is invalid."""
        valid, error = validate_project_name("123project")
        assert valid is False
        assert error is not None

    def test_invalid_name_with_hyphen(self):
        """Test name with hyphen is invalid."""
        valid, error = validate_project_name("my-project")
        assert valid is False
        assert error is not None

    def test_invalid_name_with_space(self):
        """Test name with space is invalid."""
        valid, error = validate_project_name("my project")
        assert valid is False
        assert error is not None

    def test_invalid_name_special_chars(self):
        """Test name with special characters is invalid."""
        valid, error = validate_project_name("project@name")
        assert valid is False
        assert error is not None

    def test_invalid_name_python_keyword(self):
        """Test Python keyword is invalid."""
        valid, error = validate_project_name("class")
        assert valid is False
        assert error is not None
        assert "reserved" in error.lower() or "keyword" in error.lower()

    def test_invalid_name_python_keyword_import(self):
        """Test 'import' keyword is invalid."""
        valid, error = validate_project_name("import")
        assert valid is False
        assert error is not None

    def test_invalid_name_python_keyword_True(self):
        """Test 'True' keyword is invalid."""
        valid, error = validate_project_name("True")
        assert valid is False
        assert error is not None


class TestValidateProjectNotExists:
    """Tests for validate_project_not_exists function."""

    def test_project_does_not_exist(self, tmp_path, monkeypatch):
        """Test validation passes when project doesn't exist."""
        monkeypatch.chdir(tmp_path)
        valid, error = validate_project_not_exists("new_project")
        assert valid is True
        assert error is None

    def test_project_already_exists(self, tmp_path, monkeypatch):
        """Test validation fails when project exists."""
        monkeypatch.chdir(tmp_path)
        (tmp_path / "existing_project").mkdir()

        valid, error = validate_project_not_exists("existing_project")
        assert valid is False
        assert error is not None
        assert "exists" in error.lower()


class TestValidatePythonVersion:
    """Tests for validate_python_version function."""

    def test_none_version_is_valid(self):
        """Test None version is valid (uses current Python)."""
        valid, error = validate_python_version(None)
        assert valid is True
        assert error is None

    def test_valid_major_minor(self):
        """Test valid major.minor format."""
        valid, error = validate_python_version("3.8")
        assert valid is True
        assert error is None

    def test_valid_major_minor_double_digit(self):
        """Test valid double digit minor version."""
        valid, error = validate_python_version("3.11")
        assert valid is True
        assert error is None

    def test_valid_major_only(self):
        """Test valid major only format."""
        valid, error = validate_python_version("3")
        assert valid is True
        assert error is None

    def test_invalid_format_text(self):
        """Test invalid text format."""
        valid, error = validate_python_version("python3")
        assert valid is False
        assert error is not None

    def test_invalid_format_triple(self):
        """Test invalid triple version format."""
        valid, error = validate_python_version("3.8.1")
        assert valid is False
        assert error is not None


class TestValidateGitAvailable:
    """Tests for validate_git_available function."""

    def test_git_available(self, mock_git_available):
        """Test validation passes when git is available."""
        valid, error = validate_git_available()
        assert valid is True
        assert error is None

    def test_git_not_available(self, mock_git_unavailable):
        """Test validation fails when git is not available."""
        valid, error = validate_git_available()
        assert valid is False
        assert error is not None
        assert "git" in error.lower()


class TestValidateVenvForInstallDeps:
    """Tests for validate_venv_for_install_deps function."""

    def test_install_deps_with_venv(self):
        """Test install_deps with venv is valid."""
        valid, error = validate_venv_for_install_deps(venv=True, install_deps=True)
        assert valid is True
        assert error is None

    def test_install_deps_without_venv(self):
        """Test install_deps without venv is invalid."""
        valid, error = validate_venv_for_install_deps(venv=False, install_deps=True)
        assert valid is False
        assert error is not None
        assert "venv" in error.lower()

    def test_no_install_deps_no_venv(self):
        """Test no install_deps without venv is valid."""
        valid, error = validate_venv_for_install_deps(venv=False, install_deps=False)
        assert valid is True
        assert error is None

    def test_venv_without_install_deps(self):
        """Test venv without install_deps is valid."""
        valid, error = validate_venv_for_install_deps(venv=True, install_deps=False)
        assert valid is True
        assert error is None


class TestRunAllValidations:
    """Tests for run_all_validations function."""

    def test_all_valid(self, tmp_path, monkeypatch, mock_git_available):
        """Test all validations pass."""
        monkeypatch.chdir(tmp_path)
        errors = run_all_validations(
            project_name="valid_project",
            git=True,
            venv=True,
            python_version="3.11",
            install_deps=True,
        )
        assert errors == []

    def test_invalid_name_returns_error(self, tmp_path, monkeypatch):
        """Test invalid name returns error."""
        monkeypatch.chdir(tmp_path)
        errors = run_all_validations(project_name="123invalid")
        assert len(errors) >= 1

    def test_multiple_errors(self, tmp_path, monkeypatch, mock_git_unavailable):
        """Test multiple validation errors."""
        monkeypatch.chdir(tmp_path)
        (tmp_path / "existing").mkdir()

        errors = run_all_validations(
            project_name="existing",
            git=True,
            venv=False,
            install_deps=True,
        )
        # Should have errors for: project exists, git not available, install_deps without venv
        assert len(errors) >= 2

    def test_no_git_flag_skips_git_validation(self, tmp_path, monkeypatch, mock_git_unavailable):
        """Test git validation is skipped when git flag is False."""
        monkeypatch.chdir(tmp_path)
        errors = run_all_validations(
            project_name="valid_project",
            git=False,
        )
        # Git not available error should not appear since git=False
        assert not any("git" in e.lower() for e in errors)
