package service

import (
	"context"
	"fmt"

	"github.com/pingcap/agent-git-service/internal/db"
	reposync "github.com/pingcap/agent-git-service/internal/sync"
	"github.com/pingcap/agent-git-service/internal/sync/canonical"
)

// ResolveRepositorySyncBatchRelations replaces source-side parent identities
// with the linked target identity immediately before the dependent physical
// batch executes. Parent creates in an earlier dependency phase have already
// completed and populated the ObjectLink by this point.
func (s *Service) ResolveRepositorySyncBatchRelations(ctx context.Context, bindingID uint, sourceSide string, batch *reposync.PhysicalBatch) error {
	if batch == nil {
		return fmt.Errorf("%w: sync batch is required", ErrValidation)
	}
	for index := range batch.Items {
		item := &batch.Items[index]
		if item.Action == reposync.ActionDelete {
			// Delete payloads are copied from the current target inventory, so
			// their parent identity is already target-native. Re-resolving it as
			// a source identity would break deletion of comments, reviews,
			// review requests, and release assets.
			continue
		}
		if len(item.Payload) == 0 {
			continue
		}
		record, err := canonical.Decode(item.Payload)
		if err != nil {
			return err
		}
		if record.ParentType == "" || record.ParentIdentity == "" {
			continue
		}
		query := s.DBForCtx(ctx).Where("binding_id = ? AND logical_object_type = ? AND status = ?", bindingID, record.ParentType, "active")
		if sourceSide == SyncSideA {
			query = query.Where("side_a_id = ?", record.ParentIdentity)
		} else {
			query = query.Where("side_b_id = ?", record.ParentIdentity)
		}
		var link db.SyncObjectLink
		if err := query.Take(&link).Error; err != nil {
			return fmt.Errorf("resolve parent %s/%s: %w", record.ParentType, record.ParentIdentity, err)
		}
		var targetIdentity *string
		if sourceSide == SyncSideA {
			targetIdentity = link.SideBID
		} else {
			targetIdentity = link.SideAID
		}
		if targetIdentity == nil || *targetIdentity == "" {
			return fmt.Errorf("%w: parent %s/%s has no verified target identity", ErrConflict, record.ParentType, record.ParentIdentity)
		}
		record.ParentIdentity = *targetIdentity
		payload, err := record.Payload()
		if err != nil {
			return err
		}
		item.Payload = payload
	}
	return nil
}
