package tushare

// Input and output JSON Schema builders for the Tushare catalog. Schemas are
// plain map literals mirroring the upstream OpenConnector action schemas:
// property names keep the upstream camelCase exactly, and Tushare table rows
// are nullable because the projection fills absent cells with null.

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 stringSchema(description string) map[string]any {
	return map[string]any{"type": "string", "description": description}
}

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

func enumStringSchema(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 yyyymmddSchema(description string) map[string]any {
	return map[string]any{
		"type": "string", "pattern": "^[0-9]{8}$",
		"minLength": 8, "maxLength": 8, "description": description,
	}
}

func integerSchema(description string) map[string]any {
	return map[string]any{"type": "integer", "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 nullableNumberSchema(description string) map[string]any {
	return map[string]any{
		"anyOf": []any{
			map[string]any{"type": "null"},
			map[string]any{"type": "number"},
		},
		"description": description,
	}
}

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

// jsonValueSchema accepts any JSON value; Tushare table cells are passed
// through verbatim.
func jsonValueSchema(description string) map[string]any {
	return map[string]any{"description": description}
}

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

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

func anyOfStringOrStringArraySchema(description string) map[string]any {
	return map[string]any{
		"anyOf": []any{
			nonEmptyStringSchema("Comma-separated Tushare field list, such as ts_code,name,list_date."),
			stringArraySchema("List of Tushare field names to request.", "One Tushare field name."),
		},
		"description": description,
	}
}
