package repository

import (
	"strings"

	"hyapp-admin-server/internal/model"

	"gorm.io/gorm"
)

type HostAgencySalaryPolicyListOptions struct {
	AppCode               string
	Keyword               string
	RegionID              int64
	Status                string
	SettlementMode        string
	SettlementTriggerMode string
	Page                  int
	PageSize              int
}

func (s *Store) ListHostAgencySalaryPolicies(options HostAgencySalaryPolicyListOptions) ([]model.HostAgencySalaryPolicy, int64, error) {
	// 工资政策是应用隔离配置，所有查询都必须先限定 app_code，再叠加运营筛选条件。
	db := s.db.Model(&model.HostAgencySalaryPolicy{}).Where("app_code = ?", strings.TrimSpace(options.AppCode))
	if options.RegionID > 0 {
		// 第一阶段仍按单区域保存，区域筛选直接命中主表索引。
		db = db.Where("region_id = ?", options.RegionID)
	}
	if status := strings.TrimSpace(options.Status); status != "" {
		db = db.Where("status = ?", status)
	}
	if mode := strings.TrimSpace(options.SettlementMode); mode != "" {
		db = db.Where("settlement_mode = ?", mode)
	}
	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.HostAgencySalaryPolicy
	// 等级必须随政策一起预加载并按 level_no 排序，前端展示和后续编辑都依赖稳定顺序。
	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) GetHostAgencySalaryPolicy(appCode string, id uint) (model.HostAgencySalaryPolicy, error) {
	var item model.HostAgencySalaryPolicy
	// 单条读取也预加载等级，更新时会用完整等级包替换原明细。
	err := s.db.Preload("Levels", func(tx *gorm.DB) *gorm.DB {
		return tx.Order("level_no ASC")
	}).Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).First(&item).Error
	return item, err
}

func (s *Store) CreateHostAgencySalaryPolicy(item *model.HostAgencySalaryPolicy) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// GORM 创建主表时不让它自动级联 levels；先拿到 policy_id，再批量写明细，约束更直观。
		levels := append([]model.HostAgencySalaryLevel(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
			}
		}
		// 恢复内存对象，service 可以把创建后的完整对象直接转成响应。
		item.Levels = levels
		return nil
	})
}

func (s *Store) UpdateHostAgencySalaryPolicy(item *model.HostAgencySalaryPolicy) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 等级是整包配置，不做逐条 diff；主表保存成功后删除旧明细，再插入新梯度。
		levels := append([]model.HostAgencySalaryLevel(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.HostAgencySalaryLevel{}).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) UpdateHostAgencySalaryPolicyPublishState(appCode string, id uint, status string, publishError string, publishedAtMS int64, actorID uint) error {
	// 发布状态属于 admin 配置到 wallet 运行快照的同步结果，不影响政策主配置字段和等级明细。
	return s.db.Model(&model.HostAgencySalaryPolicy{}).
		Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).
		Updates(map[string]any{
			"publish_status":        strings.TrimSpace(status),
			"publish_error":         strings.TrimSpace(publishError),
			"published_at_ms":       publishedAtMS,
			"published_by_admin_id": actorID,
			"updated_by_admin_id":   actorID,
		}).Error
}

func (s *Store) DeleteHostAgencySalaryPolicy(appCode string, id uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 先删明细再删主表，兼容没有外键级联的部署环境。
		if err := tx.Where("policy_id = ?", id).Delete(&model.HostAgencySalaryLevel{}).Error; err != nil {
			return err
		}
		return tx.Where("app_code = ? AND id = ?", strings.TrimSpace(appCode), id).Delete(&model.HostAgencySalaryPolicy{}).Error
	})
}

func (s *Store) HasOverlappingActiveHostAgencySalaryPolicy(appCode string, regionID int64, effectiveFromMS int64, effectiveToMS int64, excludeID uint) (bool, error) {
	// 与当前政策开始时间相交：已有长期有效或已有结束时间晚于当前开始。
	db := s.db.Model(&model.HostAgencySalaryPolicy{}).
		Where("app_code = ? AND region_id = ? AND status = ?", strings.TrimSpace(appCode), 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
}
