import json
import tempfile
import unittest
from pathlib import Path

from click.testing import CliRunner

from claude_history.cli import cli


def _entry(
    entry_type: str,
    message_id: str,
    text: str,
    timestamp: str,
    *,
    is_meta: bool = False,
):
    return {
        "type": entry_type,
        "uuid": f"uuid-{message_id}",
        "sessionId": "session-123",
        "timestamp": timestamp,
        "isMeta": is_meta,
        "message": {
            "id": message_id,
            "content": [{"type": "text", "text": text}],
        },
    }


def _tool_result_entry(message_id: str, timestamp: str, text: str):
    return {
        "type": "user",
        "uuid": f"uuid-{message_id}",
        "sessionId": "session-123",
        "timestamp": timestamp,
        "message": {
            "id": message_id,
            "content": [{"type": "tool_result", "content": text}],
        },
    }


def _write_conversation(base_dir: Path, entries: list[dict]) -> Path:
    project_dir = base_dir / "project-one"
    project_dir.mkdir(parents=True, exist_ok=True)
    conv_path = project_dir / "session-123.jsonl"
    with open(conv_path, "w", encoding="utf-8") as f:
        for entry in entries:
            f.write(json.dumps(entry) + "\n")
    return conv_path


class CliBehaviorTests(unittest.TestCase):
    def test_view_tail_shows_last_messages(self):
        with tempfile.TemporaryDirectory() as tmp:
            base = Path(tmp)
            entries = [
                _entry("user", "u1", "user one", "2026-01-01T00:00:01Z"),
                _entry("assistant", "a1", "assistant one", "2026-01-01T00:00:02Z"),
                _entry("user", "u2", "user two", "2026-01-01T00:00:03Z"),
                _entry("assistant", "a2", "assistant two", "2026-01-01T00:00:04Z"),
                _entry("user", "u3", "user three", "2026-01-01T00:00:05Z"),
                _tool_result_entry("tool1", "2026-01-01T00:00:06Z", "tool payload"),
                _entry("assistant", "a3", "assistant three", "2026-01-01T00:00:07Z"),
                _entry("user", "u4", "user four", "2026-01-01T00:00:08Z"),
                _entry("assistant", "a4", "assistant four", "2026-01-01T00:00:09Z"),
            ]
            _write_conversation(base, entries)

            runner = CliRunner()
            result = runner.invoke(
                cli,
                ["view", "session-123", "--tail", "-n", "3", "--no-tools"],
                env={"CLAUDE_HISTORY_DIR": str(base)},
            )

            self.assertEqual(result.exit_code, 0, result.output)
            self.assertIn("Messages (showing 3 of 8):", result.output)
            self.assertIn("assistant three", result.output)
            self.assertIn("user four", result.output)
            self.assertIn("assistant four", result.output)
            self.assertNotIn("assistant two", result.output)

    def test_view_offset_is_applied_after_meta_filtering(self):
        with tempfile.TemporaryDirectory() as tmp:
            base = Path(tmp)
            entries = [
                _entry(
                    "user",
                    "meta-user",
                    "<system-reminder>meta</system-reminder>",
                    "2026-01-01T00:00:00Z",
                    is_meta=True,
                ),
                _entry("user", "u1", "user one", "2026-01-01T00:00:01Z"),
                _entry("assistant", "a1", "assistant one", "2026-01-01T00:00:02Z"),
                _entry("user", "u2", "user two", "2026-01-01T00:00:03Z"),
                _entry("assistant", "a2", "assistant two", "2026-01-01T00:00:04Z"),
            ]
            _write_conversation(base, entries)

            runner = CliRunner()
            result = runner.invoke(
                cli,
                ["view", "session-123", "-o", "2", "-n", "2", "--no-tools"],
                env={"CLAUDE_HISTORY_DIR": str(base)},
            )

            self.assertEqual(result.exit_code, 0, result.output)
            self.assertIn("Messages (showing 2 of 4):", result.output)
            self.assertIn("user two", result.output)
            self.assertIn("assistant two", result.output)
            self.assertNotIn("assistant one", result.output)

    def test_catchup_prioritizes_end_and_keeps_final_assistant_full(self):
        with tempfile.TemporaryDirectory() as tmp:
            base = Path(tmp)
            final_text = "FINAL_HANDOFF_" + ("x" * 420)
            entries: list[dict] = []
            for i in range(1, 8):
                entries.append(
                    _entry(
                        "user",
                        f"u{i}",
                        f"EARLY_CONTEXT_SHOULD_DROP_{i}",
                        f"2026-01-01T00:00:{i:02d}Z",
                    )
                )
                entries.append(
                    _entry(
                        "assistant",
                        f"a{i}",
                        f"assistant response {i}",
                        f"2026-01-01T00:01:{i:02d}Z",
                    )
                )
            entries.append(_entry("user", "u-last", "latest user request", "2026-01-01T00:02:01Z"))
            entries.append(_entry("assistant", "a-last", final_text, "2026-01-01T00:02:02Z"))
            _write_conversation(base, entries)

            runner = CliRunner()
            result = runner.invoke(
                cli,
                ["catchup", "session-123", "-c", "350"],
                env={"CLAUDE_HISTORY_DIR": str(base)},
            )

            self.assertEqual(result.exit_code, 0, result.output)
            self.assertIn("## Final Assistant Message (Full)", result.output)
            self.assertIn(final_text, result.output)
            self.assertIn(
                "... (earlier messages omitted to prioritize recent context)",
                result.output,
            )
            self.assertNotIn("EARLY_CONTEXT_SHOULD_DROP_1", result.output)


if __name__ == "__main__":
    unittest.main()
