"""GitHub Copilot Chat collector: parses VS Code Copilot Chat history."""

import json
import sqlite3
import sys
from pathlib import Path
from typing import Optional

from memotrail.utils import get_logger

logger = get_logger("memotrail.collectors.copilot")


def _get_copilot_storage_dir() -> Path:
    """Get VS Code's workspace storage directory based on platform."""
    if sys.platform == "darwin":
        return Path.home() / "Library" / "Application Support" / "Code" / "User" / "workspaceStorage"
    elif sys.platform == "win32":
        appdata = Path.home() / "AppData" / "Roaming"
        return appdata / "Code" / "User" / "workspaceStorage"
    else:
        return Path.home() / ".config" / "Code" / "User" / "workspaceStorage"


def find_session_files(storage_dir: Path | None = None) -> list[Path]:
    """Find all VS Code state.vscdb files that may contain Copilot Chat data.

    Copilot stores interactive sessions in:
    <storage_dir>/<workspace-hash>/state.vscdb
    under the key `interactive.sessions`.
    """
    base_dir = storage_dir or _get_copilot_storage_dir()
    if not base_dir.exists():
        logger.warning(f"VS Code storage directory not found: {base_dir}")
        return []

    vscdb_files = []
    for workspace_dir in base_dir.iterdir():
        if not workspace_dir.is_dir():
            continue
        state_file = workspace_dir / "state.vscdb"
        if state_file.exists():
            vscdb_files.append(state_file)

    logger.info(f"Found {len(vscdb_files)} VS Code workspace(s) in {base_dir}")
    return sorted(vscdb_files)


def parse_session_file(filepath: Path) -> list[dict]:
    """Parse a VS Code state.vscdb file and extract Copilot Chat sessions.

    Returns:
        List of session dicts, each with: project, messages, source_file
    """
    sessions = []

    try:
        conn = sqlite3.connect(f"file:{filepath}?mode=ro", uri=True)
        conn.row_factory = sqlite3.Row

        # Copilot Chat stores data under these keys
        chat_keys = [
            "interactive.sessions",
            "github.copilot.chat",
        ]

        for key in chat_keys:
            try:
                row = conn.execute(
                    "SELECT value FROM ItemTable WHERE [key] = ?", (key,)
                ).fetchone()
                if row and row["value"]:
                    parsed = _parse_copilot_data(row["value"], filepath)
                    sessions.extend(parsed)
            except sqlite3.OperationalError:
                continue

        conn.close()
    except Exception as e:
        logger.error(f"Error reading {filepath}: {e}")

    return sessions


def _parse_copilot_data(raw_value: str, filepath: Path) -> list[dict]:
    """Parse JSON chat data from a Copilot database value."""
    sessions = []

    try:
        data = json.loads(raw_value)
    except (json.JSONDecodeError, TypeError):
        return []

    project = _infer_project(filepath)

    # Handle both list and dict formats
    if isinstance(data, list):
        for item in data:
            messages = _extract_messages(item)
            if messages:
                sessions.append({
                    "project": project,
                    "messages": messages,
                    "source_file": str(filepath),
                })
    elif isinstance(data, dict):
        # May have sessions, conversations, or chats key
        for key in ("sessions", "conversations", "chats"):
            if key in data and isinstance(data[key], list):
                for item in data[key]:
                    messages = _extract_messages(item)
                    if messages:
                        sessions.append({
                            "project": project,
                            "messages": messages,
                            "source_file": str(filepath),
                        })
                break
        else:
            # Try to parse as a single conversation
            messages = _extract_messages(data)
            if messages:
                sessions.append({
                    "project": project,
                    "messages": messages,
                    "source_file": str(filepath),
                })

    return sessions


def _extract_messages(item: dict) -> list[dict]:
    """Extract messages from a single Copilot conversation object."""
    if not isinstance(item, dict):
        return []

    messages = []

    # Look for exchanges/requests/messages
    exchanges = item.get("exchanges", item.get("requests", item.get("messages", [])))
    if not isinstance(exchanges, list):
        return []

    for exchange in exchanges:
        if not isinstance(exchange, dict):
            continue

        # User prompt
        prompt = exchange.get("prompt", exchange.get("message", exchange.get("text", "")))
        if isinstance(prompt, str) and prompt.strip():
            messages.append({
                "role": "user",
                "content": prompt.strip(),
                "timestamp": exchange.get("timestamp", ""),
            })

        # Assistant response
        response = exchange.get("response", exchange.get("result", ""))
        if isinstance(response, list):
            # Response may be a list of content blocks
            parts = []
            for part in response:
                if isinstance(part, dict) and part.get("type") == "markdown":
                    parts.append(part.get("value", ""))
                elif isinstance(part, dict) and "value" in part:
                    parts.append(part["value"])
                elif isinstance(part, str):
                    parts.append(part)
            response = "\n".join(parts)
        elif isinstance(response, dict):
            response = response.get("value", response.get("message", ""))

        if isinstance(response, str) and response.strip():
            messages.append({
                "role": "assistant",
                "content": response.strip(),
                "timestamp": exchange.get("timestamp", ""),
            })

    return messages


def _infer_project(filepath: Path) -> Optional[str]:
    """Infer project name from workspace metadata."""
    workspace_dir = filepath.parent
    workspace_json = workspace_dir / "workspace.json"
    if workspace_json.exists():
        try:
            with open(workspace_json, "r") as f:
                data = json.loads(f.read())
                folder = data.get("folder", "")
                if folder:
                    folder = folder.replace("file://", "")
                    return Path(folder).name
        except Exception:
            pass
    return workspace_dir.name


def collect_all_sessions(storage_dir: Path | None = None) -> list[dict]:
    """Collect and parse all Copilot sessions."""
    files = find_session_files(storage_dir)
    all_sessions = []

    for f in files:
        sessions = parse_session_file(f)
        for s in sessions:
            if s["messages"]:
                all_sessions.append(s)
                logger.info(
                    f"Collected Copilot session: {s['project'] or 'unknown'} "
                    f"({len(s['messages'])} messages)"
                )

    logger.info(f"Collected {len(all_sessions)} Copilot sessions total")
    return all_sessions
