"""Git sync orchestration mixin for the UserManager."""

from __future__ import annotations

from pathlib import Path
from typing import Any

import time

import structlog

from proxym.dashboard.users._models import User


logger = structlog.get_logger()


class GitSyncMixin:
    """Git-sync orchestration for UserManager (requires GitUserIdentityMixin)."""

    def _discover_git_user(self) -> User | None:
        """Discover current user from git config and create if not exists."""
        try:
            git_name, git_email = self._read_git_identity()
            if not git_name and not git_email:
                return None
            return self._upsert_git_identity(git_name, git_email)
        except Exception:
            return None

    def _resolve_git_repo_root(self) -> Path | None:
        """Find a git repository root near this process or source tree."""
        for candidate in self._candidate_git_repo_paths():
            repo_root = self._resolve_git_root_candidate(candidate)
            if repo_root is not None:
                return repo_root
        return None

    def _parse_git_log_authors(self, log_output: str) -> list[tuple[str, str]]:
        """Parse unique author/email pairs from git log output."""
        authors: list[tuple[str, str]] = []
        seen: set[str] = set()
        for line in log_output.splitlines():
            if "|" not in line:
                continue
            name, email = line.split("|", 1)
            key = f"{name}|{email}".lower()
            if key in seen or not email:
                continue
            seen.add(key)
            authors.append((name, email))
        return authors

    def _upsert_git_user(self, name: str, email: str) -> tuple[User, bool]:
        """Create or update a user discovered from git history.

        Returns (user, created_new).
        """
        existing = self.find_by_email(email)
        if existing:
            existing.last_seen_at = time.time()
            if name and not existing.name:
                existing.name = name
            self._save()
            return existing, False

        user = User(
            name=name,
            email=email,
            username=email.split("@")[0],
            git_configured=True,
            last_seen_at=time.time(),
        )
        self.create_user(user)
        return user, True

    def _upsert_git_authors(self, authors: list[tuple[str, str]]) -> list[User]:
        """Create users for newly discovered author tuples."""
        discovered: list[User] = []
        for name, email in authors:
            user, created = self._upsert_git_user(name, email)
            if created:
                discovered.append(user)
        return discovered

    def _sync_git_users_from_repo(self, cwd: Path, git_dir: Path) -> list[User]:
        """Discover users from a repository using CLI when available, otherwise fallback."""
        authors = self._sync_from_git_log_with_cli(cwd)
        if authors is None:
            authors = self._collect_git_authors_from_objects(git_dir)
        return self._upsert_git_authors(authors)

    def sync_from_git_log(self, repo_path: Path | None = None) -> list[User]:
        """Discover users from git commit history."""
        try:
            cwd = repo_path or self._resolve_git_repo_root()

            if not self._is_existing_directory(cwd):
                logger.warning("git_repo_root_not_found", cwd=str(cwd) if cwd else None)
                return []

            git_dir = self._resolve_git_dir(cwd)
            if git_dir is None:
                logger.warning("git_dir_not_found", cwd=str(cwd))
                return []

            discovered = self._sync_git_users_from_repo(cwd, git_dir)
            self._save()
            return discovered

        except Exception:
            return []

    # ── Git sync metadata ─────────────────────────────────────

    def get_git_sync_metadata(self) -> dict[str, Any]:
        """Return the last git sync metadata."""
        return dict(self._git_sync_meta)

    def set_git_sync_metadata(self, last_sync_at: float, discovered_count: int) -> None:
        """Record a completed git sync."""
        self._git_sync_meta["last_sync_at"] = last_sync_at
        self._git_sync_meta["discovered_count"] = discovered_count
        self._git_sync_meta["total_users"] = len(self.users)
        self._save()
