package app

import (
	"context"
	"errors"
	"fmt"
	"strings"

	mysql "github.com/go-sql-driver/mysql"

	"github.com/tidbcloud/AgentTeam/internal/store/agent"
)

func buildAgentRoleBindingSummary(bindingKind, roleID, roleVersionID, sourcePresetRoleID, sourcePresetVersionID, activeDefinitionPath, realizationID string) *agent.AgentRoleBindingSummary {
	if strings.TrimSpace(bindingKind) == "" &&
		strings.TrimSpace(roleID) == "" &&
		strings.TrimSpace(roleVersionID) == "" &&
		strings.TrimSpace(sourcePresetRoleID) == "" &&
		strings.TrimSpace(sourcePresetVersionID) == "" &&
		strings.TrimSpace(activeDefinitionPath) == "" &&
		strings.TrimSpace(realizationID) == "" {
		return nil
	}
	return &agent.AgentRoleBindingSummary{
		BindingKind:           strings.TrimSpace(bindingKind),
		RoleID:                strings.TrimSpace(roleID),
		RoleVersionID:         strings.TrimSpace(roleVersionID),
		SourcePresetRoleID:    strings.TrimSpace(sourcePresetRoleID),
		SourcePresetVersionID: strings.TrimSpace(sourcePresetVersionID),
		ActiveDefinitionPath:  strings.TrimSpace(activeDefinitionPath),
		RealizationID:         strings.TrimSpace(realizationID),
	}
}

func isMissingAgentRoleBindingsTable(err error) bool {
	if err == nil {
		return false
	}
	var mysqlErr *mysql.MySQLError
	if errors.As(err, &mysqlErr) && mysqlErr.Number == 1146 {
		return true
	}
	message := strings.ToLower(err.Error())
	return strings.Contains(message, "agent_role_bindings") && strings.Contains(message, "doesn't exist")
}

func (store *Store) loadAgentRoleBindingSummaries(ctx context.Context, workspaceID string, agentIDs []string) (map[string]*agent.AgentRoleBindingSummary, error) {
	trimmedWorkspaceID := strings.TrimSpace(workspaceID)
	if trimmedWorkspaceID == "" || len(agentIDs) == 0 {
		return map[string]*agent.AgentRoleBindingSummary{}, nil
	}
	trimmedAgentIDs := make([]string, 0, len(agentIDs))
	seen := make(map[string]struct{}, len(agentIDs))
	for _, agentID := range agentIDs {
		trimmed := strings.TrimSpace(agentID)
		if trimmed == "" {
			continue
		}
		if _, ok := seen[trimmed]; ok {
			continue
		}
		seen[trimmed] = struct{}{}
		trimmedAgentIDs = append(trimmedAgentIDs, trimmed)
	}
	if len(trimmedAgentIDs) == 0 {
		return map[string]*agent.AgentRoleBindingSummary{}, nil
	}

	placeholders := make([]string, 0, len(trimmedAgentIDs))
	args := make([]any, 0, 1+len(trimmedAgentIDs))
	args = append(args, trimmedWorkspaceID)
	for i, agentID := range trimmedAgentIDs {
		placeholders = append(placeholders, fmt.Sprintf("$%d", i+2))
		args = append(args, agentID)
	}
	rows, err := store.db.Query(ctx, fmt.Sprintf(`
SELECT agent_id, binding_kind, role_id, role_version_id, source_preset_role_id,
       source_preset_version_id, active_definition_path, realization_id
FROM agent_role_bindings
WHERE workspace_id = $1 AND agent_id IN (%s)
`, strings.Join(placeholders, ", ")), args...)
	if err != nil {
		if isMissingAgentRoleBindingsTable(err) {
			return map[string]*agent.AgentRoleBindingSummary{}, nil
		}
		return nil, fmt.Errorf("load agent role bindings: %w", err)
	}
	defer rows.Close()

	bindings := make(map[string]*agent.AgentRoleBindingSummary, len(trimmedAgentIDs))
	for rows.Next() {
		var agentID string
		var bindingKind string
		var roleID string
		var roleVersionID string
		var sourcePresetRoleID string
		var sourcePresetVersionID string
		var activeDefinitionPath string
		var realizationID string
		if err := rows.Scan(&agentID, &bindingKind, &roleID, &roleVersionID, &sourcePresetRoleID, &sourcePresetVersionID, &activeDefinitionPath, &realizationID); err != nil {
			return nil, fmt.Errorf("scan agent role binding: %w", err)
		}
		bindings[strings.TrimSpace(agentID)] = buildAgentRoleBindingSummary(
			bindingKind,
			roleID,
			roleVersionID,
			sourcePresetRoleID,
			sourcePresetVersionID,
			activeDefinitionPath,
			realizationID,
		)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate agent role bindings: %w", err)
	}
	return bindings, nil
}
