package profile

import (
	"fmt"
	"log"
	"sort"
	"strings"

	"github.com/tidbcloud/AgentTeam/desktop/internal/dbaas"
)

// dbaasFile is the top-level YAML wrapper for dbaas.yaml.
type dbaasFile struct {
	Services []dbaas.Service `yaml:"services"`
}

// DBaaSManager provides CRUD operations for DBaaS service configurations.
type DBaaSManager struct {
	mgr *Manager
}

// Get returns the service with the given ID.
func (dm *DBaaSManager) Get(id string) (dbaas.Service, bool) {
	dm.mgr.mu.RLock()
	defer dm.mgr.mu.RUnlock()
	s, ok := dm.mgr.dbaasServices[id]
	if !ok {
		return dbaas.Service{}, false
	}
	return *s, true
}

// All returns all DBaaS services, sorted by ID.
func (dm *DBaaSManager) All() []dbaas.Service {
	dm.mgr.mu.RLock()
	defer dm.mgr.mu.RUnlock()

	result := make([]dbaas.Service, 0, len(dm.mgr.dbaasServices))
	for _, s := range dm.mgr.dbaasServices {
		if strings.TrimSpace(s.ID) == "" {
			continue
		}
		result = append(result, *s)
	}
	sort.Slice(result, func(i, j int) bool {
		return strings.TrimSpace(result[i].ID) < strings.TrimSpace(result[j].ID)
	})
	return result
}

// Add adds a new DBaaS service configuration.
func (dm *DBaaSManager) Add(s dbaas.Service) error {
	if strings.TrimSpace(s.ID) == "" {
		s.ID = generateDBaaSID()
	}
	if err := dbaas.Validate(s); err != nil {
		return err
	}
	normalized := dbaas.Normalize(s)
	dm.mgr.mu.Lock()
	defer dm.mgr.mu.Unlock()
	if _, ok := dm.mgr.dbaasServices[normalized.ID]; ok {
		return fmt.Errorf("dbaas service %q already exists", normalized.ID)
	}
	dm.mgr.dbaasServices[normalized.ID] = &normalized
	return dm.saveDBaaSLocked()
}

// Update updates an existing DBaaS service configuration.
func (dm *DBaaSManager) Update(s dbaas.Service) error {
	if err := dbaas.Validate(s); err != nil {
		return err
	}
	normalized := dbaas.Normalize(s)
	dm.mgr.mu.Lock()
	defer dm.mgr.mu.Unlock()
	if _, ok := dm.mgr.dbaasServices[normalized.ID]; !ok {
		return fmt.Errorf("dbaas service %q not found", normalized.ID)
	}
	dm.mgr.dbaasServices[normalized.ID] = &normalized
	return dm.saveDBaaSLocked()
}

// Delete removes a DBaaS service by ID.
func (dm *DBaaSManager) Delete(id string) error {
	dm.mgr.mu.Lock()
	defer dm.mgr.mu.Unlock()
	if _, ok := dm.mgr.dbaasServices[id]; !ok {
		return fmt.Errorf("dbaas service %q not found", id)
	}
	delete(dm.mgr.dbaasServices, id)
	return dm.saveDBaaSLocked()
}

func (dm *DBaaSManager) saveDBaaSLocked() error {
	return saveDBaaSLocked(dm.mgr)
}

// saveDBaaSLocked persists the Manager's dbaasServices map to dbaas.yaml.
// The caller must hold m.mu.
func saveDBaaSLocked(m *Manager) error {
	f := dbaasFile{Services: make([]dbaas.Service, 0, len(m.dbaasServices))}
	for _, s := range m.dbaasServices {
		f.Services = append(f.Services, *s)
	}
	return saveYAMLFile(f, m.filePath("dbaas.yaml"), m)
}

// reloadDBaaS loads dbaas.yaml into the Manager's dbaasServices map.
func reloadDBaaS(m *Manager) {
	f := &dbaasFile{}
	if err := loadYAMLFile(m.filePath("dbaas.yaml"), f); err != nil {
		log.Printf("profile: load dbaas: %v", err)
	}
	services := make(map[string]*dbaas.Service, len(f.Services))
	for i := range f.Services {
		s := f.Services[i]
		services[s.ID] = &s
	}
	m.dbaasServices = services
}
