"""Tests for filesystem skills: read_file, write_file, edit_file, list_directory."""

import os

import pytest

from fliiq.runtime.package_data import bundled_skills_dir
from fliiq.runtime.skills.base import SkillBase

SKILLS_DIR = str(bundled_skills_dir())


def _load_skill(name: str) -> SkillBase:
    return SkillBase(os.path.join(SKILLS_DIR, name))


# --- read_file ---


async def test_read_file_basic(tmp_path):
    skill = _load_skill("read_file")
    test_file = tmp_path / "test.txt"
    test_file.write_text("line1\nline2\nline3\n")

    result = await skill.execute({"path": str(test_file)})
    assert "line1" in result["content"]
    assert "line2" in result["content"]


async def test_read_file_with_offset(tmp_path):
    skill = _load_skill("read_file")
    test_file = tmp_path / "test.txt"
    test_file.write_text("\n".join(f"line{i}" for i in range(20)))

    result = await skill.execute({"path": str(test_file), "offset": 5, "limit": 3})
    content = result["content"]
    assert "line5" in content
    assert "line7" in content
    assert "line8" not in content


async def test_read_file_not_found():
    skill = _load_skill("read_file")
    with pytest.raises(FileNotFoundError):
        await skill.execute({"path": "/nonexistent/file.txt"})


async def test_read_file_binary_detection(tmp_path):
    skill = _load_skill("read_file")
    binary_file = tmp_path / "binary.bin"
    binary_file.write_bytes(b"\x00\x01\x02\x03")

    with pytest.raises(ValueError, match="Binary file"):
        await skill.execute({"path": str(binary_file)})


# --- write_file ---


async def test_write_file_basic(tmp_path):
    skill = _load_skill("write_file")
    target = str(tmp_path / "output.txt")

    result = await skill.execute({"path": target, "content": "hello world"})
    assert "Wrote" in result["result"]
    assert os.path.isfile(target)
    assert open(target).read() == "hello world"


async def test_write_file_creates_dirs(tmp_path):
    skill = _load_skill("write_file")
    target = str(tmp_path / "a" / "b" / "c.txt")

    await skill.execute({"path": target, "content": "nested"})
    assert open(target).read() == "nested"


async def test_write_file_overwrites(tmp_path):
    skill = _load_skill("write_file")
    target = str(tmp_path / "overwrite.txt")
    open(target, "w").write("old")

    await skill.execute({"path": target, "content": "new"})
    assert open(target).read() == "new"


# --- edit_file ---


async def test_edit_file_basic(tmp_path):
    skill = _load_skill("edit_file")
    target = str(tmp_path / "edit.txt")
    open(target, "w").write("hello world\ngoodbye world\n")

    result = await skill.execute({"path": target, "old_text": "hello world", "new_text": "hi there"})
    assert "Edited" in result["result"]
    assert open(target).read() == "hi there\ngoodbye world\n"


async def test_edit_file_not_found_text(tmp_path):
    skill = _load_skill("edit_file")
    target = str(tmp_path / "edit2.txt")
    open(target, "w").write("some content")

    with pytest.raises(ValueError, match="not found"):
        await skill.execute({"path": target, "old_text": "missing text", "new_text": "replacement"})


async def test_edit_file_ambiguous(tmp_path):
    skill = _load_skill("edit_file")
    target = str(tmp_path / "ambiguous.txt")
    open(target, "w").write("foo bar foo bar")

    with pytest.raises(ValueError, match="2 times"):
        await skill.execute({"path": target, "old_text": "foo bar", "new_text": "baz"})


# --- list_directory ---


async def test_list_directory_basic(tmp_path):
    skill = _load_skill("list_directory")
    (tmp_path / "file.txt").write_text("content")
    (tmp_path / "subdir").mkdir()

    result = await skill.execute({"path": str(tmp_path)})
    entries = result["entries"]
    assert "[FILE] file.txt" in entries
    assert "[DIR] subdir" in entries


async def test_list_directory_not_a_dir(tmp_path):
    skill = _load_skill("list_directory")
    f = tmp_path / "not_a_dir.txt"
    f.write_text("x")

    with pytest.raises(NotADirectoryError):
        await skill.execute({"path": str(f)})
