"""
Unified MCP tools for Git Integration (Phase 3B consolidation).

Consolidates 12 individual git tools into 2 action-dispatched tools:
- git(action, ...) — 8 actions for git ops + workflow generation
- github_pr(action, ...) — 4 actions for PR management

Original tool names are preserved as deprecation wrappers in mcp_tools.py.
"""

import logging
from pathlib import Path
from typing import Any, Dict, List, Optional

from .types import (
    BranchStrategy,
    DbtCIConfig,
    DbtCommand,
    GitConfig,
    GitProvider,
)

logger = logging.getLogger(__name__)

# ============================================================================
# Lazy singletons
# ============================================================================

_git_client = None
_github_client = None
_workflow_gen = None
_config: Dict[str, GitConfig] = {}


def _ensure_git_client():
    global _git_client
    if _git_client is None:
        from .git_client import GitClient
        _git_client = GitClient()
    return _git_client


def _ensure_github_client():
    global _github_client
    if _github_client is None:
        from .github_client import GitHubClient
        _github_client = GitHubClient()
    return _github_client


def _ensure_workflow_gen():
    global _workflow_gen
    if _workflow_gen is None:
        from .workflow_generator import WorkflowGenerator
        _workflow_gen = WorkflowGenerator()
    return _workflow_gen


# ============================================================================
# git action handlers
# ============================================================================

def _git_configure(settings, **kwargs) -> Dict[str, Any]:
    repo_path = kwargs.get("repo_path")
    if not repo_path:
        return {"error": "repo_path is required for 'configure' action"}

    branch_strategy = kwargs.get("branch_strategy", "feature")
    try:
        strategy = BranchStrategy(branch_strategy.lower())
    except ValueError:
        strategy = BranchStrategy.FEATURE

    config = GitConfig(
        repo_path=repo_path,
        remote_url=kwargs.get("remote_url"),
        username=kwargs.get("username"),
        email=kwargs.get("email"),
        token=kwargs.get("token"),
        default_branch=kwargs.get("default_branch", "main"),
        branch_strategy=strategy,
        auto_commit=kwargs.get("auto_commit", False),
        commit_prefix=kwargs.get("commit_prefix", "[DataBridge]"),
    )

    _config["default"] = config

    git_client = _ensure_git_client()
    github_client = _ensure_github_client()

    git_client.config = config
    git_client.set_repo_path(repo_path)

    token = kwargs.get("token")
    remote_url = kwargs.get("remote_url")
    if token and remote_url:
        github_client.configure(token=token, remote_url=remote_url)

    return {
        "success": True,
        "config": config.to_dict(),
        "git_configured": True,
        "github_configured": github_client.is_configured,
        "message": f"Configured git for {repo_path}",
    }


def _git_status(settings, **kwargs) -> Dict[str, Any]:
    git_client = _ensure_git_client()
    repo_path = kwargs.get("repo_path")
    if repo_path:
        git_client.set_repo_path(repo_path)

    status = git_client.status()
    if "error" in status:
        return {"success": False, "error": status["error"]}
    return {"success": True, **status}


def _git_commit(settings, **kwargs) -> Dict[str, Any]:
    message = kwargs.get("message")
    if not message:
        return {"error": "message is required for 'commit' action"}

    git_client = _ensure_git_client()
    repo_path = kwargs.get("repo_path")
    if repo_path:
        git_client.set_repo_path(repo_path)

    files = kwargs.get("files")
    file_list = [f.strip() for f in files.split(",")] if files else None

    result = git_client.commit(
        message=message, files=file_list, all_files=kwargs.get("all_files", False),
    )
    return result.to_dict()


def _git_branch(settings, **kwargs) -> Dict[str, Any]:
    branch_name = kwargs.get("branch_name")
    if not branch_name:
        return {"error": "branch_name is required for 'branch' action"}

    git_client = _ensure_git_client()
    repo_path = kwargs.get("repo_path")
    if repo_path:
        git_client.set_repo_path(repo_path)

    result = git_client.create_branch(
        name=branch_name,
        checkout=kwargs.get("checkout", True),
        from_branch=kwargs.get("from_branch"),
    )
    return result.to_dict()


