package plan

import (
	"net/http"
	"strings"

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

func (handler *VersionHandler) Publish(r api.WorkspaceScopedJSON[dto.WorkflowPlanPublishRequest]) (api.Response, error) {
	id, expectedRevision, err := planMutationPreconditions(r.WorkspaceScopedRequest)
	if err != nil {
		return api.Response{}, err
	}
	if err := handler.requireDirectPlanMutationAllowed(
		r.Context(), r.WorkspaceID(), id, r.Workspace.MemberID,
	); err != nil {
		return api.Response{}, err
	}
	plan, version, err := handler.service.Publish(r.Context(), planmanage.PublishInput{
		WorkspaceID:          r.WorkspaceID(),
		PlanID:               id,
		ExpectedPlanRevision: expectedRevision,
		DraftRevision:        r.Body.DraftRevision,
		MakeDefault:          r.Body.MakeDefault,
		Actor:                requestActor(r.WorkspaceScopedRequest),
		IdempotencyKey:       idempotencyKey(r.WorkspaceScopedRequest),
	})
	if err != nil {
		return api.Response{}, err
	}
	return publishResponse(http.StatusCreated, plan, version), nil
}

func (handler *VersionHandler) List(r api.WorkspaceScopedRequest) (api.Response, error) {
	id, err := planID(r)
	if err != nil {
		return api.Response{}, err
	}
	limit, err := pageLimit(r)
	if err != nil {
		return api.Response{}, err
	}
	page, err := handler.service.ListVersions(r.Context(), r.WorkspaceID(), id, limit, strings.TrimSpace(r.Gin.Query("cursor")))
	if err != nil {
		return api.Response{}, err
	}
	items := make([]dto.WorkflowPlanVersionSummaryResponse, 0, len(page.Items))
	for _, item := range page.Items {
		items = append(items, versionSummaryResponse(item))
	}
	return api.OK(dto.WorkflowPlanVersionListResponse{Items: items, NextCursor: page.NextCursor}), nil
}

func (handler *VersionHandler) Get(r api.WorkspaceScopedRequest) (api.Response, error) {
	id, err := planID(r)
	if err != nil {
		return api.Response{}, err
	}
	versionID, err := versionID(r)
	if err != nil {
		return api.Response{}, err
	}
	version, err := handler.service.GetVersion(r.Context(), r.WorkspaceID(), id, versionID)
	if err != nil {
		return api.Response{}, err
	}
	return api.Response{
		Status:  http.StatusOK,
		Body:    versionResponse(version),
		Headers: http.Header{"ETag": []string{`"workflow-plan-version:` + version.ID + `:` + version.Digest + `"`}},
	}, nil
}

func (handler *VersionHandler) Republish(r api.WorkspaceScopedJSON[dto.WorkflowPlanRepublishRequest]) (api.Response, error) {
	id, expectedRevision, err := planMutationPreconditions(r.WorkspaceScopedRequest)
	if err != nil {
		return api.Response{}, err
	}
	versionID, err := versionID(r.WorkspaceScopedRequest)
	if err != nil {
		return api.Response{}, err
	}
	if err := handler.requireDirectPlanMutationAllowed(
		r.Context(), r.WorkspaceID(), id, r.Workspace.MemberID,
	); err != nil {
		return api.Response{}, err
	}
	plan, version, err := handler.service.Republish(r.Context(), planmanage.RepublishInput{
		WorkspaceID:          r.WorkspaceID(),
		PlanID:               id,
		SourceVersionID:      versionID,
		ExpectedPlanRevision: expectedRevision,
		MakeDefault:          r.Body.MakeDefault,
		Actor:                requestActor(r.WorkspaceScopedRequest),
		IdempotencyKey:       idempotencyKey(r.WorkspaceScopedRequest),
	})
	if err != nil {
		return api.Response{}, err
	}
	return publishResponse(http.StatusCreated, plan, version), nil
}

func (handler *VersionHandler) MakeDefault(r api.WorkspaceScopedRequest) (api.Response, error) {
	id, expectedRevision, err := planMutationPreconditions(r)
	if err != nil {
		return api.Response{}, err
	}
	versionID, err := versionID(r)
	if err != nil {
		return api.Response{}, err
	}
	if err := handler.requireDirectPlanMutationAllowed(
		r.Context(), r.WorkspaceID(), id, r.Workspace.MemberID,
	); err != nil {
		return api.Response{}, err
	}
	plan, err := handler.service.SetDefault(r.Context(), planmanage.PromoteDefaultInput{
		WorkspaceID:      r.WorkspaceID(),
		PlanID:           id,
		ExpectedRevision: expectedRevision,
		VersionID:        versionID,
		Actor:            requestActor(r),
	})
	if err != nil {
		return api.Response{}, err
	}
	return planOK(plan), nil
}

func publishResponse(status int, plan planmanage.Plan, version planmanage.Version) api.Response {
	return api.Response{
		Status: status,
		Body: dto.WorkflowPlanPublishResponse{
			Plan:    editablePlanResponse(plan),
			Version: versionResponse(version),
		},
		Headers: http.Header{"ETag": []string{planETag(plan.ID, plan.Revision)}},
	}
}
