package tools

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/vektah/gqlparser/v2"
	"github.com/vektah/gqlparser/v2/ast"
	"gogs.dmsc.dev/arp/graph"
	"gogs.dmsc.dev/arp/graph/model"
)

// Mutate executes a GraphQL mutation
func Mutate(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, args map[string]interface{}) (CallToolResult, error) {
	mutationStr, ok := args["mutation"].(string)
	if !ok {
		return CallToolResult{
			Content: []ContentBlock{
				{Type: "text", Text: "Missing required 'mutation' parameter"},
			},
			IsError: true,
		}, nil
	}

	// Parse variables
	variables := make(map[string]interface{})
	if v, ok := args["variables"].(map[string]interface{}); ok {
		variables = v
	}

	// Parse the mutation
	mutationDoc, err := gqlparser.LoadQuery(schema, mutationStr)
	if err != nil {
		return CallToolResult{
			Content: []ContentBlock{
				{Type: "text", Text: fmt.Sprintf("Mutation parse error: %v", err)},
			},
			IsError: true,
		}, nil
	}

	// Execute each operation
	var results []interface{}
	for _, op := range mutationDoc.Operations {
		if op.Operation != ast.Mutation {
			continue
		}

		result, errMsg := executeMutation(ctx, resolver, schema, mutationDoc, op, variables)
		if errMsg != "" {
			return CallToolResult{
				Content: []ContentBlock{
					{Type: "text", Text: errMsg},
				},
				IsError: true,
			}, nil
		}
		results = append(results, result)
	}

	// Format response
	var responseText string
	if len(results) == 1 {
		bytes, _ := json.MarshalIndent(results[0], "", "  ")
		responseText = string(bytes)
	} else {
		bytes, _ := json.MarshalIndent(results, "", "  ")
		responseText = string(bytes)
	}

	return CallToolResult{
		Content: []ContentBlock{
			{Type: "text", Text: responseText},
		},
	}, nil
}

func executeMutation(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, doc *ast.QueryDocument, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, string) {
	result := make(map[string]interface{})

	for _, sel := range op.SelectionSet {
		field, ok := sel.(*ast.Field)
		if !ok {
			continue
		}

		value, errMsg := resolveMutationField(ctx, resolver, schema, field, variables)
		if errMsg != "" {
			return nil, errMsg
		}
		result[field.Alias] = value
	}

	return result, ""
}

