package binding

import (
	"net/http"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
)

func (handler *RevisionHandler) Create(request api.WorkspaceScopedJSON[dto.WorkflowBindingRevisionCreateRequest]) (api.Response, error) {
	id, expectedRevision, err := bindingMutationPreconditions(request.WorkspaceScopedRequest)
	if err != nil {
		return api.Response{}, err
	}
	planVersionID, source, inputPolicy, err := requiredRevisionSpec(request.Body.PlanVersionID, request.Body.Source, request.Body.InputPolicy)
	if err != nil {
		return api.Response{}, err
	}
	idempotencyKey, err := requireIdempotencyKey(request.Gin.GetHeader(idempotencyHeader))
	if err != nil {
		return api.Response{}, err
	}
	binding, revision, err := handler.service.CreateRevision(request.Context(), CreateRevisionInput{
		WorkspaceID:      request.WorkspaceID(),
		BindingID:        id,
		ExpectedRevision: expectedRevision,
		PlanVersionID:    planVersionID,
		Source:           source,
		InputPolicy:      inputPolicy,
		Principal:        requestOwner(request.WorkspaceScopedRequest),
		Actor:            requestActor(request.WorkspaceScopedRequest),
		IdempotencyKey:   idempotencyKey,
	})
	if err != nil {
		return api.Response{}, err
	}
	return bindingRevisionMutationResponse(http.StatusCreated, binding, revision), nil
}

func (handler *RevisionHandler) List(request api.WorkspaceScopedRequest) (api.Response, error) {
	id, err := bindingID(request)
	if err != nil {
		return api.Response{}, err
	}
	limit, err := pageLimit(request)
	if err != nil {
		return api.Response{}, err
	}
	page, err := handler.service.ListRevisions(request.Context(), ListRevisionsInput{
		WorkspaceID: request.WorkspaceID(),
		BindingID:   id,
		Limit:       limit,
		Cursor:      strings.TrimSpace(request.Gin.Query("cursor")),
	})
	if err != nil {
		return api.Response{}, err
	}
	items := make([]dto.WorkflowBindingRevisionResponse, 0, len(page.Items))
	for _, item := range page.Items {
		items = append(items, revisionResponse(item))
	}
	return api.OK(dto.WorkflowBindingRevisionListResponse{Items: items, NextCursor: page.NextCursor}), nil
}

func (handler *RevisionHandler) Get(request api.WorkspaceScopedRequest) (api.Response, error) {
	id, err := bindingID(request)
	if err != nil {
		return api.Response{}, err
	}
	revisionNumber, err := revisionNumber(request)
	if err != nil {
		return api.Response{}, err
	}
	revision, err := handler.service.GetRevision(request.Context(), request.WorkspaceID(), id, revisionNumber)
	if err != nil {
		return api.Response{}, err
	}
	return api.Response{
		Status:  http.StatusOK,
		Body:    revisionResponse(revision),
		Headers: http.Header{"ETag": []string{bindingRevisionETag(revision.ID, revision.Revision, revision.Digest)}},
	}, nil
}

func (handler *RevisionHandler) Activate(request api.WorkspaceScopedRequest) (api.Response, error) {
	id, expectedRevision, err := bindingMutationPreconditions(request)
	if err != nil {
		return api.Response{}, err
	}
	revisionNumber, err := revisionNumber(request)
	if err != nil {
		return api.Response{}, err
	}
	idempotencyKey, err := requireIdempotencyKey(request.Gin.GetHeader(idempotencyHeader))
	if err != nil {
		return api.Response{}, err
	}
	binding, revision, err := handler.service.Activate(request.Context(), ActivateInput{
		WorkspaceID:      request.WorkspaceID(),
		BindingID:        id,
		Revision:         revisionNumber,
		ExpectedRevision: expectedRevision,
		Principal:        requestOwner(request),
		Actor:            requestActor(request),
		IdempotencyKey:   idempotencyKey,
	})
	if err != nil {
		return api.Response{}, err
	}
	return bindingRevisionMutationResponse(http.StatusOK, binding, revision), nil
}

func bindingRevisionMutationResponse(status int, binding Binding, revision Revision) api.Response {
	return api.Response{
		Status: status,
		Body: dto.WorkflowBindingRevisionMutationResponse{
			Binding: bindingResponse(binding), Revision: revisionResponse(revision),
		},
		Headers: http.Header{
			"ETag":                    []string{bindingETag(binding.ID, binding.Revision)},
			"X-Binding-Revision-ETag": []string{bindingRevisionETag(revision.ID, revision.Revision, revision.Digest)},
		},
	}
}
