package service

import (
	"errors"

	"nex/backend/internal/domain"
	"nex/backend/internal/repository"

	"github.com/google/uuid"
	"gorm.io/gorm"

	appErrors "nex/backend/pkg/errors"
)

type modelService struct {
	modelRepo    repository.ModelRepository
	providerRepo repository.ProviderRepository
	cache        *RoutingCache
}

func NewModelService(modelRepo repository.ModelRepository, providerRepo repository.ProviderRepository, cache *RoutingCache) ModelService {
	return &modelService{modelRepo: modelRepo, providerRepo: providerRepo, cache: cache}
}

func (s *modelService) Create(model *domain.Model) error {
	if _, err := s.providerRepo.GetByID(model.ProviderID); err != nil {
		return appErrors.ErrProviderNotFound
	}

	if err := s.checkDuplicateModelName(model.ProviderID, model.ModelName, ""); err != nil {
		return err
	}

	model.ID = uuid.New().String()
	model.Enabled = true
	err := s.modelRepo.Create(model)
	if err != nil {
		return err
	}
	s.cache.SetModel(model)
	return nil
}

func (s *modelService) Get(id string) (*domain.Model, error) {
	return s.modelRepo.GetByID(id)
}

func (s *modelService) List(providerID string) ([]domain.Model, error) {
	return s.modelRepo.List(providerID)
}

func (s *modelService) ListEnabled() ([]domain.Model, error) {
	return s.modelRepo.ListEnabled()
}

func (s *modelService) Update(id string, updates map[string]interface{}) error {
	current, err := s.modelRepo.GetByID(id)
	if err != nil {
		return appErrors.ErrModelNotFound
	}

	if providerID, ok := updates["provider_id"].(string); ok {
		if _, err := s.providerRepo.GetByID(providerID); err != nil {
			return appErrors.ErrProviderNotFound
		}
	}

	newProviderID := current.ProviderID
	if v, ok := updates["provider_id"].(string); ok {
		newProviderID = v
	}
	newModelName := current.ModelName
	if v, ok := updates["model_name"].(string); ok {
		newModelName = v
	}

	if newProviderID != current.ProviderID || newModelName != current.ModelName {
		if err := s.checkDuplicateModelName(newProviderID, newModelName, id); err != nil {
			return err
		}
	}

	err = s.modelRepo.Update(id, updates)
	if err != nil {
		return err
	}

	s.cache.InvalidateModel(current.ProviderID, current.ModelName)
	if newProviderID != current.ProviderID || newModelName != current.ModelName {
		s.cache.InvalidateModel(newProviderID, newModelName)
	}
	return nil
}

func (s *modelService) Delete(id string) error {
	model, err := s.modelRepo.GetByID(id)
	if err != nil {
		return appErrors.ErrModelNotFound
	}

	err = s.modelRepo.Delete(id)
	if err != nil {
		return err
	}

	s.cache.InvalidateModel(model.ProviderID, model.ModelName)
	return nil
}

// checkDuplicateModelName 校验同一供应商下 model_name 是否重复
// excludeID 用于更新时排除自身
func (s *modelService) checkDuplicateModelName(providerID, modelName, excludeID string) error {
	existing, err := s.modelRepo.FindByProviderAndModelName(providerID, modelName)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil // 未找到，不重复
		}

		return err
	}
	if excludeID != "" && existing.ID == excludeID {
		return nil // 排除自身
	}
	return appErrors.ErrDuplicateModel
}
