# Copyright (C) 2026 The Android Open Source Project
#
# 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.

"""Tests for the main repo script and subcommand routing."""

from unittest import mock

import pytest

from main import _Repo


@pytest.fixture(name="repo")
def fixture_repo():
    repo = _Repo("repodir")
    # Overriding the command list here ensures that we are only testing
    # against a fixed set of commands, reducing fragility to new
    # subcommands being added to the main repo tool.
    repo.commands = {"start": None, "sync": None, "smart": None}
    return repo


@pytest.fixture(name="mock_config")
def fixture_mock_config():
    return mock.MagicMock()


@mock.patch("time.sleep")
def test_autocorrect_delay(mock_sleep, repo, mock_config):
    """Test autocorrect with positive delay."""
    mock_config.GetString.return_value = "10"

    res = repo._autocorrect_command_name("tart", mock_config)

    mock_config.GetString.assert_called_with("help.autocorrect")
    mock_sleep.assert_called_with(1.0)
    assert res == "start"


@mock.patch("time.sleep")
def test_autocorrect_delay_one(mock_sleep, repo, mock_config):
    """Test autocorrect with '1' (0.1s delay, not immediate)."""
    mock_config.GetString.return_value = "1"

    res = repo._autocorrect_command_name("tart", mock_config)

    mock_sleep.assert_called_with(0.1)
    assert res == "start"


@mock.patch("time.sleep", side_effect=KeyboardInterrupt())
def test_autocorrect_delay_interrupt(mock_sleep, repo, mock_config):
    """Test autocorrect handles KeyboardInterrupt during delay."""
    mock_config.GetString.return_value = "10"

    res = repo._autocorrect_command_name("tart", mock_config)

    mock_sleep.assert_called_with(1.0)
    assert res is None


@mock.patch("time.sleep")
def test_autocorrect_immediate(mock_sleep, repo, mock_config):
    """Test autocorrect with immediate/negative delay."""
    # Test numeric negative.
    mock_config.GetString.return_value = "-1"
    res = repo._autocorrect_command_name("tart", mock_config)
    mock_sleep.assert_not_called()
    assert res == "start"

    # Test string boolean "true".
    mock_config.GetString.return_value = "true"
    res = repo._autocorrect_command_name("tart", mock_config)
    mock_sleep.assert_not_called()
    assert res == "start"

    # Test string boolean "yes".
    mock_config.GetString.return_value = "YES"
    res = repo._autocorrect_command_name("tart", mock_config)
    mock_sleep.assert_not_called()
    assert res == "start"

    # Test string boolean "immediate".
    mock_config.GetString.return_value = "Immediate"
    res = repo._autocorrect_command_name("tart", mock_config)
    mock_sleep.assert_not_called()
    assert res == "start"


def test_autocorrect_zero_or_show(repo, mock_config):
    """Test autocorrect with zero delay (suggestions only)."""
    # Test numeric zero.
    mock_config.GetString.return_value = "0"
    res = repo._autocorrect_command_name("tart", mock_config)
    assert res is None

    # Test string boolean "false".
    mock_config.GetString.return_value = "False"
    res = repo._autocorrect_command_name("tart", mock_config)
    assert res is None

    # Test string boolean "show".
    mock_config.GetString.return_value = "show"
    res = repo._autocorrect_command_name("tart", mock_config)
    assert res is None


def test_autocorrect_never(repo, mock_config):
    """Test autocorrect with 'never'."""
    mock_config.GetString.return_value = "never"
    res = repo._autocorrect_command_name("tart", mock_config)
    assert res is None


@mock.patch("builtins.input", return_value="y")
def test_autocorrect_prompt_yes(mock_input, repo, mock_config):
    """Test autocorrect with prompt and user answers yes."""
    mock_config.GetString.return_value = "prompt"

    res = repo._autocorrect_command_name("tart", mock_config)

    assert res == "start"


@mock.patch("builtins.input", return_value="n")
def test_autocorrect_prompt_no(mock_input, repo, mock_config):
    """Test autocorrect with prompt and user answers no."""
    mock_config.GetString.return_value = "prompt"

    res = repo._autocorrect_command_name("tart", mock_config)

    assert res is None


@mock.patch("builtins.input", return_value="y")
def test_autocorrect_multiple_candidates(mock_input, repo, mock_config):
    """Test autocorrect with multiple matches forces a prompt."""
    mock_config.GetString.return_value = "10"  # Normally just delay

    # 'snart' matches both 'start' and 'smart' with > 0.7 ratio
    res = repo._autocorrect_command_name("snart", mock_config)

    # Because there are multiple candidates, it should prompt
    mock_input.assert_called_once()
    assert res == "start"


@mock.patch("builtins.input", side_effect=KeyboardInterrupt())
def test_autocorrect_prompt_interrupt(mock_input, repo, mock_config):
    """Test autocorrect with prompt and user interrupts."""
    mock_config.GetString.return_value = "prompt"

    res = repo._autocorrect_command_name("tart", mock_config)

    assert res is None
