package systemconfig

import (
	"encoding/json"
	"errors"
	"strings"
)

var (
	ErrDependencyUnavailable = errors.New("dependency unavailable")
	ErrInvalidConfig         = errors.New("invalid config")
)

type Service struct {
	repo *Repository
}

func NewService(repo *Repository) *Service {
	return &Service{repo: repo}
}

func (s *Service) List() ([]ConfigDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	return s.repo.List()
}

func (s *Service) PublishOptions() (*PublishOptionsDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	options, err := s.publishOptions()
	if err != nil {
		return nil, err
	}
	return &options, nil
}

func (s *Service) SalePriceConfig() (*PublishSalePriceConfig, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	config, err := s.salePriceConfig()
	if err != nil {
		return nil, err
	}
	return &config, nil
}

func (s *Service) OrderAgreements() (*OrderAgreementsDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	agreements, err := s.orderAgreements()
	if err != nil {
		return nil, err
	}
	return &agreements, nil
}

func (s *Service) PostRentalNotice() (*PostRentalNoticeDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	notice, err := s.postRentalNotice()
	if err != nil {
		return nil, err
	}
	return &notice, nil
}

func (s *Service) publishOptions() (PublishOptionsDTO, error) {
	value, err := s.repo.FindValue(publishOptionsConfigKey)
	if err != nil {
		return PublishOptionsDTO{}, err
	}
	options := DefaultPublishOptions()
	if err := json.Unmarshal([]byte(value), &options); err != nil {
		options = DefaultPublishOptions()
	}
	normalizePublishOptions(&options)
	return options, nil
}

func (s *Service) salePriceConfig() (PublishSalePriceConfig, error) {
	value, err := s.repo.FindValue(salePriceConfigKey)
	if err != nil {
		return PublishSalePriceConfig{}, err
	}
	config := DefaultSalePriceConfig()
	if err := json.Unmarshal([]byte(value), &config); err != nil {
		config = DefaultSalePriceConfig()
	}
	normalizeSalePriceConfig(&config)
	return config, nil
}

func (s *Service) orderAgreements() (OrderAgreementsDTO, error) {
	value, err := s.repo.FindValue(orderAgreementsConfigKey)
	if err != nil {
		return OrderAgreementsDTO{}, err
	}
	agreements := DefaultOrderAgreements()
	if err := json.Unmarshal([]byte(value), &agreements); err != nil {
		agreements = DefaultOrderAgreements()
	}
	normalizeOrderAgreements(&agreements)
	return agreements, nil
}

func (s *Service) postRentalNotice() (PostRentalNoticeDTO, error) {
	value, err := s.repo.FindValue(postRentalNoticeConfigKey)
	if err != nil {
		return PostRentalNoticeDTO{}, err
	}
	notice := DefaultPostRentalNotice()
	if err := json.Unmarshal([]byte(value), &notice); err != nil {
		notice = DefaultPostRentalNotice()
	}
	normalizePostRentalNotice(&notice)
	return notice, nil
}

func (s *Service) HomeAnnouncements() (*HomeAnnouncementsDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	items, err := s.homeAnnouncements()
	if err != nil {
		return nil, err
	}
	return &HomeAnnouncementsDTO{Items: items}, nil
}

func (s *Service) HomeConfig() (*HomeConfigDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	announcements, err := s.homeAnnouncements()
	if err != nil {
		return nil, err
	}
	banners, err := s.homeBanners()
	if err != nil {
		return nil, err
	}
	publishOptions, err := s.publishOptions()
	if err != nil {
		return nil, err
	}
	return &HomeConfigDTO{
		Announcements:  announcements,
		Banners:        banners,
		PublishOptions: publishOptions,
	}, nil
}

func (s *Service) homeAnnouncements() ([]string, error) {
	value, err := s.repo.FindValue(homeAnnouncementsConfigKey)
	if err != nil {
		return nil, err
	}
	items := defaultHomeAnnouncements()
	if err := json.Unmarshal([]byte(value), &items); err != nil {
		items = defaultHomeAnnouncements()
	}
	return normalizeAnnouncements(items), nil
}

func (s *Service) homeBanners() ([]HomeBannerItem, error) {
	value, err := s.repo.FindValue(homeBannersConfigKey)
	if err != nil {
		return nil, err
	}
	items := defaultHomeBanners()
	if err := json.Unmarshal([]byte(value), &items); err != nil {
		items = defaultHomeBanners()
	}
	return normalizeHomeBanners(items), nil
}

func (s *Service) Update(actorID uint64, key string, req UpdateRequest, meta AuditMeta) (*ConfigDTO, error) {
	if s.repo == nil {
		return nil, ErrDependencyUnavailable
	}
	if key == "" || req.Value == "" {
		return nil, ErrInvalidConfig
	}
	return s.repo.Update(actorID, key, req, meta)
}

func normalizeAnnouncements(items []string) []string {
	normalized := make([]string, 0, len(items))
	for _, item := range items {
		item = strings.TrimSpace(item)
		if item != "" {
			normalized = append(normalized, item)
		}
	}
	if len(normalized) == 0 {
		return defaultHomeAnnouncements()
	}
	return normalized
}

