import os
import tempfile

import pytest

from debgpt.tools import (
    DirectoryLister,
    FileEditor,
    FileFinder,
    FileReader,
    FileWriter,
    _diff_stat,
    _short,
    render_diff,
)


def test_render_diff():
    res = render_diff("a\nb\n", "a\nc\n", "test.txt")
    assert "test.txt" in res
    assert "-b" in res or "- b" in res or "\x1b" in res  # pygments might add ansi

    res = render_diff("a", "a", "test.txt")
    assert res == "(no changes)"


def test_short():
    assert _short("a " * 30, limit=20) == "a a a a a a a a a..."
    assert _short("short") == "short"


def test_diff_stat():
    added, removed = _diff_stat("a\nb", "a\nc")
    assert added == 1
    assert removed == 1


def test_file_reader(tmp_path):
    f = tmp_path / "test.txt"
    f.write_text("line1\nline2\nline3\n")

    reader = FileReader()

    # Read full
    res = reader(str(f))
    assert "line1" in res
    assert "line3" in res

    # Read range
    res = reader(str(f), start_line=2, end_line=2)
    assert "line1" not in res
    assert "line2" in res
    assert "line3" not in res

    # Error: start > total
    assert "Error" in reader(str(f), start_line=5)

    # Error: start < 1
    assert "Error" in reader(str(f), start_line=0)

    # Error: end < start
    assert "Error" in reader(str(f), start_line=3, end_line=1)

    # Error: missing file
    assert "Error" in reader(str(tmp_path / "missing.txt"))

    assert "read" in reader.summary({"path": "foo"})


def test_file_writer(tmp_path):
    f = tmp_path / "test.txt"
    writer = FileWriter()

    # Create new
    res = writer(str(f), content="a\nb\n")
    assert "Successfully wrote" in res
    assert f.read_text() == "a\nb\n"

    # Needs confirm
    needs, reason = writer.needs_confirmation({"path": str(f)})
    assert needs
    assert "Overwrite" in reason

    ctx = writer.confirmation_context({"path": str(f), "content": "c\n"})
    assert "c" in ctx

    # Range replacement
    res = writer(str(f), content="x\n", start_line=1, end_line=1)
    assert "Successfully replaced" in res
    assert f.read_text() == "x\n\nb\n" or f.read_text() == "x\nb\n"

    # Error missing file range
    assert "Error" in writer(str(tmp_path / "missing"), "a", start_line=1, end_line=2)

    # Errors bounds
    assert "Error" in writer(str(f), "a", start_line=0)
    assert "Error" in writer(str(f), "a", start_line=2, end_line=1)
    assert "Error" in writer(str(f), "a", start_line=10)

    assert "write" in writer.summary({"path": "foo", "content": "bar"})


def test_file_editor(tmp_path):
    f = tmp_path / "test.txt"
    f.write_text("hello\nworld\nhello\n")
    editor = FileEditor()

    # Missing file
    assert "Error" in editor(str(tmp_path / "missing"), "a", "b")

    # Ambiguous
    res = editor(str(f), "hello\n", "hi\n")
    assert "Error" in res
    assert "2 times" in res

    # Replace all
    res = editor(str(f), "hello\n", "hi\n", replace_all=True)
    assert "Successfully" in res
    assert f.read_text() == "hi\nworld\nhi\n"

    # Unique match
    res = editor(str(f), "world\n", "earth\n")
    assert "Successfully" in res
    assert f.read_text() == "hi\nearth\nhi\n"

    # Missing string
    res = editor(str(f), "mars\n", "venus\n")
    assert "Error" in res

    # Same string
    res = editor(str(f), "hi\n", "hi\n")
    assert "Error" in res

    assert editor.needs_confirmation({"path": "foo"})[0]

    f.write_text("a\n")
    ctx = editor.confirmation_context(
        {"path": str(f), "old_string": "a\n", "new_string": "b\n"}
    )
    assert "b" in ctx


def test_directory_lister(tmp_path):
    (tmp_path / "file.txt").write_text("a")
    lister = DirectoryLister()

    res = lister(str(tmp_path))
    assert "file.txt" in res

    res = lister(str(tmp_path), all=True, long=True)
    assert "file.txt" in res

    assert "Error" in lister(str(tmp_path / "missing"))
    assert "Error" in lister(str(tmp_path / "file.txt"))

    assert "ls" in lister.summary({"path": "foo"})


def test_file_finder(tmp_path):
    (tmp_path / "file.txt").write_text("a")
    finder = FileFinder()

    res = finder(str(tmp_path), name="file.txt", type="f", maxdepth=1)
    assert "file.txt" in res

    assert "Error" in finder(str(tmp_path / "missing"))

    needs, reason = finder.needs_confirmation({"extra_args": "-delete"})
    assert needs
    assert "-delete" in reason

    assert "find" in finder.summary({"path": "foo", "name": "bar"})
