package testkit

import (
	"errors"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/core/domain"
	"github.com/tidbcloud/AgentTeam/internal/runtimecontrol"
	"github.com/tidbcloud/AgentTeam/internal/store/taskboard"
)

const HeaderWorkspaceID = "X-Workspace-Id"

func WriteAPIError(ctx *gin.Context, status int, message string) {
	trimmed := strings.TrimSpace(message)
	if trimmed == "" {
		trimmed = http.StatusText(status)
		if trimmed == "" {
			trimmed = "Request failed"
		}
	}
	ctx.JSON(status, gin.H{"error": trimmed})
}

func WriteAPIErrorWithCode(ctx *gin.Context, status int, message string, code string) {
	trimmedCode := strings.TrimSpace(code)
	if trimmedCode == "" {
		WriteAPIError(ctx, status, message)
		return
	}

	trimmedMessage := strings.TrimSpace(message)
	if trimmedMessage == "" {
		trimmedMessage = http.StatusText(status)
		if trimmedMessage == "" {
			trimmedMessage = "Request failed"
		}
	}
	ctx.JSON(status, gin.H{
		"error": trimmedMessage,
		"code":  trimmedCode,
	})
}

func BearerTokenFromRequest(ctx *gin.Context) (string, bool) {
	raw := strings.TrimSpace(ctx.GetHeader("Authorization"))
	if raw == "" {
		return "", false
	}
	parts := strings.Fields(raw)
	if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
		return "", false
	}
	token := strings.TrimSpace(parts[1])
	if token == "" {
		return "", false
	}
	return token, true
}

func WorkspaceIDFromRequest(ctx *gin.Context) (string, bool) {
	workspaceID := strings.TrimSpace(ctx.GetHeader(HeaderWorkspaceID))
	if workspaceID == "" {
		return "", false
	}
	return workspaceID, true
}

func StatusForError(err error) int {
	switch {
	case errors.Is(err, api.ErrUnauthorized):
		return http.StatusUnauthorized
	case errors.Is(err, api.ErrForbidden):
		return http.StatusForbidden
	case errors.Is(err, api.ErrNotFound):
		return http.StatusNotFound
	case errors.Is(err, api.ErrConflict):
		return http.StatusConflict
	case errors.Is(err, api.ErrGone):
		return http.StatusGone
	case errors.Is(err, api.ErrSystemAlreadyInitialized):
		return http.StatusConflict
	case errors.Is(err, api.ErrSystemNotInitialized):
		return http.StatusConflict
	case errors.Is(err, api.ErrBadRequest):
		return http.StatusBadRequest
	case errors.Is(err, taskboard.ErrForbidden):
		return http.StatusForbidden
	case errors.Is(err, taskboard.ErrNotFound):
		return http.StatusNotFound
	case errors.Is(err, taskboard.ErrConflict):
		return http.StatusConflict
	case errors.Is(err, taskboard.ErrBadRequest):
		return http.StatusBadRequest
	case errors.Is(err, domain.ErrInvalidArgument):
		return http.StatusBadRequest
	case errors.Is(err, runtimecontrol.ErrAgentStillRunning):
		return http.StatusConflict
	case errors.Is(err, runtimecontrol.ErrDaemonWorkspaceTargetPathUpgradeRequired):
		return http.StatusConflict
	case errors.Is(err, runtimecontrol.ErrDaemonPermissionModeUpgradeRequired):
		return http.StatusConflict
	case errors.Is(err, runtimecontrol.ErrMachineOffline):
		return http.StatusServiceUnavailable
	default:
		return http.StatusInternalServerError
	}
}

func WriteStoreError(ctx *gin.Context, err error) {
	status := StatusForError(err)
	WriteAPIError(ctx, status, err.Error())
}
