"""
checkout_active_branches.py — For each Bitbucket repo with activity in the
last 15 days, identify the most recently active branch and check it out
locally (only if the repo is already cloned in repos/).
"""
import os
import sys
import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple

from git import Repo, GitCommandError
from git.exc import InvalidGitRepositoryError

try:
    from config_manager import ConfigManager
    from bitbucket_client import BitbucketClient
    from scan_recent import _get_additional_repositories
except ImportError:
    from .config_manager import ConfigManager
    from .bitbucket_client import BitbucketClient
    from .scan_recent import _get_additional_repositories

# Look-back window in days (hardcoded per plan)
ACTIVITY_DAYS = 15

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)],
)
logger = logging.getLogger(__name__)


def _checkout_branch(repo_path: Path, branch_name: str) -> Tuple[bool, str]:
    """
    Checkout the given branch in the local repo. Creates a tracking branch if needed.

    Returns:
        (success, message) — message describes the action taken or the reason for skipping.
    """
    try:
        repo = Repo(repo_path)
    except (InvalidGitRepositoryError, Exception) as e:
        return False, f"Invalid git repo: {e}"

    # Refuse to switch a dirty working tree to avoid clobbering local changes
    if repo.is_dirty(untracked_files=False):
        return False, "Working tree dirty (uncommitted changes); skipping"

    # Already on the target branch?
    try:
        current = repo.active_branch.name
    except Exception:
        current = None

    if current == branch_name:
        return True, f"Already on '{branch_name}'"

    # Fetch latest refs so the remote branch is visible locally
    try:
        repo.remote(name="origin").fetch()
    except Exception as e:
        logger.debug(f"fetch warning for {repo_path.name}: {e}")

    # If a local branch with that name already exists, just check it out
    local_names = {h.name for h in repo.heads}
    try:
        if branch_name in local_names:
            repo.git.checkout(branch_name)
            return True, f"Checked out existing local branch '{branch_name}'"

        # Otherwise create a local tracking branch from origin/<branch>
        remote_ref = f"origin/{branch_name}"
        repo.git.checkout("-b", branch_name, "--track", remote_ref)
        return True, f"Created tracking branch '{branch_name}' from {remote_ref}"
    except GitCommandError as e:
        return False, f"git checkout failed: {e}"


def run_checkout_active_branches() -> None:
    """Main entrypoint — find active branches and check them out locally."""
    project_root = Path(__file__).resolve().parent.parent
    if str(project_root) not in sys.path:
        sys.path.insert(0, str(project_root))
    os.chdir(project_root)

    try:
        config = ConfigManager()
    except Exception as e:
        logger.error(f"Failed to load config: {e}")
        sys.exit(1)

    if not config.get("bitbucket.workspace"):
        logger.error("Bitbucket workspace not configured")
        sys.exit(1)
    if not config.get("bitbucket.username"):
        logger.error("Bitbucket username/email not configured")
        sys.exit(1)
    has_api_token = bool(config.get("bitbucket.api_token"))
    has_app_password = bool(config.get("bitbucket.app_password"))
    if not has_api_token and not has_app_password:
        logger.error("Bitbucket authentication not configured (need API token or app password)")
        sys.exit(1)

    main_workspace = config.get("bitbucket.workspace")
    repos_dir = Path(config.get("scanning.repos_dir") or "./repos")

    bitbucket = BitbucketClient(
        workspace=main_workspace,
        username=config.get("bitbucket.username"),
        app_password=config.get("bitbucket.app_password") if not has_api_token else None,
        api_token=config.get("bitbucket.api_token"),
    )

    logger.info(f"Fetching repositories from workspace '{main_workspace}'...")
    repos: List[Dict] = bitbucket.get_all_repositories() or []
    additional = _get_additional_repositories(config)
    if additional:
        logger.info(f"Found {len(additional)} additional repositories from config")
        repos.extend(additional)

    if not repos:
        logger.warning("No repositories found")
        return

    logger.info(f"Checking {len(repos)} repos for activity in the last {ACTIVITY_DAYS} days...")

    # results: list of tuples (repo_slug, branch_name, action_msg, success)
    results: List[Tuple[str, Optional[str], str, bool]] = []

    for repo_info in repos:
        repo_slug = repo_info.get("name") or repo_info.get("slug")
        if not repo_slug:
            continue

        # Only check workspace repos against Bitbucket; additional cross-workspace
        # repos use the same API call against the configured workspace, which won't
        # find them — so we check the workspace slug and skip non-main-workspace
        # repos (they're not exposed by the main-workspace branches endpoint).
        ws_slug = (repo_info.get("workspace") or {}).get("slug")
        if ws_slug and ws_slug != main_workspace:
            logger.debug(f"Skipping {repo_slug}: workspace '{ws_slug}' != '{main_workspace}'")
            continue

        active = bitbucket.get_most_active_branch(repo_slug, days=ACTIVITY_DAYS)
        if not active:
            continue

        branch_name = active["name"]
        repo_path = repos_dir / repo_slug

        if not repo_path.exists() or not (repo_path / ".git").exists():
            logger.info(f"{repo_slug}: active branch '{branch_name}' but repo not cloned locally; skipping")
            results.append((repo_slug, branch_name, "Not cloned locally", False))
            continue

        ok, msg = _checkout_branch(repo_path, branch_name)
        log_fn = logger.info if ok else logger.warning
        log_fn(f"{repo_slug} -> {branch_name}: {msg}")
        results.append((repo_slug, branch_name, msg, ok))

    # Print a final summary
    print("")
    print(f"=== Checkout Active Branches — last {ACTIVITY_DAYS} days ===")
    if not results:
        print("No repos with activity in the window.")
        return

    switched = sum(1 for _, _, _, ok in results if ok)
    print(f"Active repos: {len(results)} | Switched/Verified: {switched}")
    print("")
    for repo_slug, branch, msg, ok in results:
        status = "OK" if ok else "SKIP"
        print(f"  [{status}] {repo_slug:40s} -> {branch or '?':30s} {msg}")


if __name__ == "__main__":
    try:
        run_checkout_active_branches()
    except KeyboardInterrupt:
        logger.info("Interrupted by user")
        sys.exit(1)
    except Exception as e:
        logger.exception(f"Fatal error: {e}")
        sys.exit(1)
