package repository

import (
	"context"

	"apps/backend/internal/module/radar/domain"

	"github.com/zeromicro/go-zero/core/stores/mon"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func (s *MonStore) GetDemandMap(ctx context.Context, ownerUID int64, productID string) (*domain.DemandMap, error) {
	var value domain.DemandMap
	err := s.demandMaps.FindOne(ctx, &value, bson.M{"owner_uid": ownerUID, "product_id": productID})
	if err == mon.ErrNotFound {
		return nil, domain.ErrNotFound
	}
	if err != nil {
		return nil, err
	}
	return &value, nil
}

// SaveDemandMap implements optimistic concurrency. expectedVersion=0 is only
// valid for the first insert; every subsequent write must name the version the
// editor read, preventing an older browser tab from overwriting newer phrases.
func (s *MonStore) SaveDemandMap(ctx context.Context, value *domain.DemandMap, expectedVersion int64) (*domain.DemandMap, error) {
	if value == nil {
		return nil, domain.ErrValidation
	}
	if err := value.Normalize(); err != nil {
		return nil, err
	}
	existing, err := s.GetDemandMap(ctx, value.OwnerUID, value.ProductID)
	if err != nil && err != domain.ErrNotFound {
		return nil, err
	}
	if existing == nil {
		if expectedVersion != 0 {
			return nil, domain.ErrConflict
		}
		value.MapVersion = 1
		if value.ID == "" {
			value.ID = domain.NewID()
		}
	} else {
		if existing.MapVersion != expectedVersion {
			return nil, domain.ErrConflict
		}
		value.ID = existing.ID
		value.MapVersion = existing.MapVersion + 1
	}
	if value.UpdatedAt == 0 {
		value.UpdatedAt = domain.NowNano()
	}
	if existing == nil {
		_, err = s.demandMaps.InsertOne(ctx, value)
	} else {
		res, rerr := s.demandMaps.ReplaceOne(ctx,
			bson.M{"owner_uid": value.OwnerUID, "product_id": value.ProductID, "map_version": expectedVersion},
			value, options.Replace())
		if rerr == nil && res.MatchedCount == 0 {
			rerr = domain.ErrConflict
		}
		err = rerr
	}
	if err != nil {
		if mongo.IsDuplicateKeyError(err) {
			return nil, domain.ErrConflict
		}
		return nil, err
	}
	return s.GetDemandMap(ctx, value.OwnerUID, value.ProductID)
}