func normalizeHomeBanners(items []HomeBannerItem) []HomeBannerItem {
	normalized := make([]HomeBannerItem, 0, len(items))
	for _, item := range items {
		item.Eyebrow = strings.TrimSpace(item.Eyebrow)
		item.Title = strings.TrimSpace(item.Title)
		item.Badge = strings.TrimSpace(item.Badge)
		item.Pill = strings.TrimSpace(item.Pill)
		item.Tone = strings.TrimSpace(item.Tone)
		item.ImageURL = strings.TrimSpace(item.ImageURL)
		if item.Title == "" && item.ImageURL == "" {
			continue
		}
		if item.Tone != "green" && item.Tone != "orange" {
			item.Tone = "blue"
		}
		normalized = append(normalized, item)
	}
	if len(normalized) == 0 {
		return defaultHomeBanners()
	}
	return normalized
}

func normalizeOrderAgreements(agreements *OrderAgreementsDTO) {
	defaults := DefaultOrderAgreements()
	agreements.VirtualAssetPurchase.Title = strings.TrimSpace(agreements.VirtualAssetPurchase.Title)
	agreements.VirtualAssetPurchase.Content = strings.TrimSpace(agreements.VirtualAssetPurchase.Content)
	agreements.RenterAgreement.Title = strings.TrimSpace(agreements.RenterAgreement.Title)
	agreements.RenterAgreement.Content = strings.TrimSpace(agreements.RenterAgreement.Content)
	if agreements.VirtualAssetPurchase.Title == "" {
		agreements.VirtualAssetPurchase.Title = defaults.VirtualAssetPurchase.Title
	}
	if agreements.VirtualAssetPurchase.Content == "" {
		agreements.VirtualAssetPurchase.Content = defaults.VirtualAssetPurchase.Content
	}
	if agreements.RenterAgreement.Title == "" {
		agreements.RenterAgreement.Title = defaults.RenterAgreement.Title
	}
	if agreements.RenterAgreement.Content == "" {
		agreements.RenterAgreement.Content = defaults.RenterAgreement.Content
	}
}

func normalizePostRentalNotice(notice *PostRentalNoticeDTO) {
	defaults := DefaultPostRentalNotice()
	notice.Title = strings.TrimSpace(notice.Title)
	notice.Content = strings.TrimSpace(notice.Content)
	if notice.Title == "" {
		notice.Title = defaults.Title
	}
	if notice.Content == "" {
		notice.Content = defaults.Content
	}
}

func normalizePublishOptions(options *PublishOptionsDTO) {
	defaults := DefaultPublishOptions()
	if len(options.ServerOptions) == 0 {
		options.ServerOptions = defaults.ServerOptions
	}
	if len(options.FaceOptions) == 0 {
		options.FaceOptions = defaults.FaceOptions
	}
	if len(options.RankOptions) == 0 {
		options.RankOptions = defaults.RankOptions
	}
	if len(options.InsuranceOptions) == 0 {
		options.InsuranceOptions = defaults.InsuranceOptions
	}
	if len(options.LevelOptions) == 0 {
		options.LevelOptions = defaults.LevelOptions
	}
	if len(options.LoginMethodOptions) == 0 {
		options.LoginMethodOptions = defaults.LoginMethodOptions
	}
	if len(options.RegionOptions) == 0 {
		options.RegionOptions = defaults.RegionOptions
	}
	if len(options.SkinGroups) == 0 {
		options.SkinGroups = defaults.SkinGroups
	}
	if len(options.QuantityItems) == 0 {
		options.QuantityItems = defaults.QuantityItems
	}
	if len(options.ScreenshotSlots) == 0 {
		options.ScreenshotSlots = defaults.ScreenshotSlots
	}
	if len(options.BanRecordOptions) == 0 {
		options.BanRecordOptions = defaults.BanRecordOptions
	}
	if len(options.BanEvidenceOptions) == 0 {
		options.BanEvidenceOptions = defaults.BanEvidenceOptions
	}
	if options.FireLevelMin <= 0 {
		options.FireLevelMin = defaults.FireLevelMin
	}
	if options.PriceConfig.DepositPlaceholder == "" {
		options.PriceConfig.DepositPlaceholder = defaults.PriceConfig.DepositPlaceholder
	}
	if options.PriceConfig.PricePlaceholder == "" {
		options.PriceConfig.PricePlaceholder = defaults.PriceConfig.PricePlaceholder
	}
	if options.PriceConfig.RatioDescription == "" {
		options.PriceConfig.RatioDescription = defaults.PriceConfig.RatioDescription
	}
	if options.DepositRecommend.BaseAmount <= 0 {
		options.DepositRecommend.BaseAmount = defaults.DepositRecommend.BaseAmount
	}
	if len(options.DepositRecommend.SkinGroupRules) == 0 {
		options.DepositRecommend.SkinGroupRules = defaults.DepositRecommend.SkinGroupRules
	}
	if len(options.RatioConfig.InsuranceBaseRatios) == 0 {
		options.RatioConfig.InsuranceBaseRatios = defaults.RatioConfig.InsuranceBaseRatios
	}
	if len(options.RatioConfig.ConfigItems) == 0 {
		options.RatioConfig.ConfigItems = defaults.RatioConfig.ConfigItems
	}
	if len(options.RatioConfig.CoinCorrections) == 0 {
		options.RatioConfig.CoinCorrections = defaults.RatioConfig.CoinCorrections
	}
}

func normalizeSalePriceConfig(config *PublishSalePriceConfig) {
	defaults := DefaultSalePriceConfig()
	if len(config.FixedMarkupRules) == 0 {
		config.FixedMarkupRules = defaults.FixedMarkupRules
	}
	if len(config.RatioAdjustmentRules) == 0 {
		config.RatioAdjustmentRules = defaults.RatioAdjustmentRules
	}
}
