package dingtalkbot

// Input and output JSON Schema builders for the DingTalk Bot catalog,
// mirroring the ported OpenConnector action contracts.

const schemaDialect = "https://json-schema.org/draft/2020-12/schema"

func objectSchema(properties map[string]any, required []string) map[string]any {
	schema := map[string]any{
		"$schema":              schemaDialect,
		"type":                 "object",
		"additionalProperties": false,
		"properties":           properties,
	}
	if len(required) > 0 {
		anyRequired := make([]any, 0, len(required))
		for _, name := range required {
			anyRequired = append(anyRequired, name)
		}
		schema["required"] = anyRequired
	}
	return schema
}

func nonEmptyStringSchema(description string) map[string]any {
	return map[string]any{
		"type":        "string",
		"minLength":   1,
		"description": description,
	}
}

func stringSchema(description string) map[string]any {
	return map[string]any{"type": "string", "description": description}
}

func booleanSchema(description string) map[string]any {
	return map[string]any{"type": "boolean", "description": description}
}

func stringArraySchema(description string) map[string]any {
	return map[string]any{
		"type":        "array",
		"minItems":    1,
		"description": description,
		"items":       nonEmptyStringSchema("One value."),
	}
}

func stringEnumSchema(description string, values ...string) map[string]any {
	anyValues := make([]any, 0, len(values))
	for _, value := range values {
		anyValues = append(anyValues, value)
	}
	return map[string]any{
		"type":        "string",
		"enum":        anyValues,
		"description": description,
	}
}

func literalSchema(value string, description string) map[string]any {
	return map[string]any{
		"type":        "string",
		"const":       value,
		"description": description,
	}
}

func atFields() map[string]any {
	return map[string]any{
		"atMobiles": stringArraySchema("Optional mobile numbers to mention in the group."),
		"atUserIds": stringArraySchema("Optional DingTalk user IDs to mention in the group."),
		"isAtAll":   booleanSchema("Whether to mention everyone in the group."),
	}
}

func sendResultSchema() map[string]any {
	return objectSchema(map[string]any{
		"errcode": map[string]any{"type": "integer", "description": "The DingTalk response code. 0 means success."},
		"errmsg":  map[string]any{"type": "string", "description": "The DingTalk response message."},
	}, []string{"errcode", "errmsg"})
}

func sendTextInputSchema() map[string]any {
	properties := map[string]any{
		"msgUuid": nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"content": nonEmptyStringSchema("The text message content."),
	}
	for name, schema := range atFields() {
		properties[name] = schema
	}
	return objectSchema(properties, []string{"content"})
}

func sendLinkInputSchema() map[string]any {
	return objectSchema(map[string]any{
		"msgUuid":    nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"title":      nonEmptyStringSchema("The message title."),
		"text":       nonEmptyStringSchema("The message text shown in the card."),
		"messageUrl": nonEmptyStringSchema("The URL opened after clicking the message."),
		"picUrl":     nonEmptyStringSchema("The optional image URL shown in the message."),
	}, []string{"title", "text", "messageUrl"})
}

func sendMarkdownInputSchema() map[string]any {
	properties := map[string]any{
		"msgUuid": nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"title":   nonEmptyStringSchema("The title shown in the conversation preview."),
		"text":    nonEmptyStringSchema("The markdown message body."),
	}
	for name, schema := range atFields() {
		properties[name] = schema
	}
	return objectSchema(properties, []string{"title", "text"})
}

func buttonOrientationSchema() map[string]any {
	return stringEnumSchema(
		"How to arrange actionCard buttons. vertical maps to DingTalk 0, horizontal maps to 1.",
		"vertical", "horizontal")
}

func actionCardButtonSchema() map[string]any {
	return objectSchema(map[string]any{
		"title":     nonEmptyStringSchema("The button title."),
		"actionUrl": nonEmptyStringSchema("The URL opened after clicking the button."),
	}, []string{"title", "actionUrl"})
}

func actionCardButtonsSchema() map[string]any {
	return map[string]any{
		"type":        "array",
		"minItems":    1,
		"description": "The action buttons shown on the card.",
		"items":       actionCardButtonSchema(),
	}
}

func sendActionCardInputSchema() map[string]any {
	single := objectSchema(map[string]any{
		"cardMode":          literalSchema("single", "Use one overall action button."),
		"msgUuid":           nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"title":             nonEmptyStringSchema("The actionCard title."),
		"text":              nonEmptyStringSchema("The markdown actionCard body."),
		"singleTitle":       nonEmptyStringSchema("The single action button title."),
		"singleUrl":         nonEmptyStringSchema("The URL opened after clicking the single action."),
		"buttonOrientation": buttonOrientationSchema(),
	}, []string{"cardMode", "title", "text", "singleTitle", "singleUrl"})
	buttons := objectSchema(map[string]any{
		"cardMode":          literalSchema("buttons", "Use multiple independent action buttons."),
		"msgUuid":           nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"title":             nonEmptyStringSchema("The actionCard title."),
		"text":              nonEmptyStringSchema("The markdown actionCard body."),
		"buttons":           actionCardButtonsSchema(),
		"buttonOrientation": buttonOrientationSchema(),
	}, []string{"cardMode", "title", "text", "buttons"})
	return map[string]any{
		"$schema":     schemaDialect,
		"anyOf":       []any{single, buttons},
		"description": "Input for sending a DingTalk actionCard message.",
	}
}

func feedCardLinkSchema() map[string]any {
	return objectSchema(map[string]any{
		"title":      nonEmptyStringSchema("The link title."),
		"messageUrl": nonEmptyStringSchema("The URL opened after clicking the link."),
		"picUrl":     nonEmptyStringSchema("The image URL shown for the link."),
	}, []string{"title", "messageUrl", "picUrl"})
}

func sendFeedCardInputSchema() map[string]any {
	return objectSchema(map[string]any{
		"msgUuid": nonEmptyStringSchema("Optional idempotency key used to deduplicate retries."),
		"links": map[string]any{
			"type":        "array",
			"minItems":    1,
			"description": "The links included in the feedCard.",
			"items":       feedCardLinkSchema(),
		},
	}, []string{"links"})
}
