use crate::{
    ContentBlock,
    agent::Agent,
    error::RuntimeError,
    team::{TeamProtocolStatus, TeamRequestDirection},
    tool::ToolCall,
};

use super::schema::{
    TeamBroadcastInput, TeamListRequestsInput, TeamRequestInput, TeamRespondInput, TeamSendInput,
    TeamSpawnInput,
};

pub(super) async fn execute_team_spawn(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamSpawnInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_spawn input: {error}"),
                is_error: true,
            };
        }
    };

    match agent
        .spawn_teammate(input.name, input.role, input.prompt)
        .await
    {
        Ok(teammate) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!(
                "Spawned persistent teammate '{}' (role: {}, status: {})",
                teammate.name, teammate.role, teammate.status
            ),
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to spawn teammate: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_send(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamSendInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_send input: {error}"),
                is_error: true,
            };
        }
    };

    match agent.send_team_message(&input.to, input.content) {
        Ok(dispatch) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Sent message to '{}'", dispatch.teammate),
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to send team message: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_read_inbox(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    match agent.read_team_inbox().and_then(|messages| {
        serde_json::to_string_pretty(&messages).map_err(RuntimeError::FailedToSerializeTeam)
    }) {
        Ok(content) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content,
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to read team inbox: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_broadcast(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamBroadcastInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid broadcast input: {error}"),
                is_error: true,
            };
        }
    };

    match agent.broadcast_team_message(input.content) {
        Ok(dispatches) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!(
                "Broadcast message sent to {} recipient(s): {}",
                dispatches.len(),
                dispatches
                    .into_iter()
                    .map(|dispatch| dispatch.teammate)
                    .collect::<Vec<_>>()
                    .join(", ")
            ),
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to broadcast team message: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_request(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamRequestInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_request input: {error}"),
                is_error: true,
            };
        }
    };

    match agent.request_team_protocol(&input.to, input.protocol, input.content) {
        Ok(request) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!(
                "Created team request '{}' for '{}' using protocol '{}'",
                request.request_id, request.to, request.protocol
            ),
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to create team request: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_respond(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamRespondInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_respond input: {error}"),
                is_error: true,
            };
        }
    };

    match agent.respond_team_protocol(&input.request_id, input.approve, input.reason) {
        Ok(request) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!(
                "{} team request '{}' ({})",
                if input.approve {
                    "Approved"
                } else {
                    "Rejected"
                },
                request.request_id,
                request.protocol
            ),
            is_error: false,
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to respond to team request: {error}"),
            is_error: true,
        },
    }
}

pub(super) fn execute_team_list_requests(agent: &mut Agent, call: ToolCall) -> ContentBlock {
    let input = match serde_json::from_value::<TeamListRequestsInput>(call.input) {
        Ok(input) => input,
        Err(error) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_list_requests input: {error}"),
                is_error: true,
            };
        }
    };

    let status = match input.status.as_deref() {
        Some("pending") => Some(TeamProtocolStatus::Pending),
        Some("approved") => Some(TeamProtocolStatus::Approved),
        Some("rejected") => Some(TeamProtocolStatus::Rejected),
        Some(value) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_list_requests status '{value}'"),
                is_error: true,
            };
        }
        None => None,
    };

    let direction = match input.direction.as_deref() {
        Some("inbound") => TeamRequestDirection::Inbound,
        Some("outbound") => TeamRequestDirection::Outbound,
        Some("any") | None => TeamRequestDirection::Any,
        Some(value) => {
            return ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Invalid team_list_requests direction '{value}'"),
                is_error: true,
            };
        }
    };

    match agent.list_team_protocol_requests(status, input.protocol, input.counterparty, direction) {
        Ok(requests) => match serde_json::to_string_pretty(&requests) {
            Ok(content) => ContentBlock::ToolResult {
                tool_use_id: call.id,
                content,
                is_error: false,
            },
            Err(error) => ContentBlock::ToolResult {
                tool_use_id: call.id,
                content: format!("Failed to serialize team requests: {error}"),
                is_error: true,
            },
        },
        Err(error) => ContentBlock::ToolResult {
            tool_use_id: call.id,
            content: format!("Failed to list team requests: {error}"),
            is_error: true,
        },
    }
}
