"""Tests for /files, /copy, /export, /stats, /tag, /rename, /branch, /effort, /doctor."""

from __future__ import annotations

import json
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path

from src.agent_runtime import LocalCodingAgent
from src.agent_session import AgentMessage, AgentSessionState
from src.agent_types import AgentRuntimeConfig, ModelConfig, UsageStats


def _make_agent(tmp_dir: str) -> LocalCodingAgent:
    return LocalCodingAgent(
        model_config=ModelConfig(model='test-model'),
        runtime_config=AgentRuntimeConfig(cwd=Path(tmp_dir)),
    )


def _set_session(agent: LocalCodingAgent, messages: list[AgentMessage]) -> None:
    session = AgentSessionState(
        system_prompt_parts=('You are a helper.',),
        messages=messages,
    )
    agent.last_session = session


class TestFilesCommand(unittest.TestCase):
    def test_no_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/files')
        self.assertIn('No active session', result.final_output)

    def test_no_files_in_context(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='Hi'),
            ])
            result = agent.run('/files')
        self.assertIn('No files loaded', result.final_output)

    def test_files_from_tool_calls(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Read main.py'),
                AgentMessage(
                    role='assistant', content='',
                    tool_calls=(
                        {'id': 'tc1', 'type': 'function', 'function': {
                            'name': 'Read',
                            'arguments': json.dumps({'file_path': '/home/user/project/main.py'}),
                        }},
                    ),
                ),
                AgentMessage(
                    role='tool', content='print("hello")',
                    name='Read',
                    tool_call_id='tc1',
                    metadata={'path': '/home/user/project/main.py'},
                ),
            ])
            result = agent.run('/files')
        self.assertIn('Files in context', result.final_output)
        self.assertIn('main.py', result.final_output)


class TestCopyCommand(unittest.TestCase):
    def test_no_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/copy')
        self.assertIn('No active session', result.final_output)

    def test_no_assistant_messages(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
            ])
            result = agent.run('/copy')
        self.assertIn('No assistant responses', result.final_output)

    def test_copies_latest_response(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='First response.'),
                AgentMessage(role='user', content='More'),
                AgentMessage(role='assistant', content='Second response with details.'),
            ])
            result = agent.run('/copy')
        self.assertIn('Copied', result.final_output)
        self.assertIn('response.md', result.final_output)
        # Verify the file was written
        tmp_file = Path(tempfile.gettempdir()) / 'claw-code' / 'response.md'
        self.assertTrue(tmp_file.exists())
        content = tmp_file.read_text()
        self.assertEqual(content, 'Second response with details.')

    def test_copies_nth_response(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='First.'),
                AgentMessage(role='user', content='More'),
                AgentMessage(role='assistant', content='Second.'),
            ])
            result = agent.run('/copy 1')
        tmp_file = Path(tempfile.gettempdir()) / 'claw-code' / 'response.md'
        content = tmp_file.read_text()
        self.assertEqual(content, 'First.')


class TestExportCommand(unittest.TestCase):
    def test_no_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/export')
        self.assertIn('No active session', result.final_output)

    def test_exports_with_auto_filename(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='Hi there'),
            ])
            result = agent.run('/export')
        self.assertIn('Exported 2 messages', result.final_output)
        self.assertIn('.txt', result.final_output)

    def test_exports_with_custom_filename(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='Hi'),
            ])
            result = agent.run('/export my_chat')
            self.assertIn('my_chat.txt', result.final_output)
            out_file = Path(tmp) / 'my_chat.txt'
            self.assertTrue(out_file.exists())
            content = out_file.read_text()
            self.assertIn('Hello', content)
            self.assertIn('Hi', content)


class TestStatsCommand(unittest.TestCase):
    def test_shows_statistics(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='Hi'),
                AgentMessage(role='user', content='Question'),
            ])
            agent.cumulative_usage = UsageStats(input_tokens=500, output_tokens=200)
            result = agent.run('/stats')
        self.assertIn('Session Statistics', result.final_output)
        self.assertIn('3 total', result.final_output)
        self.assertIn('2 user', result.final_output)
        self.assertIn('1 assistant', result.final_output)
        self.assertIn('500', result.final_output)
        self.assertIn('200', result.final_output)


class TestTagCommand(unittest.TestCase):
    def test_no_tags_initially(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/tag')
        self.assertIn('No tags set', result.final_output)

    def test_add_tag(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/tag important')
        self.assertIn('Added tag: important', result.final_output)

    def test_toggle_tag(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            agent.run('/tag my-tag')
            result = agent.run('/tag my-tag')
        self.assertIn('Removed tag: my-tag', result.final_output)

    def test_list_tags(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            agent.run('/tag alpha')
            agent.run('/tag beta')
            result = agent.run('/tag')
        self.assertIn('alpha', result.final_output)
        self.assertIn('beta', result.final_output)


class TestRenameCommand(unittest.TestCase):
    def test_no_name(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/rename')
        self.assertIn('Usage', result.final_output)

    def test_rename_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/rename My Cool Session')
        self.assertIn('renamed to: My Cool Session', result.final_output)


class TestBranchCommand(unittest.TestCase):
    def test_no_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/branch')
        self.assertIn('No active session', result.final_output)

    def test_branch_with_session(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
                AgentMessage(role='assistant', content='Hi'),
            ])
            result = agent.run('/branch my-feature')
        self.assertIn('Created branch "my-feature"', result.final_output)
        self.assertIn('Saved to:', result.final_output)

    def test_branch_auto_name(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            _set_session(agent, [
                AgentMessage(role='user', content='Hello'),
            ])
            result = agent.run('/branch')
        self.assertIn('Created branch "branch-', result.final_output)


class TestEffortCommand(unittest.TestCase):
    def test_show_current_effort(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/effort')
        self.assertIn('Current effort level: auto', result.final_output)

    def test_set_effort_level(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/effort high')
        self.assertIn('Set effort level to: high', result.final_output)

    def test_invalid_effort_level(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/effort extreme')
        self.assertIn('Invalid effort level', result.final_output)

    def test_all_valid_levels(self) -> None:
        for level in ('low', 'medium', 'high', 'max', 'auto'):
            with tempfile.TemporaryDirectory() as tmp:
                agent = _make_agent(tmp)
                result = agent.run(f'/effort {level}')
            self.assertIn(f'Set effort level to: {level}', result.final_output)


class TestDoctorCommand(unittest.TestCase):
    def test_shows_report(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            agent = _make_agent(tmp)
            result = agent.run('/doctor')
        output = result.final_output
        self.assertIn('Doctor Report', output)
        self.assertIn('Python version', output)
        self.assertIn('git', output)
        self.assertIn('Model', output)
        self.assertIn('Working directory', output)

    def test_detects_claude_md(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            (Path(tmp) / 'CLAUDE.md').write_text('memory file')
            agent = _make_agent(tmp)
            result = agent.run('/doctor')
        self.assertIn('CLAUDE.md', result.final_output)
        self.assertIn('found', result.final_output)


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