package repository

import (
	"context"
	"fmt"

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

func demandMapKey(ownerUID int64, productID string) string {
	return fmt.Sprintf("%d\x00%s", ownerUID, productID)
}

func (m *Memory) GetDemandMap(_ context.Context, ownerUID int64, productID string) (*domain.DemandMap, error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	value, ok := m.demandMaps[demandMapKey(ownerUID, productID)]
	if !ok {
		return nil, domain.ErrNotFound
	}
	return cloneDemandMap(value), nil
}

func (m *Memory) SaveDemandMap(_ 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
	}
	m.mu.Lock()
	defer m.mu.Unlock()
	key := demandMapKey(value.OwnerUID, value.ProductID)
	existing, exists := m.demandMaps[key]
	if exists {
		if expectedVersion != existing.MapVersion {
			return nil, domain.ErrConflict
		}
		value.MapVersion = existing.MapVersion + 1
	} else {
		if expectedVersion != 0 {
			return nil, domain.ErrConflict
		}
		if value.MapVersion < 1 {
			value.MapVersion = 1
		}
	}
	if value.UpdatedAt == 0 {
		value.UpdatedAt = domain.NowNano()
	}
	if value.ID == "" {
		value.ID = domain.NewID()
	}
	stored := cloneDemandMap(value)
	m.demandMaps[key] = stored
	return cloneDemandMap(stored), nil
}

func cloneDemandMap(value *domain.DemandMap) *domain.DemandMap {
	if value == nil {
		return nil
	}
	out := *value
	out.PainPhrases = append([]domain.DemandMapPhrase(nil), value.PainPhrases...)
	out.ScenarioPhrases = append([]domain.DemandMapPhrase(nil), value.ScenarioPhrases...)
	out.DesiredOutcomes = append([]domain.DemandMapPhrase(nil), value.DesiredOutcomes...)
	out.SolutionSignals = append([]domain.DemandMapPhrase(nil), value.SolutionSignals...)
	out.ExclusionSignals = append([]domain.DemandMapPhrase(nil), value.ExclusionSignals...)
	out.SourceBasis = append([]string(nil), value.SourceBasis...)
	out.CustomPhrases = append([]domain.DemandMapPhrase(nil), value.CustomPhrases...)
	return &out
}