def _git_push(settings, **kwargs) -> Dict[str, Any]:
    git_client = _ensure_git_client()
    repo_path = kwargs.get("repo_path")
    if repo_path:
        git_client.set_repo_path(repo_path)

    result = git_client.push(
        remote=kwargs.get("remote", "origin"),
        branch=kwargs.get("branch"),
        set_upstream=kwargs.get("set_upstream", True),
    )
    return result.to_dict()


def _git_generate_dbt_workflow(settings, **kwargs) -> Dict[str, Any]:
    project_name = kwargs.get("project_name")
    if not project_name:
        return {"error": "project_name is required for 'generate_dbt_workflow'"}

    workflow_gen = _ensure_workflow_gen()
    run_commands = kwargs.get("run_commands", "build,test")

    commands = []
    for cmd in run_commands.split(","):
        cmd = cmd.strip().lower()
        try:
            if cmd == "docs generate":
                commands.append(DbtCommand.DOCS_GENERATE)
            else:
                commands.append(DbtCommand(cmd))
        except ValueError:
            pass

    environments = kwargs.get("environments", "dev,prod")
    config = DbtCIConfig(
        project_name=project_name,
        dbt_version=kwargs.get("dbt_version", "1.7.0"),
        database_type=kwargs.get("database_type", "snowflake"),
        run_commands=commands,
        environments=[e.strip() for e in environments.split(",")],
    )

    workflow = workflow_gen.generate_dbt_ci_workflow(config)
    yaml_content = workflow.to_yaml()

    output_path = kwargs.get("output_path")
    if output_path:
        output_file = Path(output_path)
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_text(yaml_content)

    return {
        "success": True,
        "workflow_name": workflow.name, "filename": workflow.filename,
        "job_count": len(workflow.jobs), "jobs": list(workflow.jobs.keys()),
        "output_path": output_path,
        "yaml": yaml_content[:2000] + "..." if len(yaml_content) > 2000 else yaml_content,
    }


def _git_generate_deploy_workflow(settings, **kwargs) -> Dict[str, Any]:
    project_name = kwargs.get("project_name")
    if not project_name:
        return {"error": "project_name is required for 'generate_deploy_workflow'"}

    workflow_gen = _ensure_workflow_gen()
    environments = kwargs.get("environments", "dev,prod")
    env_list = [e.strip() for e in environments.split(",")]

    workflow = workflow_gen.generate_databridge_deploy_workflow(
        project_name=project_name, environments=env_list,
    )
    yaml_content = workflow.to_yaml()

    output_path = kwargs.get("output_path")
    if output_path:
        output_file = Path(output_path)
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_text(yaml_content)

    return {
        "success": True,
        "workflow_name": workflow.name, "filename": workflow.filename,
        "environments": env_list,
        "job_count": len(workflow.jobs), "jobs": list(workflow.jobs.keys()),
        "output_path": output_path,
        "yaml": yaml_content[:2000] + "..." if len(yaml_content) > 2000 else yaml_content,
    }


def _git_generate_mart_workflow(settings, **kwargs) -> Dict[str, Any]:
    project_name = kwargs.get("project_name")
    hierarchy_table = kwargs.get("hierarchy_table")
    mapping_table = kwargs.get("mapping_table")
    if not all([project_name, hierarchy_table, mapping_table]):
        return {"error": "project_name, hierarchy_table, mapping_table are required for 'generate_mart_workflow'"}

    workflow_gen = _ensure_workflow_gen()
    workflow = workflow_gen.generate_mart_factory_workflow(
        project_name=project_name, hierarchy_table=hierarchy_table, mapping_table=mapping_table,
    )
    yaml_content = workflow.to_yaml()

    output_path = kwargs.get("output_path")
    if output_path:
        output_file = Path(output_path)
        output_file.parent.mkdir(parents=True, exist_ok=True)
        output_file.write_text(yaml_content)

    return {
        "success": True,
        "workflow_name": workflow.name, "filename": workflow.filename,
        "hierarchy_table": hierarchy_table, "mapping_table": mapping_table,
        "job_count": len(workflow.jobs), "jobs": list(workflow.jobs.keys()),
        "output_path": output_path,
        "yaml": yaml_content[:2000] + "..." if len(yaml_content) > 2000 else yaml_content,
    }


# ============================================================================
# github_pr action handlers
# ============================================================================

