package teamsalarypolicy

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/model"
	"hyapp-admin-server/internal/repository"
)

const (
	policyTypeBD    = "bd"
	policyTypeAdmin = "admin"

	policyStatusActive   = "active"
	policyStatusDisabled = "disabled"

	settlementTriggerAutomatic = "automatic"
	settlementTriggerManual    = "manual"
)

type Service struct {
	store *repository.Store
}

func NewService(store *repository.Store) *Service {
	return &Service{store: store}
}

func (s *Service) List(appCode string, options repository.TeamSalaryPolicyListOptions) ([]policyDTO, int64, error) {
	options.AppCode = appctx.Normalize(appCode)
	options.PolicyType = normalizePolicyType(options.PolicyType)
	if options.PolicyType == "" {
		return nil, 0, errors.New("政策类型不正确")
	}
	options.Status = normalizeStatusFilter(options.Status)
	options.SettlementTriggerMode = normalizeSettlementTriggerModeFilter(options.SettlementTriggerMode)
	items, total, err := s.store.ListTeamSalaryPolicies(options)
	if err != nil {
		return nil, 0, err
	}
	out := make([]policyDTO, 0, len(items))
	for _, item := range items {
		out = append(out, policyFromModel(item))
	}
	return out, total, nil
}

func (s *Service) Create(appCode string, actorID uint, req policyRequest) (policyDTO, error) {
	item, err := policyModelFromRequest(appctx.Normalize(appCode), actorID, req)
	if err != nil {
		return policyDTO{}, err
	}
	if err := s.ensureNoActiveOverlap(item, 0); err != nil {
		return policyDTO{}, err
	}
	if err := s.store.CreateTeamSalaryPolicy(&item); err != nil {
		return policyDTO{}, err
	}
	return policyFromModel(item), nil
}

func (s *Service) Update(appCode string, actorID uint, id uint, req policyRequest) (policyDTO, error) {
	policyType := normalizePolicyType(req.PolicyType)
	if policyType == "" {
		return policyDTO{}, errors.New("政策类型不正确")
	}
	item, err := s.store.GetTeamSalaryPolicy(appctx.Normalize(appCode), policyType, id)
	if err != nil {
		return policyDTO{}, err
	}
	updated, err := policyModelFromRequest(item.AppCode, actorID, req)
	if err != nil {
		return policyDTO{}, err
	}
	item.Name = updated.Name
	item.RegionID = updated.RegionID
	item.Status = updated.Status
	item.SettlementTriggerMode = updated.SettlementTriggerMode
	item.EffectiveFromMS = updated.EffectiveFromMS
	item.EffectiveToMS = updated.EffectiveToMS
	item.Description = updated.Description
	item.UpdatedByAdminID = actorID
	item.Levels = updated.Levels
	if err := s.ensureNoActiveOverlap(item, id); err != nil {
		return policyDTO{}, err
	}
	if err := s.store.UpdateTeamSalaryPolicy(&item); err != nil {
		return policyDTO{}, err
	}
	return policyFromModel(item), nil
}

func (s *Service) Delete(appCode string, policyType string, id uint) error {
	policyType = normalizePolicyType(policyType)
	if policyType == "" {
		return errors.New("政策类型不正确")
	}
	if _, err := s.store.GetTeamSalaryPolicy(appctx.Normalize(appCode), policyType, id); err != nil {
		return err
	}
	return s.store.DeleteTeamSalaryPolicy(appctx.Normalize(appCode), policyType, id)
}

func (s *Service) ensureNoActiveOverlap(item model.TeamSalaryPolicy, excludeID uint) error {
	if item.Status != policyStatusActive {
		return nil
	}
	overlap, err := s.store.HasOverlappingActiveTeamSalaryPolicy(item.AppCode, item.PolicyType, item.RegionID, item.EffectiveFromMS, item.EffectiveToMS, excludeID)
	if err != nil {
		return err
	}
	if overlap {
		return errors.New("同一区域同一时间只能存在一个启用政策")
	}
	return nil
}

