package bindingmanage

import (
	"encoding/json"
	"fmt"

	"github.com/tidbcloud/AgentTeam/internal/store/workflow/binding"
	bindinglang "github.com/tidbcloud/AgentTeam/internal/workflow/binding"
)

func storeActor(value Actor) binding.Actor {
	return binding.Actor{Type: value.Type, ID: value.ID, MemberID: value.MemberID}
}

func actorFromStore(value binding.Actor) Actor {
	return Actor{Type: value.Type, ID: value.ID, MemberID: value.MemberID}
}

func storeOwner(value Owner) binding.Owner {
	return binding.Owner{UserID: value.UserID, MemberID: value.MemberID}
}

func ownerFromStore(value binding.Owner) Owner {
	return Owner{UserID: value.UserID, MemberID: value.MemberID}
}

func bindingFromStore(value binding.Binding) Binding {
	result := Binding{
		ID: value.ID, WorkspaceID: value.WorkspaceID, PlanID: value.PlanID,
		PlanDisplayName: value.PlanDisplayName,
		Key:             value.Key, DisplayName: value.DisplayName, DescriptionMD: value.DescriptionMD,
		State: BindingState(value.State), Revision: value.Revision, Owner: ownerFromStore(value.Owner),
		CreatedBy: actorFromStore(value.CreatedBy), CreatedAt: value.CreatedAt,
		UpdatedBy: actorFromStore(value.UpdatedBy), UpdatedAt: value.UpdatedAt,
		ArchivedAt: value.ArchivedAt,
	}
	if value.LatestRevision.ID != "" {
		result.LatestRevision = &RevisionRef{ID: value.LatestRevision.ID, Revision: value.LatestRevision.Revision}
	}
	if value.ActiveRevision != nil {
		result.ActiveRevision = &RevisionRef{ID: value.ActiveRevision.ID, Revision: value.ActiveRevision.Revision}
	}
	if value.ArchivedBy != nil {
		actor := actorFromStore(*value.ArchivedBy)
		result.ArchivedBy = &actor
	}
	return result
}

func revisionFromStore(value binding.Revision) (Revision, error) {
	spec, err := bindinglang.DecodeConfig(value.PlanID, value.PlanVersionID, value.ConfigJSON)
	if err != nil {
		return Revision{}, fmt.Errorf("decode persisted Binding revision %s: %w", value.ID, err)
	}
	if !bindinglang.VerifyDigest(spec, value.Digest) {
		return Revision{}, fmt.Errorf("persisted Binding revision %s digest does not match its exact PlanVersion/config projection", value.ID)
	}
	source, err := json.Marshal(spec.Source)
	if err != nil {
		return Revision{}, fmt.Errorf("encode Binding revision source: %w", err)
	}
	inputPolicy, err := json.Marshal(spec.InputPolicy)
	if err != nil {
		return Revision{}, fmt.Errorf("encode Binding revision input policy: %w", err)
	}
	return Revision{
		ID: value.ID, WorkspaceID: value.WorkspaceID, BindingID: value.BindingID, PlanID: value.PlanID,
		Revision: value.Revision, PlanVersionID: value.PlanVersionID,
		Source: json.RawMessage(source), InputPolicy: json.RawMessage(inputPolicy), Digest: value.Digest,
		CreatedBy: actorFromStore(value.CreatedBy), CreatedAt: value.CreatedAt,
	}, nil
}
