package app

import (
	"net/http"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
	"github.com/tidbcloud/AgentTeam/internal/extension/providers/searchengine/runtime"
	storeapp "github.com/tidbcloud/AgentTeam/internal/store/app"
)

func (handler *WorkspaceAppHandler) SearchEngineConnectionGet(
	r api.WorkspaceScopedRequest,
) (api.Response, error) {
	view, err := handler.store.GetSearchEngineConnectionForUser(
		r.Context(),
		r.UserID(),
		r.WorkspaceID(),
		strings.TrimSpace(r.Gin.Param("installationId")),
	)
	if err != nil {
		return api.Response{}, err
	}
	return noStoreOK(converter.ToSearchEngineConnectionResponse(view)), nil
}

func (handler *WorkspaceAppHandler) SearchEngineConnectionPut(
	r api.WorkspaceScopedJSON[dto.SearchEngineConnectionPutRequest],
) (api.Response, error) {
	view, err := handler.store.UpsertSearchEngineConnectionForUser(
		r.Context(),
		r.UserID(),
		r.WorkspaceID(),
		strings.TrimSpace(r.Gin.Param("installationId")),
		storeapp.UpsertSearchEngineConnectionParams{
			Config:      r.Body.Config,
			Credentials: r.Body.Credentials,
		},
	)
	if err != nil {
		return api.Response{}, err
	}
	handler.emitWorkspaceAppsUpdated(r.WorkspaceID())
	return noStoreOK(converter.ToSearchEngineConnectionResponse(view)), nil
}

func (handler *WorkspaceAppHandler) SearchEngineConnectionDelete(
	r api.WorkspaceScopedRequest,
) (api.Response, error) {
	view, err := handler.store.DeleteSearchEngineConnectionForUser(
		r.Context(),
		r.UserID(),
		r.WorkspaceID(),
		strings.TrimSpace(r.Gin.Param("installationId")),
	)
	if err != nil {
		return api.Response{}, err
	}
	handler.emitWorkspaceAppsUpdated(r.WorkspaceID())
	return noStoreOK(converter.ToSearchEngineConnectionResponse(view)), nil
}

func (handler *WorkspaceAppHandler) SearchEngineConnectionTest(
	r api.WorkspaceScopedRequest,
) (api.Response, error) {
	installationID := strings.TrimSpace(r.Gin.Param("installationId"))
	view, err := handler.store.GetSearchEngineConnectionForUser(
		r.Context(),
		r.UserID(),
		r.WorkspaceID(),
		installationID,
	)
	if err != nil {
		return api.Response{}, err
	}
	if !view.Active {
		return api.Response{}, api.NewHTTPError(
			http.StatusBadRequest,
			"Search engine connection is not configured",
		)
	}
	if handler.searchEngineConnections == nil || handler.searchEngineTester == nil {
		return api.Response{}, api.NewHTTPError(
			http.StatusServiceUnavailable,
			"Search engine connection testing is unavailable",
		)
	}
	connection, err := handler.searchEngineConnections.ResolveSearchEngineRuntimeConnection(
		r.Context(),
		r.WorkspaceID(),
		installationID,
		view.Provider,
	)
	if err != nil {
		return api.Response{}, err
	}
	if err := handler.searchEngineTester.TestConnection(r.Context(), connection); err != nil {
		return api.Response{}, searchEngineTestHTTPError(err)
	}
	return noStoreOK(dto.SearchEngineConnectionTestResponse{OK: true}), nil
}

func searchEngineTestHTTPError(err error) error {
	switch runtime.CodeOf(err) {
	case runtime.ErrorValidation,
		runtime.ErrorProviderAuthUnavailable:
		return api.NewHTTPError(
			http.StatusBadRequest,
			"Search engine connection was rejected",
		)
	case runtime.ErrorRateLimited:
		return api.NewHTTPError(
			http.StatusTooManyRequests,
			"Search engine provider rate limited the test",
		)
	default:
		return api.NewHTTPError(
			http.StatusBadGateway,
			"Search engine connection test failed",
		)
	}
}