func policyModelFromRequest(appCode string, actorID uint, req policyRequest) (model.TeamSalaryPolicy, error) {
	policyType := normalizePolicyType(req.PolicyType)
	if policyType == "" {
		return model.TeamSalaryPolicy{}, errors.New("政策类型不正确")
	}
	name := strings.TrimSpace(req.Name)
	if name == "" || len([]rune(name)) > 120 {
		return model.TeamSalaryPolicy{}, errors.New("政策名称不正确")
	}
	if req.RegionID <= 0 {
		return model.TeamSalaryPolicy{}, errors.New("请选择适用区域")
	}
	status := normalizeStatus(req.Status)
	if status == "" {
		// BD/Admin 政策默认先保存为停用，运营确认等级表无误后再启用，避免自动结算读到半成品。
		status = policyStatusDisabled
	}
	if !validStatus(status) {
		return model.TeamSalaryPolicy{}, errors.New("政策状态不正确")
	}
	triggerMode := normalizeSettlementTriggerMode(req.SettlementTriggerMode)
	if triggerMode == "" {
		triggerMode = settlementTriggerAutomatic
	}
	if !validSettlementTriggerMode(triggerMode) {
		return model.TeamSalaryPolicy{}, errors.New("结算触发方式不正确")
	}
	if req.EffectiveFromMS < 0 || req.EffectiveToMS < 0 || (req.EffectiveToMS > 0 && req.EffectiveToMS <= req.EffectiveFromMS) {
		return model.TeamSalaryPolicy{}, errors.New("政策生效时间不正确")
	}
	description := strings.TrimSpace(req.Description)
	if len([]rune(description)) > 255 {
		return model.TeamSalaryPolicy{}, errors.New("备注不能超过 255 个字符")
	}
	levels, err := levelModelsFromRequest(policyType, req.Levels)
	if err != nil {
		return model.TeamSalaryPolicy{}, err
	}
	return model.TeamSalaryPolicy{
		AppCode:               appCode,
		PolicyType:            policyType,
		Name:                  name,
		RegionID:              req.RegionID,
		Status:                status,
		SettlementTriggerMode: triggerMode,
		EffectiveFromMS:       req.EffectiveFromMS,
		EffectiveToMS:         req.EffectiveToMS,
		Description:           description,
		CreatedByAdminID:      actorID,
		UpdatedByAdminID:      actorID,
		Levels:                levels,
	}, nil
}

func levelModelsFromRequest(policyType string, requests []levelRequest) ([]model.TeamSalaryLevel, error) {
	if len(requests) == 0 {
		return nil, errors.New("至少需要配置一个等级")
	}
	levels := append([]levelRequest(nil), requests...)
	sortLevelRequests(levels)
	seen := map[int32]struct{}{}
	out := make([]model.TeamSalaryLevel, 0, len(levels))
	var previousThresholdCents int64
	var previousSalaryCents int64
	for index, req := range levels {
		if req.Level <= 0 {
			return nil, errors.New("等级必须大于 0")
		}
		if _, ok := seen[req.Level]; ok {
			return nil, fmt.Errorf("等级 %d 重复", req.Level)
		}
		seen[req.Level] = struct{}{}
		threshold, thresholdCents, err := parseFixedDecimal(req.ThresholdUSD, 2, false, thresholdFieldName(policyType))
		if err != nil {
			return nil, fmt.Errorf("等级 %d %w", req.Level, err)
		}
		if index > 0 && thresholdCents <= previousThresholdCents {
			return nil, fmt.Errorf("等级 %d 收入门槛必须大于上一等级", req.Level)
		}
		// rate_percent 保存百分比文本，例如 8 表示 8%；允许 4 位小数应对后续更细比例。
		rate, _, err := parseFixedDecimal(req.RatePercent, 4, false, "提成比例")
		if err != nil {
			return nil, fmt.Errorf("等级 %d %w", req.Level, err)
		}
		salary, salaryCents, err := parseFixedDecimal(req.SalaryUSD, 2, true, salaryFieldName(policyType))
		if err != nil {
			return nil, fmt.Errorf("等级 %d %w", req.Level, err)
		}
		if index > 0 && salaryCents < previousSalaryCents {
			return nil, fmt.Errorf("等级 %d 累计工资不能小于上一等级", req.Level)
		}
		status := normalizeStatus(req.Status)
		if status == "" {
			status = policyStatusActive
		}
		if !validStatus(status) {
			return nil, fmt.Errorf("等级 %d 状态不正确", req.Level)
		}
		sortOrder := req.SortOrder
		if sortOrder == 0 {
			sortOrder = req.Level
		}
		out = append(out, model.TeamSalaryLevel{
			LevelNo:      req.Level,
			ThresholdUSD: threshold,
			RatePercent:  rate,
			SalaryUSD:    salary,
			Status:       status,
			SortOrder:    sortOrder,
		})
		previousThresholdCents = thresholdCents
		previousSalaryCents = salaryCents
	}
	return out, nil
}

func thresholdFieldName(policyType string) string {
	if policyType == policyTypeAdmin {
		return "BD工资门槛"
	}
	return "下属主播工资门槛"
}

