package cluster

import (
	"os"

	"darvaza.org/slog"

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

type cephScanTODO struct {
	names map[string]bool
	addrs map[string]bool
}

func (todo *cephScanTODO) checkMachine(p *Machine) bool {
	// on ceph all addresses are ring1
	addr := p.RingOneAddress().String()

	if _, found := todo.names[p.Name]; found {
		// found on the TODO by name
		todo.names[p.Name] = true
		todo.addrs[addr] = true
		return true
	}

	if _, found := todo.addrs[addr]; found {
		// found on the TODO by address
		todo.names[p.Name] = true
		todo.addrs[addr] = true
		return true
	}

	return false
}

func (todo *cephScanTODO) LogMissing(log slog.Logger) {
	for name, found := range todo.names {
		if !found {
			log.Warn().
				WithField("subsystem", "ceph").
				WithField("monitor", name).
				Print("unknown monitor")
		}
	}

	for addr, found := range todo.addrs {
		if !found {
			log.Warn().
				WithField("subsystem", "ceph").
				WithField("monitor", addr).
				Print("unknown monitor")
		}
	}
}

func newCephScanTODO(cfg *ceph.Config) *cephScanTODO {
	todo := &cephScanTODO{
		names: make(map[string]bool),
		addrs: make(map[string]bool),
	}

	for _, name := range cfg.Global.Monitors {
		todo.names[name] = false
	}

	for _, addr := range cfg.Global.MonitorsAddr {
		todo.addrs[addr.String()] = false
	}

	return todo
}

func (m *Cluster) scanCephMonitors(opts *ScanOptions) error {
	cfg, err := m.GetCephConfig()
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	if cfg != nil {
		// store FSID
		m.CephFSID = cfg.Global.FSID

		// flag monitors based on config
		todo := newCephScanTODO(cfg)
		m.ForEachMachine(func(p *Machine) bool {
			p.CephMonitor = todo.checkMachine(p)
			return false
		})

		todo.LogMissing(m.log)
	}

	return m.initCephMonitors(opts)
}

func (m *Cluster) initCephMonitors(_ *ScanOptions) error {
	// make sure every zone has one
	m.ForEachZone(func(z *Zone) bool {
		_ = z.GetCephMonitors()
		return false
	})
	return nil
}