use anyhow;
use kodegen_mcp_tool::{McpError, Tool, ToolExecutionContext, ToolResponse};
use kodegen_mcp_schema::github::{CreateBranchArgs, CreateBranchPromptArgs, GITHUB_CREATE_BRANCH};
use rmcp::model::{PromptArgument, PromptMessage, PromptMessageContent, PromptMessageRole};

use crate::GitHubClient;

/// Tool for creating a new branch
pub struct CreateBranchTool;

impl Tool for CreateBranchTool {
    type Args = CreateBranchArgs;
    type PromptArgs = CreateBranchPromptArgs;

    fn name() -> &'static str {
        GITHUB_CREATE_BRANCH
    }

    fn description() -> &'static str {
        "Create a new branch from a commit SHA"
    }

    fn read_only() -> bool {
        false
    }

    fn destructive() -> bool {
        false
    }

    fn idempotent() -> bool {
        false
    }

    fn open_world() -> bool {
        true
    }

    async fn execute(&self, args: Self::Args, _ctx: ToolExecutionContext) 
        -> Result<ToolResponse<<Self::Args as kodegen_mcp_schema::ToolArgs>::Output>, McpError> 
    {
        let token = std::env::var("GITHUB_TOKEN").map_err(|_| {
            McpError::Other(anyhow::anyhow!("GITHUB_TOKEN environment variable not set"))
        })?;

        let client = GitHubClient::builder()
            .personal_token(token)
            .build()
            .map_err(|e| McpError::Other(anyhow::anyhow!("Failed to create GitHub client: {e}")))?;

        let task_result = client
            .create_branch(args.owner.clone(), args.repo.clone(), args.branch_name.clone(), args.sha.clone())
            .await;

        let api_result =
            task_result.map_err(|e| McpError::Other(anyhow::anyhow!("Task channel error: {e}")))?;

        let reference =
            api_result.map_err(|e| McpError::Other(anyhow::anyhow!("GitHub API error: {e}")))?;

        // Extract SHA from Object enum
        let sha = match &reference.object {
            octocrab::models::repos::Object::Commit { sha, .. } => sha.clone(),
            octocrab::models::repos::Object::Tag { sha, .. } => sha.clone(),
            _ => return Err(McpError::Other(anyhow::anyhow!("Unexpected object type"))),
        };

        let output = kodegen_mcp_schema::github::GitHubCreateBranchOutput {
            success: true,
            owner: args.owner.clone(),
            repo: args.repo.clone(),
            branch_name: args.branch_name.clone(),
            sha: sha.clone(),
            message: format!("Branch '{}' created from {}", args.branch_name, args.sha),
        };

        let display = format!(
            "✅ Branch Created\n\n\
             Repository: {}/{}\n\
             Branch: {}\n\
             From: {}\n\
             SHA: {}",
            output.owner,
            output.repo,
            output.branch_name,
            args.sha,
            output.sha
        );

        Ok(ToolResponse::new(display, output))
    }

    async fn prompt(&self, _args: Self::PromptArgs) -> Result<Vec<PromptMessage>, McpError> {
        Ok(vec![PromptMessage {
            role: PromptMessageRole::User,
            content: PromptMessageContent::text(
                r#"# GitHub Create Branch Examples

## Create Branch from Specific SHA
To create a new branch from a specific commit:

```json
{
  "owner": "octocat",
  "repo": "hello-world",
  "branch_name": "feature/new-feature",
  "sha": "abc123def456789abc123def456789abc123def4"
}
```

## Create Branch from Latest Commit

### Step 1: Get the latest commit SHA
First, use `list_commits` to get recent commits:

```json
{
  "owner": "octocat",
  "repo": "hello-world",
  "sha": "main",
  "per_page": 1
}
```

### Step 2: Create branch from that SHA
Use the SHA from the response:

```json
{
  "owner": "octocat",
  "repo": "hello-world",
  "branch_name": "feature/from-main",
  "sha": "abc123def456"
}
```

## How to Get SHA from Commit History

### Method 1: List Commits
Use `list_commits` to see commit history:
- Returns array of commits with SHA, message, author, date
- Can filter by branch, author, date range, or file path
- Most recent commits appear first

### Method 2: Get Specific Commit
Use `get_commit` if you know the commit identifier:
- Provides detailed information including full SHA
- Shows files changed and diff stats

### Method 3: From Branch Info
Use `list_branches` to get branch tip SHA:
- Each branch object includes latest commit SHA
- Useful for creating branches from other branches

## Branch Naming Best Practices

**Feature Branches:**
- `feature/user-authentication`
- `feature/payment-integration`

**Bug Fixes:**
- `bugfix/login-error`
- `fix/memory-leak`

**Hotfixes:**
- `hotfix/security-patch`
- `hotfix/critical-bug`

**Release Branches:**
- `release/v1.0.0`
- `release/2024-01`

## Common Workflows

### 1. Feature Development
```
1. Get main branch SHA
2. Create feature branch from main
3. Develop feature
4. Create pull request back to main
```

### 2. Release Preparation
```
1. Get develop branch SHA
2. Create release branch
3. Make final adjustments
4. Merge to main and tag
```

### 3. Hotfix
```
1. Get production tag SHA
2. Create hotfix branch
3. Fix critical issue
4. Merge to main and develop
```

## Important Notes

- **Branch Name Uniqueness**: Cannot create a branch with an existing name
- **SHA Format**: Must be a valid 40-character commit SHA
- **Permissions**: Requires write access to the repository
- **Protected Branches**: Cannot be created via API if name matches protection rules
- **Immediate Availability**: Branch is available immediately after creation

## Response Information

The response includes:
- **ref**: Full reference name (refs/heads/branch-name)
- **node_id**: GitHub's internal node identifier
- **url**: API URL for the reference
- **object**: Object containing the SHA and type (commit)

## Troubleshooting

- **"Reference already exists"**: Branch name is already taken
- **"Object does not exist"**: SHA is invalid or not found
- **"Not Found"**: Repository doesn't exist or no write access
"#,
            ),
        }])
    }

    fn prompt_arguments() -> Vec<PromptArgument> {
        vec![PromptArgument {
            name: "focus".to_string(),
            title: None,
            description: Some(
                "Customize teaching examples by focus area: \
                 'basic' for simple feature branch creation, \
                 'advanced' for Git workflows and release management, \
                 'troubleshooting' for error handling and edge cases".to_string()
            ),
            required: Some(false),
        }]
    }
}