func salaryFieldName(policyType string) string {
	if policyType == policyTypeAdmin {
		return "Admin工资"
	}
	return "BD工资"
}

func sortLevelRequests(items []levelRequest) {
	for i := 1; i < len(items); i++ {
		item := items[i]
		j := i - 1
		for j >= 0 && items[j].Level > item.Level {
			items[j+1] = items[j]
			j--
		}
		items[j+1] = item
	}
}

func parseFixedDecimal(raw string, scale int, allowZero bool, field string) (string, int64, error) {
	value := strings.TrimSpace(raw)
	if strings.HasPrefix(value, "+") {
		value = strings.TrimPrefix(value, "+")
	}
	if value == "" || strings.HasPrefix(value, "-") {
		return "", 0, fmt.Errorf("%s不正确", field)
	}
	parts := strings.Split(value, ".")
	if len(parts) > 2 || parts[0] == "" || !allDigits(parts[0]) {
		return "", 0, fmt.Errorf("%s不正确", field)
	}
	if len(parts) == 2 && (parts[1] == "" || len(parts[1]) > scale || !allDigits(parts[1])) {
		return "", 0, fmt.Errorf("%s最多支持 %d 位小数", field, scale)
	}
	whole, err := strconv.ParseInt(parts[0], 10, 64)
	if err != nil {
		return "", 0, fmt.Errorf("%s过大", field)
	}
	multiplier := pow10(scale)
	if whole > (1<<62)/multiplier {
		return "", 0, fmt.Errorf("%s过大", field)
	}
	var fraction int64
	if len(parts) == 2 {
		fractionText := parts[1] + strings.Repeat("0", scale-len(parts[1]))
		fraction, err = strconv.ParseInt(fractionText, 10, 64)
		if err != nil {
			return "", 0, fmt.Errorf("%s不正确", field)
		}
	}
	scaled := whole*multiplier + fraction
	if !allowZero && scaled <= 0 {
		return "", 0, fmt.Errorf("%s必须大于 0", field)
	}
	return strconv.FormatInt(whole, 10) + "." + fixedDigits(fraction, scale), scaled, nil
}

func fixedDigits(value int64, scale int) string {
	text := strconv.FormatInt(value, 10)
	if len(text) >= scale {
		return text
	}
	return strings.Repeat("0", scale-len(text)) + text
}

func trimDecimalZeros(value string) string {
	value = strings.TrimSpace(value)
	if !strings.Contains(value, ".") {
		return value
	}
	value = strings.TrimRight(value, "0")
	return strings.TrimRight(value, ".")
}

func pow10(scale int) int64 {
	var out int64 = 1
	for i := 0; i < scale; i++ {
		out *= 10
	}
	return out
}

func allDigits(value string) bool {
	for _, r := range value {
		if r < '0' || r > '9' {
			return false
		}
	}
	return true
}

func firstNonBlank(values ...string) string {
	for _, value := range values {
		if strings.TrimSpace(value) != "" {
			return value
		}
	}
	return ""
}

func normalizePolicyType(value string) string {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case policyTypeBD:
		return policyTypeBD
	case policyTypeAdmin, "super_admin", "super-admin":
		return policyTypeAdmin
	default:
		return ""
	}
}

func normalizeStatus(value string) string {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "", policyStatusActive, "enabled":
		if strings.TrimSpace(value) == "" {
			return ""
		}
		return policyStatusActive
	case policyStatusDisabled, "inactive":
		return policyStatusDisabled
	default:
		return strings.ToLower(strings.TrimSpace(value))
	}
}

func normalizeStatusFilter(value string) string {
	status := normalizeStatus(value)
	if !validStatus(status) {
		return ""
	}
	return status
}

func validStatus(value string) bool {
	return value == policyStatusActive || value == policyStatusDisabled
}

func normalizeSettlementTriggerMode(value string) string {
	switch strings.ToLower(strings.TrimSpace(value)) {
	case "", settlementTriggerAutomatic, "auto":
		if strings.TrimSpace(value) == "" {
			return ""
		}
		return settlementTriggerAutomatic
	case settlementTriggerManual, "manual_settlement":
		return settlementTriggerManual
	default:
		return strings.ToLower(strings.TrimSpace(value))
	}
}

func normalizeSettlementTriggerModeFilter(value string) string {
	mode := normalizeSettlementTriggerMode(value)
	if !validSettlementTriggerMode(mode) {
		return ""
	}
	return mode
}

func validSettlementTriggerMode(value string) bool {
	return value == settlementTriggerAutomatic || value == settlementTriggerManual
}
