package tianyancha

// Input and output JSON Schema builders for the Tianyancha catalog, ported
// from the upstream OpenConnector actions. Record payloads stay loose
// objects because the available fields depend on the API editions the
// workspace purchased.

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 rawObjectSchema(description string) map[string]any {
	return map[string]any{
		"$schema":              schemaDialect,
		"type":                 "object",
		"description":          description,
		"additionalProperties": true,
	}
}

func nullableRawObjectSchema(description string) map[string]any {
	return map[string]any{
		"anyOf": []any{
			map[string]any{"type": "null"},
			rawObjectSchema(description),
		},
		"description": description,
	}
}

func rawRecordArraySchema(description string) map[string]any {
	return map[string]any{
		"type":        "array",
		"items":       rawObjectSchema("A record returned by Tianyancha."),
		"description": description,
	}
}

// nonWhitespaceSchema mirrors upstream s.nonWhitespaceString: at least one
// non-whitespace character, internal spaces allowed.
func nonWhitespaceSchema(description string) map[string]any {
	return map[string]any{
		"type":        "string",
		"pattern":     `\S`,
		"description": description,
	}
}

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

func nullableIntegerSchema(description string, minimum, maximum int) map[string]any {
	return map[string]any{
		"anyOf": []any{
			map[string]any{"type": "null"},
			map[string]any{"type": "integer", "minimum": minimum, "maximum": maximum},
		},
		"description": description,
	}
}

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

func enumArraySchema(description, itemDescription 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":        "array",
		"items":       map[string]any{"type": "string", "enum": anyValues, "description": itemDescription},
		"minItems":    1,
		"description": description,
	}
}

func enumSchema(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 dateSchema(description string) map[string]any {
	return map[string]any{
		"type":        "string",
		"pattern":     `^\d{4}-\d{2}-\d{2}$`,
		"description": description,
	}
}

var (
	pageNumSchema = map[string]any{
		"type":        "integer",
		"minimum":     1,
		"description": "The one-based page number. Defaults to 1.",
	}
	pageSizeSchema = map[string]any{
		"type":        "integer",
		"minimum":     1,
		"maximum":     20,
		"description": "The number of records per page. Defaults to 20 and cannot exceed 20.",
	}
	keywordSchema = nonWhitespaceSchema(
		"A company name, Tianyancha company ID, registration number, or unified social credit code.")
)

func nonNegativeIntegerSchema(description string) map[string]any {
	return map[string]any{"type": "integer", "minimum": 0, "description": description}
}

func positiveIntegerSchema(description string) map[string]any {
	return map[string]any{"type": "integer", "minimum": 1, "description": description}
}

// pagedOutputSchema mirrors upstream pagedOutput: one keyed record array plus
// the pagination echo.
func pagedOutputSchema(itemName, itemDescription string) map[string]any {
	return objectSchema(map[string]any{
		itemName:   rawRecordArraySchema(itemDescription),
		"total":    nonNegativeIntegerSchema("The total number of matching records reported by Tianyancha."),
		"pageNum":  positiveIntegerSchema("The requested one-based page number."),
		"pageSize": positiveIntegerSchema("The requested number of records per page."),
	}, nil)
}