func resolveMutationField(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, field *ast.Field, variables map[string]interface{}) (interface{}, string) {
	// Get field arguments
	args := make(map[string]interface{})
	for _, arg := range field.Arguments {
		value, err := arg.Value.Value(variables)
		if err != nil {
			return nil, fmt.Sprintf("failed to evaluate argument %s: %v", arg.Name, err)
		}
		args[arg.Name] = value
	}

	// Resolve based on field name
	switch field.Name {
	// User mutations
	case "createUser":
		input := parseNewUser(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createUser"
		}
		user, err := resolver.Mutation().CreateUser(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return user, ""

	case "updateUser":
		id, _ := args["id"].(string)
		input := parseUpdateUserInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateUser"
		}
		user, err := resolver.Mutation().UpdateUser(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return user, ""

	case "deleteUser":
		id, _ := args["id"].(string)
		user, err := resolver.Mutation().DeleteUser(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return user, ""

	// Note mutations
	case "createNote":
		input := parseNewNote(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createNote"
		}
		note, err := resolver.Mutation().CreateNote(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return note, ""

	case "updateNote":
		id, _ := args["id"].(string)
		input := parseUpdateNoteInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateNote"
		}
		note, err := resolver.Mutation().UpdateNote(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return note, ""

	case "deleteNote":
		id, _ := args["id"].(string)
		note, err := resolver.Mutation().DeleteNote(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return note, ""

	// Role mutations
	case "createRole":
		input := parseNewRole(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createRole"
		}
		role, err := resolver.Mutation().CreateRole(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return role, ""

	case "updateRole":
		id, _ := args["id"].(string)
		input := parseUpdateRoleInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateRole"
		}
		role, err := resolver.Mutation().UpdateRole(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return role, ""

	case "deleteRole":
		id, _ := args["id"].(string)
		role, err := resolver.Mutation().DeleteRole(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return role, ""

	// Permission mutations
	case "createPermission":
		input := parseNewPermission(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createPermission"
		}
		perm, err := resolver.Mutation().CreatePermission(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return perm, ""

	case "updatePermission":
		id, _ := args["id"].(string)
		input := parseUpdatePermissionInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updatePermission"
		}
		perm, err := resolver.Mutation().UpdatePermission(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return perm, ""

	case "deletePermission":
		id, _ := args["id"].(string)
		perm, err := resolver.Mutation().DeletePermission(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return perm, ""

	// Service mutations
	case "createService":
		input := parseNewService(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createService"
		}
		service, err := resolver.Mutation().CreateService(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return service, ""

	case "updateService":
		id, _ := args["id"].(string)
		input := parseUpdateServiceInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateService"
		}
		service, err := resolver.Mutation().UpdateService(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return service, ""

	case "deleteService":
		id, _ := args["id"].(string)
		service, err := resolver.Mutation().DeleteService(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return service, ""

	// Task mutations
	case "createTask":
		input := parseNewTask(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createTask"
		}
		task, err := resolver.Mutation().CreateTask(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return task, ""

	case "updateTask":
		id, _ := args["id"].(string)
		input := parseUpdateTaskInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateTask"
		}
		task, err := resolver.Mutation().UpdateTask(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return task, ""

	case "deleteTask":
		id, _ := args["id"].(string)
		task, err := resolver.Mutation().DeleteTask(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return task, ""

	// TaskStatus mutations
	case "createTaskStatus":
		input := parseNewTaskStatus(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createTaskStatus"
		}
		status, err := resolver.Mutation().CreateTaskStatus(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return status, ""

	case "updateTaskStatus":
		id, _ := args["id"].(string)
		input := parseUpdateTaskStatusInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateTaskStatus"
		}
		status, err := resolver.Mutation().UpdateTaskStatus(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return status, ""

	case "deleteTaskStatus":
		id, _ := args["id"].(string)
		status, err := resolver.Mutation().DeleteTaskStatus(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return status, ""

	// Message mutations
	case "createMessage":
		input := parseNewMessage(args["input"])
		if input == nil {
			return nil, "missing or invalid input for createMessage"
		}
		msg, err := resolver.Mutation().CreateMessage(ctx, *input)
		if err != nil {
			return nil, err.Error()
		}
		return msg, ""

	case "updateMessage":
		id, _ := args["id"].(string)
		input := parseUpdateMessageInput(args["input"])
		if input == nil {
			return nil, "missing or invalid input for updateMessage"
		}
		msg, err := resolver.Mutation().UpdateMessage(ctx, id, *input)
		if err != nil {
			return nil, err.Error()
		}
		return msg, ""

	case "deleteMessage":
		id, _ := args["id"].(string)
		msg, err := resolver.Mutation().DeleteMessage(ctx, id)
		if err != nil {
			return nil, err.Error()
		}
		return msg, ""

	default:
		return nil, fmt.Sprintf("unknown mutation: %s", field.Name)
	}
}

// Helper functions

func getString(m map[string]interface{}, key string) string {
	if v, ok := m[key]; ok {
		if s, ok := v.(string); ok {
			return s
		}
	}
	return ""
}

func parseStringSlice(v interface{}) []string {
	if v == nil {
		return nil
	}
	if arr, ok := v.([]interface{}); ok {
		result := make([]string, 0, len(arr))
		for _, item := range arr {
			if s, ok := item.(string); ok {
				result = append(result, s)
			}
		}
		return result
	}
	if arr, ok := v.([]string); ok {
		return arr
	}
	return nil
}

func parseStringPtr(v interface{}) *string {
	if v == nil {
		return nil
	}
	if s, ok := v.(string); ok {
		return &s
	}
	return nil
}

// Input parsing functions

func parseNewUser(v interface{}) *model.NewUser {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewUser{
		Email:    getString(m, "email"),
		Password: getString(m, "password"),
		Roles:    parseStringSlice(m["roles"]),
	}
}

func parseUpdateUserInput(v interface{}) *model.UpdateUserInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateUserInput{
		Email:    parseStringPtr(m["email"]),
		Password: parseStringPtr(m["password"]),
		Roles:    parseStringSlice(m["roles"]),
	}
}

func parseNewNote(v interface{}) *model.NewNote {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewNote{
		Title:     getString(m, "title"),
		Content:   getString(m, "content"),
		UserID:    getString(m, "userId"),
		ServiceID: getString(m, "serviceId"),
	}
}

func parseUpdateNoteInput(v interface{}) *model.UpdateNoteInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateNoteInput{
		Title:     parseStringPtr(m["title"]),
		Content:   parseStringPtr(m["content"]),
		UserID:    parseStringPtr(m["userId"]),
		ServiceID: parseStringPtr(m["serviceId"]),
	}
}

func parseNewRole(v interface{}) *model.NewRole {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewRole{
		Name:        getString(m, "name"),
		Description: getString(m, "description"),
		Permissions: parseStringSlice(m["permissions"]),
	}
}

func parseUpdateRoleInput(v interface{}) *model.UpdateRoleInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateRoleInput{
		Name:        parseStringPtr(m["name"]),
		Description: parseStringPtr(m["description"]),
		Permissions: parseStringSlice(m["permissions"]),
	}
}

func parseNewPermission(v interface{}) *model.NewPermission {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewPermission{
		Code:        getString(m, "code"),
		Description: getString(m, "description"),
	}
}

func parseUpdatePermissionInput(v interface{}) *model.UpdatePermissionInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdatePermissionInput{
		Code:        parseStringPtr(m["code"]),
		Description: parseStringPtr(m["description"]),
	}
}

func parseNewService(v interface{}) *model.NewService {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewService{
		Name:         getString(m, "name"),
		Description:  parseStringPtr(m["description"]),
		CreatedByID:  getString(m, "createdById"),
		Participants: parseStringSlice(m["participants"]),
	}
}

func parseUpdateServiceInput(v interface{}) *model.UpdateServiceInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateServiceInput{
		Name:         parseStringPtr(m["name"]),
		Description:  parseStringPtr(m["description"]),
		CreatedByID:  parseStringPtr(m["createdById"]),
		Participants: parseStringSlice(m["participants"]),
	}
}

func parseNewTask(v interface{}) *model.NewTask {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewTask{
		Title:       getString(m, "title"),
		Content:     getString(m, "content"),
		CreatedByID: getString(m, "createdById"),
		AssigneeID:  parseStringPtr(m["assigneeId"]),
		StatusID:    parseStringPtr(m["statusId"]),
		DueDate:     parseStringPtr(m["dueDate"]),
		Priority:    getString(m, "priority"),
	}
}

func parseUpdateTaskInput(v interface{}) *model.UpdateTaskInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateTaskInput{
		Title:       parseStringPtr(m["title"]),
		Content:     parseStringPtr(m["content"]),
		CreatedByID: parseStringPtr(m["createdById"]),
		AssigneeID:  parseStringPtr(m["assigneeId"]),
		StatusID:    parseStringPtr(m["statusId"]),
		DueDate:     parseStringPtr(m["dueDate"]),
		Priority:    parseStringPtr(m["priority"]),
	}
}

func parseNewTaskStatus(v interface{}) *model.NewTaskStatus {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewTaskStatus{
		Code:  getString(m, "code"),
		Label: getString(m, "label"),
	}
}

func parseUpdateTaskStatusInput(v interface{}) *model.UpdateTaskStatusInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateTaskStatusInput{
		Code:  parseStringPtr(m["code"]),
		Label: parseStringPtr(m["label"]),
	}
}

func parseNewMessage(v interface{}) *model.NewMessage {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.NewMessage{
		Content:   getString(m, "content"),
		Receivers: parseStringSlice(m["receivers"]),
	}
}

func parseUpdateMessageInput(v interface{}) *model.UpdateMessageInput {
	if v == nil {
		return nil
	}
	m, ok := v.(map[string]interface{})
	if !ok {
		return nil
	}
	return &model.UpdateMessageInput{
		Content:   parseStringPtr(m["content"]),
		Receivers: parseStringSlice(m["receivers"]),
	}
}