def _pr_create(settings, **kwargs) -> Dict[str, Any]:
    github_client = _ensure_github_client()
    if not github_client.is_configured:
        return {"success": False, "error": "GitHub not configured. Call git(action='configure', ...) with token and remote_url first."}

    title = kwargs.get("title")
    body = kwargs.get("body")
    head_branch = kwargs.get("head_branch")
    if not all([title, body, head_branch]):
        return {"error": "title, body, head_branch are required for 'create' action"}

    reviewers = kwargs.get("reviewers")
    reviewer_list = [r.strip() for r in reviewers.split(",")] if reviewers else None

    labels = kwargs.get("labels")
    label_list = [l.strip() for l in labels.split(",")] if labels else None

    result = github_client.create_pull_request(
        title=title, body=body, head=head_branch,
        base=kwargs.get("base_branch"), draft=kwargs.get("draft", False),
        reviewers=reviewer_list, labels=label_list,
    )
    return result.to_dict()


def _pr_status(settings, **kwargs) -> Dict[str, Any]:
    github_client = _ensure_github_client()
    if not github_client.is_configured:
        return {"success": False, "error": "GitHub not configured"}

    pr_number = kwargs.get("pr_number")
    if not pr_number:
        return {"error": "pr_number is required for 'status' action"}

    status = github_client.get_pr_status(pr_number)
    if "error" in status:
        return {"success": False, "error": status["error"]}
    return {"success": True, **status}


def _pr_list(settings, **kwargs) -> Dict[str, Any]:
    github_client = _ensure_github_client()
    if not github_client.is_configured:
        return {"success": False, "error": "GitHub not configured"}

    prs = github_client.list_pull_requests(
        state=kwargs.get("state", "open"),
        head=kwargs.get("head_branch"),
        base=kwargs.get("base_branch"),
    )
    return {"success": True, "count": len(prs), "pull_requests": [pr.to_dict() for pr in prs]}


def _pr_merge(settings, **kwargs) -> Dict[str, Any]:
    github_client = _ensure_github_client()
    if not github_client.is_configured:
        return {"success": False, "error": "GitHub not configured"}

    pr_number = kwargs.get("pr_number")
    if not pr_number:
        return {"error": "pr_number is required for 'merge' action"}

    result = github_client.merge_pull_request(
        pr_number=pr_number,
        merge_method=kwargs.get("merge_method", "squash"),
        commit_message=kwargs.get("commit_message"),
    )
    return result.to_dict()


# ============================================================================
# Action dispatch dictionaries
# ============================================================================

_GIT_ACTIONS = {
    "configure": _git_configure,
    "status": _git_status,
    "commit": _git_commit,
    "branch": _git_branch,
    "push": _git_push,
    "generate_dbt_workflow": _git_generate_dbt_workflow,
    "generate_deploy_workflow": _git_generate_deploy_workflow,
    "generate_mart_workflow": _git_generate_mart_workflow,
}

_PR_ACTIONS = {
    "create": _pr_create,
    "status": _pr_status,
    "list": _pr_list,
    "merge": _pr_merge,
}


# ============================================================================
# Unified dispatch functions
# ============================================================================

def dispatch_git(settings, action: str, **kwargs) -> Dict[str, Any]:
    """Dispatch a git action."""
    handler = _GIT_ACTIONS.get(action)
    if not handler:
        return {
            "error": f"Unknown action: '{action}'",
            "valid_actions": sorted(_GIT_ACTIONS.keys()),
        }
    try:
        return handler(settings, **kwargs)
    except Exception as e:
        logger.error(f"git({action}) failed: {e}")
        return {"error": f"git({action}) failed: {e}"}


def dispatch_github_pr(settings, action: str, **kwargs) -> Dict[str, Any]:
    """Dispatch a github_pr action."""
    handler = _PR_ACTIONS.get(action)
    if not handler:
        return {
            "error": f"Unknown action: '{action}'",
            "valid_actions": sorted(_PR_ACTIONS.keys()),
        }
    try:
        return handler(settings, **kwargs)
    except Exception as e:
        logger.error(f"github_pr({action}) failed: {e}")
        return {"error": f"github_pr({action}) failed: {e}"}


# ============================================================================
# Registration
# ============================================================================

