// Package response wraps handler output into the unified types.Status envelope.
// Logic layers should return (data, error) only; handlers call Write.
package response

import (
	"context"
	"net/http"

	errs "gateway/internal/library/errors"
	"gateway/internal/library/errors/code"
	"gateway/internal/types"

	"github.com/zeromicro/go-zero/rest/httpx"
)

// Write serializes data or err into types.Status and writes the HTTP response.
//   - Success: HTTP 200, code=102000, message=SUCCESS, data=<payload>
//   - Failure: HTTP from errs.Error.HTTPStatus(), code/message/error from business error
func Write(ctx context.Context, w http.ResponseWriter, data any, err error) {
	if err != nil {
		status, body := buildError(err)
		httpx.WriteJsonCtx(ctx, w, status, body)

		return
	}

	httpx.WriteJsonCtx(ctx, w, http.StatusOK, buildOK(data))
}

func buildOK(data any) types.Status {
	st := types.Status{
		Code:    code.DefaultSuccessFullCodeInt,
		Message: code.DefaultSuccessMessage,
	}
	if data != nil {
		st.Data = data
	}

	return st
}

func buildError(err error) (httpStatus int, body types.Status) {
	if e := errs.FromError(err); e != nil {
		return e.HTTPStatus(), types.Status{
			Code:    int64(e.Code()),
			Message: e.Error(),
			Error: types.ErrorDetail{
				BizCode:  e.DisplayCode(),
				Scope:    uint32(e.Scope()),
				Category: uint32(e.Category()),
				Detail:   uint32(e.Detail()),
			},
		}
	}

	// Non-business errors: generic 500, do not leak internal error text to clients.
	fallback := errs.MustNew(code.Unset, code.SysInternal, 0, "internal server error")

	return fallback.HTTPStatus(), types.Status{
		Code:    int64(fallback.Code()),
		Message: fallback.Error(),
		Error: types.ErrorDetail{
			BizCode: fallback.DisplayCode(),
		},
	}
}
