from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path

from pulka.tui.controllers.file_browser import FileTransferPlan
from pulka.tui.controllers.file_ops import FileOpsController


@dataclass
class _Entry:
    path: Path


class _FakeFileBrowser:
    def __init__(self) -> None:
        self.transfer_calls: list[tuple[str, list[tuple[Path, Path]]]] = []

    def resolve_entries(self, *, viewer):
        return [_Entry(path=Path("a.txt"))], None

    def plan_transfer(self, operation: str, dest: str, *, entries, sheet):
        del dest, entries, sheet
        return FileTransferPlan(
            targets=[(Path("a.txt"), Path("dest/a.txt"))],
            conflicts=[Path("dest/a.txt")],
            error=None,
        )

    def perform_transfer(self, operation: str, targets):
        self.transfer_calls.append((operation, list(targets)))
        return "Copied 1 item", [], 1

    def rename_entry(self, *, sheet, entry, new_name: str):
        del sheet, entry, new_name
        return None, None

    def make_directory(self, *, sheet, dest: str):
        del sheet, dest
        return None, None


class _FakePresenter:
    def __init__(self) -> None:
        self.confirm_calls: list[dict[str, object]] = []
        self.status_calls: list[dict[str, object]] = []

    def open_confirmation_modal(self, **kwargs) -> None:
        self.confirm_calls.append(kwargs)

    def open_status_modal(self, **kwargs) -> None:
        self.status_calls.append(kwargs)


class _FakeSheet:
    is_file_browser = True


class _FakeViewer:
    def __init__(self) -> None:
        self.sheet = _FakeSheet()
        self.status_message: str | None = None


def test_file_ops_transfer_conflict_prompts_then_executes() -> None:
    viewer = _FakeViewer()
    refresh_calls: list[object] = []
    invalidate_calls: list[object] = []
    browser = _FakeFileBrowser()
    presenter = _FakePresenter()

    def refresh() -> None:
        refresh_calls.append(object())

    def handle_refresh(sheet) -> None:
        del sheet

    def invalidate() -> None:
        invalidate_calls.append(object())

    ops = FileOpsController(
        file_browser=browser,
        presenter=presenter,  # type: ignore[arg-type]
        get_viewer=lambda: viewer,  # type: ignore[return-value]
        refresh=refresh,
        handle_file_browser_refresh=handle_refresh,
        invalidate=invalidate,
    )

    ops.request_transfer("copy", "dest")
    assert len(presenter.confirm_calls) == 1
    confirm = presenter.confirm_calls[0]
    assert confirm["context_type"] == "file_transfer_overwrite"

    on_confirm = confirm["on_confirm"]
    assert callable(on_confirm)
    on_confirm()

    assert browser.transfer_calls == [("copy", [(Path("a.txt"), Path("dest/a.txt"))])]
    assert refresh_calls
    assert invalidate_calls
