package zones

import (
	"bytes"
	"net/netip"
	"sort"

	"darvaza.org/core"
	"github.com/gofrs/uuid/v5"

	"git.jpi.io/amery/jpictl/pkg/ceph"
)

// GetCephFSID returns our Ceph's FSID
func (m *Zones) GetCephFSID() (uuid.UUID, error) {
	if core.IsZero(m.CephFSID) {
		// TODO: generate one
		return uuid.Nil, nil
	}
	return m.CephFSID, nil
}

// GetCephConfig reads the ceph.conf file
func (m *Zones) GetCephConfig() (*ceph.Config, error) {
	data, err := m.ReadFile("ceph.conf")
	if err != nil {
		return nil, err
	}

	r := bytes.NewReader(data)
	return ceph.NewConfigFromReader(r)
}

// GenCephConfig prepares a ceph.Config using the cluster information
func (m *Zones) GenCephConfig() (*ceph.Config, error) {
	fsid, err := m.GetCephFSID()
	if err != nil {
		return nil, err
	}

	cfg := &ceph.Config{
		Global: ceph.GlobalConfig{
			FSID: fsid,
			ClusterNetwork: netip.PrefixFrom(
				netip.AddrFrom4([4]byte{10, 0, 0, 0}),
				8,
			),
		},
	}

	m.ForEachZone(func(z *Zone) bool {
		for _, p := range z.GetCephMonitors() {
			addr, _ := RingOneAddress(z.ID, p.ID)

			cfg.Global.Monitors = append(cfg.Global.Monitors, p.Name)
			cfg.Global.MonitorsAddr = append(cfg.Global.MonitorsAddr, addr)
		}
		return false
	})

	return cfg, nil
}

// GetCephMonitors returns the set of Ceph monitors on
// the zone
func (z *Zone) GetCephMonitors() Machines {
	var mons Machines
	var first, second *Machine

	z.ForEachMachine(func(p *Machine) bool {
		switch {
		case p.CephMonitor:
			// it is a monitor
			mons = append(mons, p)
		case len(mons) > 0:
			// zone has a monitor
		case first == nil && !p.IsGateway():
			// first option for monitor
			first = p
		case second == nil:
			// second option for monitor
			second = p
		}

		return false
	})

	switch {
	case len(mons) > 0:
		// ready
	case first != nil:
		// make first option our monitor
		first.CephMonitor = true
		mons = append(mons, first)
	case second != nil:
		// make second option our monitor
		second.CephMonitor = true
		mons = append(mons, second)
	default:
		// zone without machines??
		panic("unreachable")
	}

	sort.Sort(mons)
	return mons
}