"""Tests for task filesystem snapshot pull helpers."""

from __future__ import annotations

from types import SimpleNamespace

import pytest

from terminaluse.lib.cli.handlers import filesystem_handlers as fh


def _make_client(
    *,
    filesystem_id: str = "fs-123",
    system_folder_types: list[SimpleNamespace] | None = None,
    system_folder_record: object | None = None,
    download_url: object | None = None,
) -> SimpleNamespace:
    """Build a minimal client stub for filesystem snapshot tests."""
    if system_folder_types is None:
        system_folder_types = [SimpleNamespace(type="dot_claude", host_path=".claude")]

    return SimpleNamespace(
        tasks=SimpleNamespace(
            retrieve=lambda task_id: SimpleNamespace(id=task_id, filesystem_id=filesystem_id),
            list_system_folder_types=lambda task_id: system_folder_types,
            get_system_folder=lambda task_id, folder_type: system_folder_record,
            get_system_folder_download_url=lambda task_id, folder_type: download_url,
        )
    )


def test_pull_task_filesystem_snapshot_downloads_workspace_and_system_folder(tmp_path, monkeypatch):
    """Workspace goes to output/workspace and .claude goes to output/.claude."""
    output_dir = tmp_path / "out"
    workspace_path = output_dir / "workspace"
    system_folder_path = output_dir / ".claude"

    def fake_pull_directory(client, filesystem_id, local_path, force=False, allow_missing_archive=False):
        assert filesystem_id == "fs-123"
        assert local_path == workspace_path
        local_path.mkdir(parents=True, exist_ok=True)
        return 4, 4096

    async def fake_download_from_presigned_url(url, timeout=300.0):
        assert "example.com" in url
        return b"archive-bytes"

    async def fake_extract_archive(archive_data, local_path):
        assert archive_data == b"archive-bytes"
        assert local_path == system_folder_path
        local_path.mkdir(parents=True, exist_ok=True)
        return SimpleNamespace(files_count=2, bytes_extracted=512)

    monkeypatch.setattr(fh, "pull_directory", fake_pull_directory)
    monkeypatch.setattr(fh, "download_from_presigned_url", fake_download_from_presigned_url)
    monkeypatch.setattr(fh, "extract_archive", fake_extract_archive)

    client = _make_client(
        system_folder_record=SimpleNamespace(id="sf-1"),
        download_url=SimpleNamespace(url="https://example.com/system-folder"),
    )

    result = fh.pull_task_filesystem_snapshot(client=client, task_id="task-1", output_dir=output_dir)

    assert workspace_path.is_dir()
    assert system_folder_path.is_dir()
    assert result.workspace_files_count == 4
    assert result.workspace_bytes_extracted == 4096
    assert len(result.system_folders) == 1
    assert result.system_folders[0].host_path == ".claude"
    assert result.system_folders[0].files_count == 2
    assert result.system_folders[0].bytes_extracted == 512
    assert result.system_folders[0].downloaded is True


def test_pull_task_filesystem_snapshot_skips_missing_system_folder_record(tmp_path, monkeypatch):
    """If a folder type is registered but task has no record, skip it."""
    output_dir = tmp_path / "out"

    monkeypatch.setattr(fh, "pull_directory", lambda *args, **kwargs: (0, 0))
    client = _make_client(system_folder_record=None, download_url=SimpleNamespace(url="https://example.com/ignored"))

    result = fh.pull_task_filesystem_snapshot(client=client, task_id="task-1", output_dir=output_dir)

    assert result.system_folders == []
    assert not (output_dir / ".claude").exists()


def test_pull_task_filesystem_snapshot_creates_empty_system_folder_when_archive_missing(tmp_path, monkeypatch):
    """A folder is still created locally when no archive exists remotely."""
    output_dir = tmp_path / "out"
    system_folder_path = output_dir / ".claude"

    monkeypatch.setattr(fh, "pull_directory", lambda *args, **kwargs: (1, 128))
    client = _make_client(system_folder_record=SimpleNamespace(id="sf-1"), download_url=None)

    result = fh.pull_task_filesystem_snapshot(client=client, task_id="task-1", output_dir=output_dir)

    assert system_folder_path.is_dir()
    assert len(result.system_folders) == 1
    assert result.system_folders[0].files_count == 0
    assert result.system_folders[0].bytes_extracted == 0
    assert result.system_folders[0].downloaded is False


def test_pull_task_filesystem_snapshot_rejects_unsafe_system_folder_host_path(tmp_path, monkeypatch):
    """Folder host paths must be safe relative paths."""
    output_dir = tmp_path / "out"
    unsafe_types = [SimpleNamespace(type="dot_claude", host_path="../escape")]

    monkeypatch.setattr(fh, "pull_directory", lambda *args, **kwargs: (0, 0))
    client = _make_client(
        system_folder_types=unsafe_types,
        system_folder_record=SimpleNamespace(id="sf-1"),
        download_url=SimpleNamespace(url="https://example.com/system-folder"),
    )

    with pytest.raises(fh.FilesystemError, match="Invalid system folder host_path"):
        fh.pull_task_filesystem_snapshot(client=client, task_id="task-1", output_dir=output_dir)
