"""End-to-end integration tests for unified chat interface."""

from pathlib import Path
from unittest.mock import Mock, patch

import pytest

from fwauto.cli import _build_deploy_state, _build_log_state
from fwauto.command_logger import CommandLogger
from fwauto.slash_commands import (
    parse_command_args,
    parse_slash_command,
)


@pytest.fixture
def mock_state():
    """Create mock FirmwareState for testing."""
    return {
        "user_prompt": "",
        "project_root": "/test/project",
        "project_initialized": True,
        "platform": "am62x",
        "execution_mode": "chat",
        "command": "chat",
        "command_args": {},
        "mode_metadata": {},
        "command_error": None,
        "build_status": "pending",
        "build_errors": [],
        "build_log": "",
        "deploy_status": "pending",
        "deploy_errors": [],
        "deploy_log": "",
        "iteration": 0,
        "max_retries": 3,
        "log_file_path": None,
        "log_analysis_result": None,
        "firmware_path": None,
    }


class TestSlashCommandParsing:
    """Test slash command parsing with various formats."""

    def test_parse_build_command(self):
        cmd = parse_slash_command("/build")
        assert cmd is not None
        assert cmd.name == "build"
        assert cmd.raw_args == []

    def test_parse_deploy_with_binary_args(self):
        cmd = parse_slash_command("/deploy --binary-args test.hex")
        assert cmd is not None
        assert cmd.name == "deploy"
        assert "--binary-args" in cmd.raw_args
        assert "test.hex" in cmd.raw_args

    def test_parse_deploy_with_scenario(self):
        cmd = parse_slash_command("/deploy --scenario quick")
        assert cmd is not None
        assert cmd.name == "deploy"

        # Parse args
        args = parse_command_args(cmd)
        assert "scenario" in args or "binary_args" in args

    def test_parse_log_with_prompt(self):
        cmd = parse_slash_command("/log uart.log '有任何 error 嗎?'")
        assert cmd is not None
        assert cmd.name == "log"

        args = parse_command_args(cmd)
        assert args["log_path"] == "uart.log"
        assert args["analysis_prompt"] == "有任何 error 嗎?"

    def test_parse_natural_language_returns_none(self):
        cmd = parse_slash_command("請幫我分析這個錯誤")
        assert cmd is None

    def test_parse_invalid_command_returns_none(self):
        cmd = parse_slash_command("/invalid_cmd")
        assert cmd is None


class TestParameterConversion:
    """Test parameter conversion layer consistency."""

    def test_build_deploy_state_consistency(self):
        state1 = _build_deploy_state("test.hex", "/project", "am62x")
        state2 = _build_deploy_state("test.hex", "/project", "am62x")

        # Should produce identical states
        assert state1["command_args"] == state2["command_args"]
        assert state1["execution_mode"] == "deploy"
        assert state1["command_args"]["binary_args"] == "test.hex"

    def test_build_log_state_double_storage(self):
        state = _build_log_state("uart.log", "分析", "/project", "am62x")

        # Verify double storage
        assert state["log_file_path"] == "uart.log"
        assert state["command_args"]["log_path"] == "uart.log"
        assert state["command_args"]["analysis_prompt"] == "分析"


class TestCommandLogger:
    """Test CommandLogger functionality."""

    def test_command_logger_initialization(self, tmp_path, mock_state):
        logger = CommandLogger(tmp_path, mock_state)

        assert logger.log_file.exists()
        content = logger.log_file.read_text(encoding="utf-8")
        assert "Command Execution Log" in content
        assert str(tmp_path) in content

    def test_command_logger_logs_execution(self, tmp_path, mock_state):
        logger = CommandLogger(tmp_path, mock_state)
        logger.log_command_execution(
            command="/deploy --binary-args test.hex",
            parameters={"binary_args": "test.hex"},
            status="success",
            output="✅ Deploy successful",
        )

        content = logger.log_file.read_text(encoding="utf-8")
        assert "/deploy --binary-args test.hex" in content
        assert "binary_args: test.hex" in content
        assert "Status: success" in content
        assert "✅ Deploy successful" in content

    def test_command_logger_finalize(self, tmp_path, mock_state):
        logger = CommandLogger(tmp_path, mock_state)
        logger.command_count = 5
        logger.finalize()

        content = logger.log_file.read_text(encoding="utf-8")
        assert "Total commands: 5" in content
        assert "Session ended:" in content


class TestCLIEntryPoint:
    """Test CLI entry point routing."""

    def test_main_no_args_enters_chat(self, monkeypatch):
        """Test that fwauto with no args enters chat mode."""
        import sys

        from fwauto.cli import main

        monkeypatch.setattr(sys, "argv", ["fwauto"])

        mock_graph = Mock()
        mock_graph.invoke.return_value = {"chat_completed": True}

        mock_project_root = Path("/test/project")
        mock_config = Mock()
        mock_config.platform = "am62x"

        with patch("fwauto.config.find_project_root", return_value=mock_project_root):
            with patch("fwauto.config.load_project_config", return_value=mock_config):
                with patch("fwauto.graph.create_firmware_graph", return_value=mock_graph):
                    try:
                        main()
                    except SystemExit:
                        pass  # Expected exit after chat completes

        # Verify graph.invoke was called with chat state
        if mock_graph.invoke.called:
            call_args = mock_graph.invoke.call_args[0][0]
            assert call_args["execution_mode"] == "chat"
            assert call_args["command"] == "chat"

    def test_main_with_build_arg_uses_typer(self, monkeypatch):
        """Test that fwauto build uses direct CLI command."""
        import sys

        from fwauto.cli import main

        monkeypatch.setattr(sys, "argv", ["fwauto", "build"])

        with patch("fwauto.cli.app") as mock_app:
            try:
                main()
            except SystemExit:
                pass  # May exit after command

        # Verify Typer app was called (not chat mode)
        assert mock_app.called


class TestEndToEndScenarios:
    """Test complete user scenarios end-to-end."""

    def test_slash_command_full_parsing_flow(self):
        """Test complete parsing flow from user input to parsed args."""
        # User input
        user_input = "/deploy --binary-args test.hex --scenario quick"

        # Parse slash command
        cmd = parse_slash_command(user_input)
        assert cmd is not None
        assert cmd.name == "deploy"

        # Parse arguments
        args = parse_command_args(cmd)

        # Verify --binary-args takes priority
        assert args["binary_args"] == "test.hex"

    def test_log_command_with_cjk_characters(self):
        """Test log command with CJK characters."""
        user_input = "/log uart.log '有任何 error 嗎？LED 狀態如何？'"

        cmd = parse_slash_command(user_input)
        assert cmd is not None
        assert cmd.name == "log"

        args = parse_command_args(cmd)
        assert args["log_path"] == "uart.log"
        assert "error" in args["analysis_prompt"]
        assert "LED" in args["analysis_prompt"]
