package api

import "strings"

// Parameter represents an OpenAPI parameter.
type Parameter map[string]any

// PathParam creates a required path parameter.
//
// Example:
//
//	PathParam("id", "User identifier")
func PathParam(name, description string) Parameter {
	return Parameter{
		"name":        name,
		"in":          "path",
		"required":    true,
		"description": description,
		"schema":      String(),
	}
}

// PathParamWithSchema creates a required path parameter with a custom schema.
func PathParamWithSchema(name, description string, schema Schema) Parameter {
	return Parameter{
		"name":        name,
		"in":          "path",
		"required":    true,
		"description": description,
		"schema":      schema,
	}
}

// QueryParam creates an optional query parameter.
//
// Example:
//
//	QueryParam("page", "Page number", false)
func QueryParam(name, description string, required bool) Parameter {
	return Parameter{
		"name":        name,
		"in":          "query",
		"required":    required,
		"description": description,
		"schema":      String(),
	}
}

// QueryParamWithSchema creates a query parameter with a custom schema.
func QueryParamWithSchema(name, description string, required bool, schema Schema) Parameter {
	return Parameter{
		"name":        name,
		"in":          "query",
		"required":    required,
		"description": description,
		"schema":      schema,
	}
}

// HeaderParam creates a header parameter.
func HeaderParam(name, description string, required bool) Parameter {
	return Parameter{
		"name":        name,
		"in":          "header",
		"required":    required,
		"description": description,
		"schema":      String(),
	}
}

// CookieParam creates a cookie parameter.
func CookieParam(name, description string, required bool) Parameter {
	return Parameter{
		"name":        name,
		"in":          "cookie",
		"required":    required,
		"description": description,
		"schema":      String(),
	}
}

// WithExample adds an example to a parameter.
func (p Parameter) WithExample(example any) Parameter {
	p["example"] = example
	return p
}

// WithDefault adds a default value to a parameter.
func (p Parameter) WithDefault(value any) Parameter {
	if schema, ok := p["schema"].(Schema); ok {
		schema["default"] = value
		p["schema"] = schema
	}
	return p
}

// WithDeprecated marks a parameter as deprecated.
func (p Parameter) WithDeprecated(deprecated bool) Parameter {
	p["deprecated"] = deprecated
	return p
}

// -----------------------------------------------------------------------------
// Common Parameter Presets
// -----------------------------------------------------------------------------

// IDParam creates a standard ID path parameter.
func IDParam() Parameter {
	return PathParamWithSchema("id", "Resource identifier", UUID())
}

// PageParam creates a standard pagination page parameter.
func PageParam() Parameter {
	return QueryParamWithSchema("page", "Page number (1-indexed)", false, Int().WithDefault(1))
}

// PerPageParam creates a standard items-per-page parameter.
func PerPageParam() Parameter {
	return QueryParamWithSchema("per_page", "Items per page (max 100)", false, IntWithMinMax(1, 100).WithDefault(20))
}

// SortParam creates a sort parameter.
// If allowedFields are provided, they're listed in the description.
func SortParam(allowedFields ...string) Parameter {
	desc := "Sort field and direction (e.g., name:asc, created_at:desc)"
	if len(allowedFields) > 0 {
		desc = "Sort by: " + strings.Join(allowedFields, ", ") + " (append :asc or :desc)"
	}
	return QueryParamWithSchema("sort", desc, false,
		String().WithExample("created_at:desc"))
}

// SearchParam creates a search query parameter.
func SearchParam() Parameter {
	return QueryParam("q", "Search query", false).WithExample("keyword")
}

// APIKeyHeader creates the X-API-Key header parameter.
func APIKeyHeader() Parameter {
	return HeaderParam("X-API-Key", "API key for authentication", true)
}

// AuthorizationHeader creates the Authorization header parameter.
func AuthorizationHeader() Parameter {
	return HeaderParam("Authorization", "Bearer token for authentication", true).
		WithExample("Bearer eyJhbGciOiJIUzI1NiIs...")
}

// -----------------------------------------------------------------------------
// Request Body Helpers
// -----------------------------------------------------------------------------

// RequestBody creates a JSON request body.
func RequestBody(schema Schema, required bool) map[string]any {
	return map[string]any{
		"required": required,
		"content": map[string]any{
			"application/json": map[string]any{
				"schema": schema,
			},
		},
	}
}

// -----------------------------------------------------------------------------
// Response Helpers
// -----------------------------------------------------------------------------

// OpResponse creates a response definition for an OpenAPI operation.
func OpResponse(description string, schema Schema) map[string]any {
	return map[string]any{
		"description": description,
		"content": map[string]any{
			"application/json": map[string]any{
				"schema": schema,
			},
		},
	}
}

// OpResponseNoContent creates a 204 No Content response.
func OpResponseNoContent() map[string]any {
	return map[string]any{
		"description": "No content",
	}
}

// OpResponses creates a responses map for an operation.
func OpResponses(responses map[string]map[string]any) map[string]any {
	result := make(map[string]any, len(responses))
	for code, resp := range responses {
		result[code] = resp
	}
	return result
}

// OpStandardResponses returns common error responses to include in operations.
func OpStandardResponses() map[string]map[string]any {
	return map[string]map[string]any{
		"400": OpResponse("Bad request", ErrorResponseSchema()),
		"401": OpResponse("Unauthorized", ErrorResponseSchema()),
		"403": OpResponse("Forbidden", ErrorResponseSchema()),
		"404": OpResponse("Not found", ErrorResponseSchema()),
		"422": OpResponse("Unprocessable entity", ErrorResponseSchema()),
		"429": OpResponse("Too many requests", ErrorResponseSchema()),
		"500": OpResponse("Internal server error", ErrorResponseSchema()),
		"503": OpResponse("Service unavailable", ErrorResponseSchema()),
	}
}
