package main

import (
	"encoding/json"
	"fmt"
	"strings"

	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
)

type NamespacesConfig struct {
	Namespaces Namespaces `json:"namespaces"`
}

type Namespaces map[string]Namespace

type Namespace struct {
	Name                string              `json:"-"`
	LocationConstraints LocationConstraints `json:"location_constraints"`
	CopiesNumbers       map[string][]uint32 `json:"copies_numbers"`
}

type LocationConstraints map[string]netmap.PlacementPolicy

func (c *Namespaces) UnmarshalJSON(data []byte) error {
	namespaces := make(map[string]Namespace)
	if err := json.Unmarshal(data, &namespaces); err != nil {
		return err
	}

	for name, namespace := range namespaces {
		namespace.Name = name
		namespaces[name] = namespace
	}

	*c = namespaces

	return nil
}

func (c *LocationConstraints) UnmarshalJSON(data []byte) error {
	m := make(map[string]string)
	if err := json.Unmarshal(data, &m); err != nil {
		return err
	}

	*c = make(LocationConstraints, len(m))
	for region, policy := range m {
		var pp netmap.PlacementPolicy
		if err := pp.DecodeString(policy); err == nil {
			(*c)[region] = pp
			continue
		}

		if err := pp.UnmarshalJSON([]byte(policy)); err == nil {
			(*c)[region] = pp
			continue
		}

		return fmt.Errorf("failed to parse location contraint '%s': '%s'", region, policy)
	}

	return nil
}

func (c LocationConstraints) MarshalJSON() ([]byte, error) {
	m := make(map[string]string, len(c))

	for region, policy := range c {
		var sb strings.Builder
		if err := policy.WriteStringTo(&sb); err != nil {
			return nil, err
		}

		m[region] = sb.String()
	}

	return json.Marshal(m)
}