"""A8: Session linkage — continuation detection, sequential chains, parallel sessions."""

from datetime import datetime

from .base import BaseAnalyzer
from .helpers import is_compaction_message


def _parse_ts(ts) -> datetime | None:
    if not ts:
        return None
    try:
        return datetime.fromisoformat(str(ts).replace("Z", "+00:00"))
    except (ValueError, TypeError):
        return None


class SessionLinkageAnalyzer(BaseAnalyzer):
    name = "a08_session_linkage"

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

        # Sort sessions by first_seen
        sorted_sessions = sessions_df.sort_values("first_seen")

        # Pre-compute start/end times
        session_times = []
        for _, s in sorted_sessions.iterrows():
            start = _parse_ts(s.get("first_seen"))
            end = _parse_ts(s.get("last_updated"))
            session_times.append((s.to_dict(), start, end))

        prev_by_repo = {}

        for idx, (s, start, end) in enumerate(session_times):
            sid = s["id"]
            repo = s.get("repo_name")
            msgs = self.get_session_messages(messages_df, sid)

            # Compaction detection
            compaction_count = 0
            is_continuation = False
            for _, m in msgs.iterrows():
                mc = m.get("content")
                if m["msg_type"] == "user" and isinstance(mc, str) and mc:
                    if is_compaction_message(mc):
                        compaction_count += 1
                        is_continuation = True

            # Time gap to previous session (same repo)
            time_gap_min = None
            is_sequential = False
            prev = prev_by_repo.get(repo)
            if prev and start:
                _, _, prev_end = prev
                if prev_end:
                    gap_sec = (start - prev_end).total_seconds()
                    time_gap_min = round(gap_sec / 60, 2)
                    is_sequential = gap_sec < 7200 and repo is not None

            # Parallel sessions
            has_parallel = False
            parallel_same_repo = False
            if start and end:
                for j, (other_s, other_start, other_end) in enumerate(session_times):
                    if j == idx:
                        continue
                    if other_start and other_end and other_start < end and start < other_end:
                        has_parallel = True
                        if other_s.get("repo_name") == repo and repo is not None:
                            parallel_same_repo = True
                            break

            per_session.append({
                "session_id": sid,
                "is_continuation": is_continuation,
                "compaction_count": compaction_count,
                "time_gap_to_prev_session_min": time_gap_min,
                "is_sequential": is_sequential,
                "has_parallel_sessions": has_parallel,
                "parallel_same_repo": parallel_same_repo,
            })

            prev_by_repo[repo] = (s, start, end)

        return {
            "total_sessions": len(per_session),
            "continuation_sessions": sum(1 for s in per_session if s["is_continuation"]),
            "sequential_sessions": sum(1 for s in per_session if s["is_sequential"]),
            "parallel_sessions": sum(1 for s in per_session if s["has_parallel_sessions"]),
            "per_session": per_session,
        }
