from __future__ import annotations

from pathlib import Path

import pytest

from shared_codex_state import SharedCodexState


SHARED_FIXTURE_NAMES = ("config.toml", "skills", "commands")


@pytest.fixture
def shared_state(tmp_path: Path) -> SharedCodexState:
    legacy = tmp_path / "legacy"
    accounts = tmp_path / "tray" / "accounts"
    legacy.mkdir(parents=True)
    for name in SHARED_FIXTURE_NAMES:
        target = legacy / name
        if "." in name:
            target.write_text(name, encoding="utf-8")
        else:
            target.mkdir()
    return SharedCodexState(legacy_codex_home=legacy, accounts_dir=accounts)


def test_sync_shared_links_shares_every_noncredential_entry(shared_state: SharedCodexState) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    (codex_home / "auth.json").write_text("account-auth", encoding="utf-8")
    (codex_home / "auth.json.bak").write_text("account-backup", encoding="utf-8")
    (codex_home / "state_5.sqlite").write_text("account-db", encoding="utf-8")
    (codex_home / "history.jsonl").write_text(
        '{"session_id":"account","ts":2,"text":"account"}\n',
        encoding="utf-8",
    )
    agents = codex_home / "agents"
    agents.mkdir()
    (agents / "reviewer.md").write_text("reviewer", encoding="utf-8")
    (codex_home / "future-state.json").write_text("future", encoding="utf-8")
    (shared_state.legacy_codex_home / "history.jsonl").write_text(
        '{"session_id":"shared","ts":1,"text":"shared"}\n',
        encoding="utf-8",
    )
    (shared_state.legacy_codex_home / "hooks.json").write_text("hooks", encoding="utf-8")
    shared_log = shared_state.legacy_codex_home / "log" / "codex-login.log"
    shared_log.parent.mkdir()
    shared_log.write_text("shared-log\n", encoding="utf-8")
    account_log = codex_home / "log" / "codex-login.log"
    account_log.parent.mkdir()
    account_log.write_text("account-log\n", encoding="utf-8")
    shared_cache = shared_state.legacy_codex_home / ".tmp" / "plugins" / ".git" / "FETCH_HEAD"
    shared_cache.parent.mkdir(parents=True)
    shared_cache.write_text("shared-cache", encoding="utf-8")
    account_cache = codex_home / ".tmp" / "plugins" / ".git" / "FETCH_HEAD"
    account_cache.parent.mkdir(parents=True)
    account_cache.write_text("account-cache", encoding="utf-8")

    shared_state.sync_shared_links(codex_home)

    for name in (
        *SHARED_FIXTURE_NAMES,
        ".tmp",
        "agents",
        "future-state.json",
        "history.jsonl",
        "hooks.json",
        "log",
    ):
        shared_entry = codex_home / name
        assert shared_entry.is_symlink()
        assert shared_entry.resolve() == (shared_state.legacy_codex_home / name).resolve()
    assert (codex_home / "agents" / "reviewer.md").read_text(encoding="utf-8") == "reviewer"
    assert (shared_state.legacy_codex_home / "history.jsonl").read_text(
        encoding="utf-8"
    ).splitlines() == [
        '{"session_id":"shared","ts":1,"text":"shared"}',
        '{"session_id":"account","ts":2,"text":"account"}',
    ]
    assert (codex_home / "auth.json").read_text(encoding="utf-8") == "account-auth"
    assert not (codex_home / "auth.json").is_symlink()
    assert (codex_home / "auth.json.bak").read_text(encoding="utf-8") == "account-backup"
    assert not (codex_home / "auth.json.bak").is_symlink()
    assert (codex_home / "state_5.sqlite").read_text(encoding="utf-8") == "account-db"
    assert not (codex_home / "state_5.sqlite").is_symlink()
    assert shared_log.read_text(encoding="utf-8") == "shared-log\naccount-log\n"
    assert shared_cache.read_text(encoding="utf-8") == "shared-cache"


def test_sync_shared_links_keeps_divergent_lock_files_per_account(
    shared_state: SharedCodexState,
) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    (codex_home / "daemon.lock").write_text('{"pid":1}', encoding="utf-8")
    (shared_state.legacy_codex_home / "daemon.lock").write_text('{"pid":2}', encoding="utf-8")

    shared_state.sync_shared_links(codex_home)

    entry = codex_home / "daemon.lock"
    assert not entry.is_symlink()
    assert entry.read_text(encoding="utf-8") == '{"pid":1}'
    assert (shared_state.legacy_codex_home / "daemon.lock").read_text(
        encoding="utf-8"
    ) == '{"pid":2}'


