"""
Team Sync — share project memory with teammates.

Each project has .kodara/index.json — push it to a shared dir,
teammates pull it. No server. No accounts.

Shared dir can be: network share, Dropbox, OneDrive, git-tracked folder.
"""

from __future__ import annotations

import json
import time
from pathlib import Path
from typing import Optional

from ..memory.store import MemoryStore, KODARA_DIR

_CONFIG_NAME = "team.json"


# ── Config (stored in project's .kodara/team.json) ────────────────────────────

def _config_path(project_root: Path) -> Path:
    return project_root / KODARA_DIR / _CONFIG_NAME


def _load_config(project_root: Path) -> dict:
    p = _config_path(project_root)
    if p.exists():
        try:
            return json.loads(p.read_text(encoding="utf-8"))
        except Exception:
            pass
    return {}


def _save_config(project_root: Path, config: dict) -> None:
    p = _config_path(project_root)
    p.parent.mkdir(parents=True, exist_ok=True)
    p.write_text(json.dumps(config, indent=2), encoding="utf-8")


def get_shared_dir(project_root: Path) -> Optional[Path]:
    sd = _load_config(project_root).get("shared_dir")
    return Path(sd) if sd else None


def set_shared_dir(shared_dir: str, project_root: Path) -> Path:
    resolved = Path(shared_dir).expanduser().resolve()
    config = _load_config(project_root)
    config["shared_dir"] = str(resolved)
    _save_config(project_root, config)
    return resolved


# ── Push ──────────────────────────────────────────────────────────────────────

def push(project_root: Path) -> str:
    """Serialise .kodara/index.db to JSON and copy to shared dir. Returns destination path."""
    shared_dir = get_shared_dir(project_root)
    if not shared_dir:
        raise ValueError(
            "Shared dir not configured.\n"
            "Run: kodara team config --shared-dir <path>"
        )
    shared_dir.mkdir(parents=True, exist_ok=True)

    store = MemoryStore(project_root)
    if not store.exists():
        raise ValueError("Project not initialised. Run: kodara init")

    idx = store.load()
    if not idx:
        raise ValueError("Index is empty. Run: kodara init")

    from dataclasses import asdict
    data = asdict(idx)
    data["_pushed_at"] = time.time()
    data["_pushed_by"] = _username()

    project_name = project_root.name
    dst = shared_dir / f"{project_name}.json"
    tmp = dst.with_suffix(".tmp")
    tmp.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
    tmp.replace(dst)

    return str(dst)


# ── Pull ──────────────────────────────────────────────────────────────────────

def pull(project_root: Path) -> list[str]:
    """Pull matching project index from shared dir into .kodara/."""
    shared_dir = get_shared_dir(project_root)
    if not shared_dir:
        raise ValueError(
            "Shared dir not configured.\n"
            "Run: kodara team config --shared-dir <path>"
        )
    if not shared_dir.exists():
        raise ValueError(f"Shared dir does not exist: {shared_dir}")

    project_name = project_root.name
    candidates = list(shared_dir.glob(f"{project_name}.json"))
    if not candidates:
        # Try any json that matches by display_name
        for f in shared_dir.glob("*.json"):
            try:
                d = json.loads(f.read_text(encoding="utf-8"))
                if d.get("display_name") == project_name:
                    candidates.append(f)
            except Exception:
                pass

    if not candidates:
        return []

    store = MemoryStore(project_root)
    store.init_dir()
    pulled = []

    for src in candidates:
        try:
            data = json.loads(src.read_text(encoding="utf-8"))
        except Exception:
            continue

        from ..memory.store import KodaraIndex, INDEX_VERSION
        idx = KodaraIndex(
            repo_id         = data.get("repo_id", ""),
            display_name    = data.get("display_name", ""),
            source_root     = data.get("source_root", ""),
            indexed_at      = float(data.get("indexed_at", 0)),
            index_version   = INDEX_VERSION,
            file_count      = int(data.get("file_count", 0)),
            language_counts = data.get("language_counts", {}),
            modules         = data.get("modules", {}),
            graph_edges     = data.get("graph_edges", []),
            file_hashes     = data.get("file_hashes", {}),
        )
        store.save(idx)
        pulled.append(src.name)

    return pulled


# ── Status ────────────────────────────────────────────────────────────────────

def status(project_root: Path) -> dict:
    shared_dir = get_shared_dir(project_root)
    store = MemoryStore(project_root)
    project_name = project_root.name

    shared_exists = False
    pushed_at = None
    pushed_by = None

    if shared_dir and shared_dir.exists():
        candidate = shared_dir / f"{project_name}.json"
        if candidate.exists():
            shared_exists = True
            try:
                d = json.loads(candidate.read_text(encoding="utf-8"))
                pushed_at = d.get("_pushed_at")
                pushed_by = d.get("_pushed_by")
            except Exception:
                pass

    return {
        "shared_dir": str(shared_dir) if shared_dir else None,
        "local_exists": store.exists(),
        "shared_exists": shared_exists,
        "pushed_at": pushed_at,
        "pushed_by": pushed_by,
    }


def _username() -> str:
    try:
        import getpass
        return getpass.getuser()
    except Exception:
        return "unknown"
