"""A4: Session Outcome Signals — edits, git ops, tests."""

from .base import BaseAnalyzer
from .helpers import SHELL_TOOLS, EDIT_TOOLS, is_shell_error

TEST_COMMANDS = ["pytest", "npm test", "go test", "jest", "cargo test"]
TEST_FAIL_INDICATORS = ["FAILED", "FAIL", "Error", "failures", "failed", "exit code 1", "exit status 1"]
TEST_PASS_INDICATORS = ["passed", "PASSED", "OK", "success", "0 failures", "exit code 0", "All tests passed"]


class SessionOutcomesAnalyzer(BaseAnalyzer):
    name = "a04_session_outcomes"

    def analyze(self, sessions_df, messages_df, tool_calls_df, tool_results_df, token_usage_df) -> dict:
        per_session = []

        for session in self.iter_sessions(sessions_df):
            sid = session["id"]
            stream = self.build_message_stream(messages_df, tool_calls_df, tool_results_df, sid)
            if not stream:
                continue

            edit_count = 0
            files_edited = set()
            has_git_commit = False
            has_git_push = False
            has_test_run = False
            test_results = []
            git_ops = {"git commit": 0, "git push": 0, "git diff": 0,
                       "git checkout": 0, "git reset": 0, "git stash": 0}

            for i, m in enumerate(stream):
                if m["msg_type"] != "tool_call":
                    continue

                tool_name = m.get("tool_name") or ""
                tool_input = m.get("tool_input")
                tool_input_str = ""
                if isinstance(tool_input, dict):
                    tool_input_str = tool_input.get("command", "") or tool_input.get("file_path", "") or str(tool_input)
                elif isinstance(tool_input, str):
                    tool_input_str = tool_input
                tool_input_lower = tool_input_str.lower()

                # Edit tools
                if tool_name in EDIT_TOOLS:
                    edit_count += 1
                    if isinstance(tool_input, dict):
                        fp = tool_input.get("file_path") or tool_input.get("path") or tool_input.get("file")
                        if fp:
                            files_edited.add(fp)

                # Shell tools
                if tool_name in SHELL_TOOLS:
                    for gop in git_ops:
                        if gop in tool_input_lower:
                            git_ops[gop] += 1
                    if "git commit" in tool_input_lower:
                        has_git_commit = True
                    if "git push" in tool_input_lower:
                        has_git_push = True

                    if any(tc in tool_input_lower for tc in TEST_COMMANDS):
                        has_test_run = True
                        # Check result
                        result_output = self._find_result(stream, i)
                        if result_output:
                            is_fail = any(p in result_output for p in TEST_FAIL_INDICATORS)
                            is_pass = any(p in result_output for p in TEST_PASS_INDICATORS)
                            if is_fail:
                                test_results.append("fail")
                            elif is_pass:
                                test_results.append("pass")

            has_test_pass_after_fail = False
            seen_fail = False
            for r in test_results:
                if r == "fail":
                    seen_fail = True
                elif r == "pass" and seen_fail:
                    has_test_pass_after_fail = True
                    break

            session_ended_with_user = stream[-1]["msg_type"] == "user" if stream else False

            per_session.append({
                "session_id": sid,
                "has_edits": edit_count > 0,
                "edit_count": edit_count,
                "files_edited": len(files_edited),
                "has_git_commit": has_git_commit,
                "has_git_push": has_git_push,
                "has_test_run": has_test_run,
                "has_test_pass_after_fail": has_test_pass_after_fail,
                "session_ended_with_user_msg": session_ended_with_user,
                "git_operations": git_ops,
            })

        return {
            "sessions_with_edits": sum(1 for s in per_session if s["has_edits"]),
            "sessions_with_commits": sum(1 for s in per_session if s["has_git_commit"]),
            "sessions_with_tests": sum(1 for s in per_session if s["has_test_run"]),
            "total_sessions": len(per_session),
            "per_session": per_session,
        }

    def _find_result(self, stream, tool_idx):
        for j in range(tool_idx + 1, min(tool_idx + 5, len(stream))):
            if stream[j]["msg_type"] == "tool_result":
                return stream[j].get("result_output") or ""
        return ""