def test_sync_shared_links_unshares_previously_linked_lock_file(
    shared_state: SharedCodexState,
) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    (shared_state.legacy_codex_home / "daemon.lock").write_text('{"pid":2}', encoding="utf-8")
    (codex_home / "daemon.lock").symlink_to(shared_state.legacy_codex_home / "daemon.lock")

    shared_state.sync_shared_links(codex_home)

    entry = codex_home / "daemon.lock"
    assert not entry.is_symlink()
    assert entry.read_text(encoding="utf-8") == '{"pid":2}'


def test_sync_all_shared_links_merges_existing_conversation_state(
    shared_state: SharedCodexState,
) -> None:
    rafa_home = shared_state.accounts_dir / "rafa" / "CODEX_HOME"
    roy_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    shared_session = Path("2026/07/02/rollout-shared.jsonl")
    rafa_only_session = Path("2026/07/02/rollout-rafa.jsonl")
    roy_only_archive = Path("2026/07/01/rollout-roy.jsonl")

    for codex_home in (rafa_home, roy_home):
        path = codex_home / "sessions" / shared_session
        path.parent.mkdir(parents=True)
        path.write_text("shared\n", encoding="utf-8")
    rafa_only = rafa_home / "sessions" / rafa_only_session
    rafa_only.write_text("rafa\n", encoding="utf-8")
    roy_archive = roy_home / "archived_sessions" / roy_only_archive
    roy_archive.parent.mkdir(parents=True)
    roy_archive.write_text("roy\n", encoding="utf-8")

    shared_state.sync_all_shared_links()
    shared_state.sync_all_shared_links()

    for codex_home in (rafa_home, roy_home):
        assert (codex_home / "sessions").is_symlink()
        assert (codex_home / "archived_sessions").is_symlink()
        assert (codex_home / "sessions" / shared_session).read_text(encoding="utf-8") == (
            "shared\n"
        )
        assert (codex_home / "sessions" / rafa_only_session).read_text(
            encoding="utf-8"
        ) == "rafa\n"
        assert (codex_home / "archived_sessions" / roy_only_archive).read_text(
            encoding="utf-8"
        ) == "roy\n"


def test_sync_all_shared_links_preserves_conflicting_session_files(
    shared_state: SharedCodexState,
) -> None:
    relative_path = Path("2026/07/02/rollout-conflict.jsonl")
    rafa_session = shared_state.accounts_dir / "rafa" / "CODEX_HOME" / "sessions" / relative_path
    roy_session = shared_state.accounts_dir / "roy" / "CODEX_HOME" / "sessions" / relative_path
    rafa_session.parent.mkdir(parents=True)
    roy_session.parent.mkdir(parents=True)
    rafa_session.write_text("rafa\n", encoding="utf-8")
    roy_session.write_text("roy\n", encoding="utf-8")

    conflicts = shared_state.sync_all_shared_links()

    assert roy_session in conflicts
    canonical = shared_state.legacy_codex_home / "sessions" / relative_path
    assert canonical.read_text(encoding="utf-8") == "rafa\n"
    assert roy_session.read_text(encoding="utf-8") == "roy\n"


def test_sync_shared_links_never_raises_on_type_conflict(
    shared_state: SharedCodexState,
) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    (codex_home / "notes").write_text("account-file", encoding="utf-8")
    (shared_state.legacy_codex_home / "notes").mkdir()

    conflicts = shared_state.sync_shared_links(codex_home)

    assert conflicts == [codex_home / "notes"]
    assert (codex_home / "notes").read_text(encoding="utf-8") == "account-file"
    assert not (codex_home / "notes").is_symlink()


def test_sync_shared_links_conflict_leaves_other_entries_shared(
    shared_state: SharedCodexState,
) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    (codex_home / "notes").write_text("account-file", encoding="utf-8")
    (shared_state.legacy_codex_home / "notes").mkdir()
    (shared_state.legacy_codex_home / "hooks.json").write_text("hooks", encoding="utf-8")

    shared_state.sync_shared_links(codex_home)

    entry = codex_home / "hooks.json"
    assert entry.is_symlink()
    assert entry.resolve() == (shared_state.legacy_codex_home / "hooks.json").resolve()


def test_sync_shared_links_unshares_link_pointing_outside_shared_home(
    shared_state: SharedCodexState,
    tmp_path: Path,
) -> None:
    codex_home = shared_state.accounts_dir / "roy" / "CODEX_HOME"
    codex_home.mkdir(parents=True)
    foreign = tmp_path / "foreign-hooks.json"
    foreign.write_text("foreign", encoding="utf-8")
    (codex_home / "hooks.json").symlink_to(foreign)

    conflicts = shared_state.sync_shared_links(codex_home)

    entry = codex_home / "hooks.json"
    assert conflicts == [entry]
    assert not entry.is_symlink()
    assert entry.read_text(encoding="utf-8") == "foreign"