def register_unified_git_tools(mcp, settings):
    """Register the 2 unified git MCP tools."""

    @mcp.tool()
    def git(
        action: str,
        repo_path: Optional[str] = None,
        remote_url: Optional[str] = None,
        username: Optional[str] = None,
        email: Optional[str] = None,
        token: Optional[str] = None,
        default_branch: str = "main",
        branch_strategy: str = "feature",
        auto_commit: bool = False,
        commit_prefix: str = "[DataBridge]",
        message: Optional[str] = None,
        files: Optional[str] = None,
        all_files: bool = False,
        branch_name: Optional[str] = None,
        checkout: bool = True,
        from_branch: Optional[str] = None,
        remote: str = "origin",
        branch: Optional[str] = None,
        set_upstream: bool = True,
        project_name: Optional[str] = None,
        dbt_version: str = "1.7.0",
        database_type: str = "snowflake",
        run_commands: str = "build,test",
        environments: str = "dev,prod",
        output_path: Optional[str] = None,
        hierarchy_table: Optional[str] = None,
        mapping_table: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Unified git operations and workflow generation tool. Replaces 8 individual tools.

        Actions:
        - configure: Configure git integration (requires repo_path)
        - status: Get repository status
        - commit: Commit changes (requires message)
        - branch: Create a branch (requires branch_name)
        - push: Push to remote
        - generate_dbt_workflow: Generate dbt CI/CD workflow (requires project_name)
        - generate_deploy_workflow: Generate deploy workflow (requires project_name)
        - generate_mart_workflow: Generate mart factory workflow (requires project_name, hierarchy_table, mapping_table)

        Returns:
            Action-specific result dict
        """
        return dispatch_git(settings, action, **{
            k: v for k, v in {
                "repo_path": repo_path, "remote_url": remote_url,
                "username": username, "email": email, "token": token,
                "default_branch": default_branch, "branch_strategy": branch_strategy,
                "auto_commit": auto_commit, "commit_prefix": commit_prefix,
                "message": message, "files": files, "all_files": all_files,
                "branch_name": branch_name, "checkout": checkout, "from_branch": from_branch,
                "remote": remote, "branch": branch, "set_upstream": set_upstream,
                "project_name": project_name, "dbt_version": dbt_version,
                "database_type": database_type, "run_commands": run_commands,
                "environments": environments, "output_path": output_path,
                "hierarchy_table": hierarchy_table, "mapping_table": mapping_table,
            }.items() if v is not None
        })

    @mcp.tool()
    def github_pr(
        action: str,
        title: Optional[str] = None,
        body: Optional[str] = None,
        head_branch: Optional[str] = None,
        base_branch: Optional[str] = None,
        draft: bool = False,
        reviewers: Optional[str] = None,
        labels: Optional[str] = None,
        pr_number: Optional[int] = None,
        state: str = "open",
        merge_method: str = "squash",
        commit_message: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Unified GitHub pull request management tool. Replaces 4 individual tools.

        Actions:
        - create: Create a PR (requires title, body, head_branch)
        - status: Get PR status (requires pr_number)
        - list: List PRs (optional state, head_branch, base_branch filters)
        - merge: Merge a PR (requires pr_number)

        Args:
            action: The action to perform (create, status, list, merge)
            title: PR title (for create)
            body: PR description (for create)
            head_branch: Source branch (for create/list filter)
            base_branch: Target branch (for create/list filter)
            draft: Create as draft (for create)
            reviewers: Comma-separated reviewers (for create)
            labels: Comma-separated labels (for create)
            pr_number: PR number (for status/merge)
            state: PR state filter (for list: open, closed, all)
            merge_method: Merge method (for merge: merge, squash, rebase)
            commit_message: Custom commit message (for merge)

        Returns:
            Action-specific result dict
        """
        return dispatch_github_pr(settings, action, **{
            k: v for k, v in {
                "title": title, "body": body, "head_branch": head_branch,
                "base_branch": base_branch, "draft": draft,
                "reviewers": reviewers, "labels": labels,
                "pr_number": pr_number, "state": state,
                "merge_method": merge_method, "commit_message": commit_message,
            }.items() if v is not None
        })

    logger.info("Registered 2 unified git tools: git, github_pr")
    return ["git", "github_pr"]
