package repository

import (
	"strings"

	"hyapp-admin-server/internal/model"

	"gorm.io/gorm"
)

type TeamSalaryPolicyListOptions struct {
	AppCode               string
	PolicyType            string
	Keyword               string
	RegionID              int64
	Status                string
	SettlementTriggerMode string
	Page                  int
	PageSize              int
}

func (s *Store) ListTeamSalaryPolicies(options TeamSalaryPolicyListOptions) ([]model.TeamSalaryPolicy, int64, error) {
	// BD/Admin 政策共表保存，查询必须同时限定 app_code 和 policy_type，避免两个 tab 的配置互相混入。
	db := s.db.Model(&model.TeamSalaryPolicy{}).
		Where("app_code = ? AND policy_type = ?", strings.TrimSpace(options.AppCode), strings.TrimSpace(options.PolicyType))
	if options.RegionID > 0 {
		db = db.Where("region_id = ?", options.RegionID)
	}
	if status := strings.TrimSpace(options.Status); status != "" {
		db = db.Where("status = ?", status)
	}
	if triggerMode := strings.TrimSpace(options.SettlementTriggerMode); triggerMode != "" {
		db = db.Where("settlement_trigger_mode = ?", triggerMode)
	}
	if keyword := strings.TrimSpace(options.Keyword); keyword != "" {
		like := "%" + keyword + "%"
		db = db.Where("name LIKE ? OR description LIKE ?", like, like)
	}

	var total int64
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	page, pageSize := normalizePage(options.Page, options.PageSize)
	var items []model.TeamSalaryPolicy
	err := db.Preload("Levels", func(tx *gorm.DB) *gorm.DB {
		// 等级顺序是差额结算的业务顺序，列表和编辑都必须使用同一排序。
		return tx.Order("level_no ASC")
	}).Order("region_id ASC, effective_from_ms DESC, id DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&items).Error
	return items, total, err
}

func (s *Store) GetTeamSalaryPolicy(appCode string, policyType string, id uint) (model.TeamSalaryPolicy, error) {
	var item model.TeamSalaryPolicy
	err := s.db.Preload("Levels", func(tx *gorm.DB) *gorm.DB {
		return tx.Order("level_no ASC")
	}).Where("app_code = ? AND policy_type = ? AND id = ?", strings.TrimSpace(appCode), strings.TrimSpace(policyType), id).First(&item).Error
	return item, err
}

func (s *Store) CreateTeamSalaryPolicy(item *model.TeamSalaryPolicy) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 主表和等级整包保存，避免部分等级成功造成一套不可结算的政策梯度。
		levels := append([]model.TeamSalaryLevel(nil), item.Levels...)
		item.Levels = nil
		if err := tx.Create(item).Error; err != nil {
			return err
		}
		for index := range levels {
			levels[index].PolicyID = item.ID
		}
		if len(levels) > 0 {
			if err := tx.Create(&levels).Error; err != nil {
				return err
			}
		}
		item.Levels = levels
		return nil
	})
}

func (s *Store) UpdateTeamSalaryPolicy(item *model.TeamSalaryPolicy) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 编辑按整包替换等级，保证 UI 提交内容就是下一次结算读取的完整梯度。
		levels := append([]model.TeamSalaryLevel(nil), item.Levels...)
		item.Levels = nil
		if err := tx.Save(item).Error; err != nil {
			return err
		}
		if err := tx.Where("policy_id = ?", item.ID).Delete(&model.TeamSalaryLevel{}).Error; err != nil {
			return err
		}
		for index := range levels {
			levels[index].ID = 0
			levels[index].PolicyID = item.ID
		}
		if len(levels) > 0 {
			if err := tx.Create(&levels).Error; err != nil {
				return err
			}
		}
		item.Levels = levels
		return nil
	})
}

func (s *Store) DeleteTeamSalaryPolicy(appCode string, policyType string, id uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Where("policy_id = ?", id).Delete(&model.TeamSalaryLevel{}).Error; err != nil {
			return err
		}
		return tx.Where("app_code = ? AND policy_type = ? AND id = ?", strings.TrimSpace(appCode), strings.TrimSpace(policyType), id).Delete(&model.TeamSalaryPolicy{}).Error
	})
}

func (s *Store) HasOverlappingActiveTeamSalaryPolicy(appCode string, policyType string, regionID int64, effectiveFromMS int64, effectiveToMS int64, excludeID uint) (bool, error) {
	// 同一类型、同一区域、同一时间只能有一条启用政策，避免结算时 BD/Admin 可命中多套比例。
	db := s.db.Model(&model.TeamSalaryPolicy{}).
		Where("app_code = ? AND policy_type = ? AND region_id = ? AND status = ?", strings.TrimSpace(appCode), strings.TrimSpace(policyType), regionID, "active").
		Where("(effective_to_ms = 0 OR effective_to_ms > ?)", effectiveFromMS)
	if effectiveToMS > 0 {
		db = db.Where("effective_from_ms < ?", effectiveToMS)
	}
	if excludeID > 0 {
		db = db.Where("id <> ?", excludeID)
	}
	var count int64
	if err := db.Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}
