package swagger

import (
	"net/http"
	"strings"

	"github.com/go-openapi/spec"
	apiSpec "github.com/zeromicro/go-zero/tools/goctl/api/spec"
)

func jsonResponseFromType(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type) *spec.Responses {
	return jsonResponseFromTypeWithDocs(ctx, atDoc, tp, nil)
}

func jsonResponseFromTypeWithDocs(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type, handlerDoc apiSpec.Doc) *spec.Responses {
	// 首先檢查是否有 @respdoc 註解（從 handlerDoc 或 atDoc）
	var respDocs []RespDoc
	if len(handlerDoc) > 0 {
		respDocs = parseRespDocsFromDoc(handlerDoc)
	}
	if len(respDocs) == 0 {
		respDocs = parseRespDocs(atDoc)
	}

	if len(respDocs) > 0 {
		return jsonResponseFromRespDocs(ctx, atDoc, respDocs, tp)
	}

	// 原有邏輯：使用默認的 200 回應
	if tp == nil {
		return &spec.Responses{
			ResponsesProps: spec.ResponsesProps{
				StatusCodeResponses: map[int]spec.Response{
					http.StatusOK: {
						ResponseProps: spec.ResponseProps{
							Description: "",
							Schema:      &spec.Schema{},
						},
					},
				},
			},
		}
	}
	props := spec.SchemaProps{
		AdditionalProperties: mapFromGoType(ctx, tp),
		Items:                itemsFromGoType(ctx, tp),
	}
	if ctx.UseDefinitions {
		structName, ok := containsStruct(tp)
		if ok {
			props.Ref = spec.MustCreateRef(getRefName(structName))
			return &spec.Responses{
				ResponsesProps: spec.ResponsesProps{
					StatusCodeResponses: map[int]spec.Response{
						http.StatusOK: {
							ResponseProps: spec.ResponseProps{
								Schema: &spec.Schema{
									SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
								},
							},
						},
					},
				},
			}
		}
	}

	p, _ := propertiesFromType(ctx, tp)
	props.Type = typeFromGoType(ctx, tp)
	props.Properties = p
	return &spec.Responses{
		ResponsesProps: spec.ResponsesProps{
			StatusCodeResponses: map[int]spec.Response{
				http.StatusOK: {
					ResponseProps: spec.ResponseProps{
						Schema: &spec.Schema{
							SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
						},
					},
				},
			},
		},
	}
}

// jsonResponseFromRespDocs 從 @respdoc 註解生成多狀態碼回應
func jsonResponseFromRespDocs(ctx Context, atDoc apiSpec.AtDoc, respDocs []RespDoc, defaultType apiSpec.Type) *spec.Responses {
	responses := &spec.Responses{
		ResponsesProps: spec.ResponsesProps{
			StatusCodeResponses: make(map[int]spec.Response),
		},
	}

	for _, respDoc := range respDocs {
		// 如果有單一 Schema，直接使用
		if respDoc.Schema != "" {
			tp := findTypeByName(ctx.Api, respDoc.Schema)
			if tp == nil && respDoc.StatusCode == http.StatusOK && defaultType != nil {
				// 如果找不到類型且是 200，使用默認類型
				tp = defaultType
			}

			response := createResponseFromType(ctx, atDoc, tp, respDoc.Description)
			responses.StatusCodeResponses[respDoc.StatusCode] = response
			continue
		}

		// 如果有多個業務錯誤碼（BizCodes），為 Swagger 2.0 創建一個通用回應
		// OpenAPI 3.0 會在 convertSwagger2ToOpenAPI3 中特殊處理
		if len(respDoc.BizCodes) > 0 {
			// 對於 Swagger 2.0，我們使用 oneOf/anyOf 概念的註釋
			// 但 Swagger 2.0 不支持 oneOf，所以使用第一個類型作為示例
			// 並在描述中列出所有可能的類型

			var firstType apiSpec.Type
			descriptions := []string{}

			for code, bizCode := range respDoc.BizCodes {
				tp := findTypeByName(ctx.Api, bizCode.Schema)
				if firstType == nil && tp != nil {
					firstType = tp
				}
				desc := code + ": " + bizCode.Schema
				if bizCode.Description != "" {
					desc += " - " + bizCode.Description
				}
				descriptions = append(descriptions, desc)
			}

			description := respDoc.Description
			if len(descriptions) > 0 {
				if description != "" {
					description += "\n\n"
				}
				description += "Possible errors:\n" + strings.Join(descriptions, "\n")
			}

			response := createResponseFromType(ctx, atDoc, firstType, description)

			// 在 VendorExtensible 中存儲業務錯誤碼信息，供 OpenAPI 3.0 使用
			if response.Extensions == nil {
				response.Extensions = make(spec.Extensions)
			}
			response.Extensions["x-biz-codes"] = respDoc.BizCodes

			responses.StatusCodeResponses[respDoc.StatusCode] = response
		}
	}

	// 如果沒有定義 200 回應，添加默認的
	if _, ok := responses.StatusCodeResponses[http.StatusOK]; !ok && defaultType != nil {
		responses.StatusCodeResponses[http.StatusOK] = createResponseFromType(ctx, atDoc, defaultType, "")
	}

	return responses
}

// createResponseFromType 從類型創建回應對象
func createResponseFromType(ctx Context, atDoc apiSpec.AtDoc, tp apiSpec.Type, description string) spec.Response {
	if tp == nil {
		return spec.Response{
			ResponseProps: spec.ResponseProps{
				Description: description,
				Schema:      &spec.Schema{},
			},
		}
	}

	props := spec.SchemaProps{
		AdditionalProperties: mapFromGoType(ctx, tp),
		Items:                itemsFromGoType(ctx, tp),
	}

	if ctx.UseDefinitions {
		structName, ok := containsStruct(tp)
		if ok {
			props.Ref = spec.MustCreateRef(getRefName(structName))
			return spec.Response{
				ResponseProps: spec.ResponseProps{
					Description: description,
					Schema: &spec.Schema{
						SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
					},
				},
			}
		}
	}

	p, _ := propertiesFromType(ctx, tp)
	props.Type = typeFromGoType(ctx, tp)
	props.Properties = p

	return spec.Response{
		ResponseProps: spec.ResponseProps{
			Description: description,
			Schema: &spec.Schema{
				SchemaProps: wrapCodeMsgProps(ctx, props, atDoc),
			},
		},
	}
}
