"""Tests for bash_history_done_right.cli."""

import os
import tempfile

from bash_history_done_right.cli import (
    BEGIN_MARKER,
    END_MARKER,
    build_snippet,
    install,
    is_installed,
    remove_config_lines,
    remove_default_history_lines,
    remove_existing_block,
    uninstall,
)

SAMPLE_BASHRC = """\
# ~/.bashrc: executed by bash(1) for non-login shells.

# some alias
alias ll='ls -la'

# History settings
HISTCONTROL=ignoreboth
shopt -s histappend
HISTSIZE=1000
HISTFILESIZE=2000

# enable color support
alias grep='grep --color=auto'
"""


def _write_tmp(content):
    fd, path = tempfile.mkstemp(suffix=".bashrc")
    os.close(fd)
    with open(path, "w") as f:
        f.write(content)
    return path


def test_remove_default_history_lines():
    result = remove_default_history_lines(SAMPLE_BASHRC)
    assert "HISTCONTROL=ignoreboth" not in result
    assert "shopt -s histappend" not in result
    assert "HISTSIZE=1000" not in result
    assert "HISTFILESIZE=2000" not in result
    # Other content preserved
    assert "alias ll='ls -la'" in result
    assert "alias grep='grep --color=auto'" in result


def test_build_snippet_all():
    snippet = build_snippet(arrow_search=True, eternal_history=True)
    assert "HISTSIZE=9000" in snippet
    assert "history-search-backward" in snippet
    assert "bash_eternal_history" in snippet
    assert snippet.startswith(BEGIN_MARKER)
    assert snippet.rstrip().endswith(END_MARKER)


def test_build_snippet_no_optionals():
    snippet = build_snippet(arrow_search=False, eternal_history=False)
    assert "HISTSIZE=9000" in snippet
    assert "history-search-backward" not in snippet
    assert "bash_eternal_history" not in snippet


def test_install_full():
    path = _write_tmp(SAMPLE_BASHRC)
    try:
        rc = install(path, quiet=True)
        assert rc == 0
        content = open(path).read()
        # Default lines removed
        assert "HISTCONTROL=ignoreboth" not in content
        assert "shopt -s histappend" not in content
        # Our block present
        assert BEGIN_MARKER in content
        assert END_MARKER in content
        assert "HISTSIZE=9000" in content
        assert "history-search-backward" in content
        assert "bash_eternal_history" in content
        # Backup created
        assert os.path.isfile(path + ".bak")
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_install_no_optionals():
    path = _write_tmp(SAMPLE_BASHRC)
    try:
        rc = install(path, arrow_search=False, eternal_history=False, quiet=True)
        assert rc == 0
        content = open(path).read()
        assert "HISTSIZE=9000" in content
        assert "history-search-backward" not in content
        assert "bash_eternal_history" not in content
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_install_idempotent():
    path = _write_tmp(SAMPLE_BASHRC)
    try:
        install(path, quiet=True)
        install(path, quiet=True)
        content = open(path).read()
        # Only one block
        assert content.count(BEGIN_MARKER) == 1
        assert content.count(END_MARKER) == 1
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_uninstall():
    path = _write_tmp(SAMPLE_BASHRC)
    try:
        install(path, quiet=True)
        rc = uninstall(path, quiet=True)
        assert rc == 0
        content = open(path).read()
        assert BEGIN_MARKER not in content
        assert END_MARKER not in content
        assert "HISTSIZE=9000" not in content
        # Default history lines restored
        assert "HISTCONTROL=ignoreboth" in content
        assert "shopt -s histappend" in content
        assert "HISTSIZE=1000" in content
        assert "HISTFILESIZE=2000" in content
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_uninstall_nothing_to_remove():
    path = _write_tmp(SAMPLE_BASHRC)
    try:
        rc = uninstall(path, quiet=True)
        assert rc == 0
    finally:
        os.unlink(path)


def test_remove_existing_block():
    content = "before\n" + BEGIN_MARKER + "\nstuff\n" + END_MARKER + "\nafter\n"
    result = remove_existing_block(content)
    assert BEGIN_MARKER not in result
    assert "stuff" not in result
    assert "before" in result
    assert "after" in result


def test_install_missing_file():
    rc = install("/nonexistent/path/.bashrc", quiet=True)
    assert rc == 1


# --- Manual config detection ---

MANUAL_CONFIG_BASHRC = """\
# ~/.bashrc

alias ll='ls -la'

HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups
_bash_history_sync() {
    builtin history -a
    HISTFILESIZE=$HISTSIZE
}
history() {
    _bash_history_sync
    builtin history "$@"
}
PROMPT_COMMAND=_bash_history_sync
"""


def test_is_installed_detects_manual_config():
    assert is_installed(MANUAL_CONFIG_BASHRC)


def test_is_installed_negative():
    assert not is_installed(SAMPLE_BASHRC)


def test_install_replaces_manual_config():
    """If the user already pasted the config manually, replace it with the marked version."""
    path = _write_tmp(MANUAL_CONFIG_BASHRC)
    try:
        rc = install(path, quiet=True)
        assert rc == 0
        content = open(path).read()
        # Old manual config replaced with marked version
        assert BEGIN_MARKER in content
        assert END_MARKER in content
        assert content.count("_bash_history_sync()") == 1
        # Non-config lines preserved
        assert "alias ll='ls -la'" in content
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_uninstall_manual_config():
    """Uninstall should remove manually-pasted config (no markers)."""
    path = _write_tmp(MANUAL_CONFIG_BASHRC)
    try:
        rc = uninstall(path, quiet=True)
        assert rc == 0
        content = open(path).read()
        assert "_bash_history_sync" not in content
        assert "HISTSIZE=9000" not in content
        assert "PROMPT_COMMAND=_bash_history_sync" not in content
        # Non-config lines preserved
        assert "alias ll='ls -la'" in content
    finally:
        os.unlink(path)
        if os.path.isfile(path + ".bak"):
            os.unlink(path + ".bak")


def test_remove_config_lines_preserves_other_content():
    content = "alias ll='ls -la'\n" + MANUAL_CONFIG_BASHRC + "alias grep='grep'\n"
    result = remove_config_lines(content)
    assert "_bash_history_sync" not in result
    assert "alias ll='ls -la'" in result
    assert "alias grep='grep'" in result
