package model

import (
	"errors"
	"fmt"
	"strings"

	"github.com/QuantumNous/new-api/common"

	"gorm.io/gorm"
)

// 分销商申请状态：1=待审核 2=已通过 3=已驳回
const (
	DistributorAppStatusPending    = 1
	DistributorAppStatusApproved   = 2
	DistributorAppStatusRejected   = 3
	DistributorApplyTypePersonal   = 1 // 个人申请：real_name=姓名，id_card_no=身份证
	DistributorApplyTypeEnterprise = 2 // 企业申请：real_name=企业名称，id_card_no=统一社会信用代码
)

// DistributorApplication 分销商入驻申请（每个用户最多一条记录，驳回后可更新重新提交）
type DistributorApplication struct {
	Id                int    `json:"id" gorm:"primaryKey;autoIncrement"`
	UserId            int    `json:"user_id" gorm:"not null;uniqueIndex:idx_dist_app_user"`
	ApplyType         int    `json:"apply_type" gorm:"type:int;not null;default:1;column:apply_type"` // 1=个人 2=企业
	RealName          string `json:"real_name" gorm:"type:varchar(64);not null;column:real_name"`
	IdCardNo          string `json:"id_card_no" gorm:"type:varchar(32);not null;column:id_card_no"`
	QualificationUrls string `json:"qualification_urls" gorm:"type:text;not null;column:qualification_urls"` // JSON 数组 URL 字符串
	Contact           string `json:"contact" gorm:"type:varchar(128);not null;column:contact"`
	Status            int    `json:"status" gorm:"type:int;not null;default:1;index:idx_dist_app_status"`
	RejectReason      string `json:"reject_reason" gorm:"type:varchar(512);column:reject_reason"`
	ReviewerId        int    `json:"reviewer_id" gorm:"column:reviewer_id"`
	ReviewedAt        int64  `json:"reviewed_at" gorm:"column:reviewed_at"`
	CreatedAt         int64  `json:"created_at" gorm:"autoCreateTime;bigint"`
	UpdatedAt         int64  `json:"updated_at" gorm:"autoUpdateTime;bigint"`
}

func (DistributorApplication) TableName() string {
	return "distributor_applications"
}

func distributorQualificationURLsNonEmpty(jsonStr string) bool {
	raw := strings.TrimSpace(jsonStr)
	if raw == "" {
		return false
	}
	var urls []string
	if common.UnmarshalJsonStr(raw, &urls) != nil {
		return false
	}
	for _, u := range urls {
		if strings.TrimSpace(u) != "" {
			return true
		}
	}
	return false
}

// NormalizeDistributorQualificationURLsJSON 解析并规范化资格证书 JSON 数组字符串
func NormalizeDistributorQualificationURLsJSON(raw string) (string, error) {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return "[]", nil
	}
	var urls []string
	if err := common.UnmarshalJsonStr(raw, &urls); err != nil {
		return "", errors.New("资格证书格式无效")
	}
	out := make([]string, 0, len(urls))
	for _, u := range urls {
		u = strings.TrimSpace(u)
		if u != "" {
			out = append(out, u)
		}
	}
	b, err := common.Marshal(out)
	if err != nil {
		return "", err
	}
	return string(b), nil
}

// UpsertDistributorApplication 用户提交或驳回后重新提交
func UpsertDistributorApplication(userId, applyType int, realName, idCardNo, qualificationUrlsJSON, contact string) error {
	if userId <= 0 {
		return errors.New("invalid user")
	}
	if applyType != DistributorApplyTypePersonal && applyType != DistributorApplyTypeEnterprise {
		return errors.New("申请类型无效")
	}
	realName = strings.TrimSpace(realName)
	idCardNo = strings.TrimSpace(idCardNo)
	contact = strings.TrimSpace(contact)
	qualJSON, err := NormalizeDistributorQualificationURLsJSON(qualificationUrlsJSON)
	if err != nil {
		return err
	}
	if !distributorQualificationURLsNonEmpty(qualJSON) {
		return errors.New("请上传资格证书")
	}
	if realName == "" || idCardNo == "" || contact == "" {
		return errors.New("请填写完整资料")
	}
	u, err := GetUserById(userId, false)
	if err != nil {
		return err
	}
	if UserIsDistributor(u) {
		return errors.New("您已是分销商")
	}
	if u.Role >= common.RoleAdminUser {
		return errors.New("管理员无需申请")
	}
	var app DistributorApplication
	err = DB.Where("user_id = ?", userId).First(&app).Error
	ts := common.GetTimestamp()
	if errors.Is(err, gorm.ErrRecordNotFound) {
		app = DistributorApplication{
			UserId:            userId,
			ApplyType:         applyType,
			RealName:          realName,
			IdCardNo:          idCardNo,
			QualificationUrls: qualJSON,
			Contact:           contact,
			Status:            DistributorAppStatusPending,
			CreatedAt:         ts,
			UpdatedAt:         ts,
		}
		return DB.Create(&app).Error
	}
	if err != nil {
		return err
	}
	if app.Status == DistributorAppStatusPending {
		return errors.New("申请正在审核中，请耐心等待")
	}
	if app.Status == DistributorAppStatusApproved {
		// 记录仍为「已通过」，但账号已被取消分销商资格时需允许再次提交（与驳回后重提相同，重置为待审核）
		if UserIsDistributor(u) {
			return errors.New("申请已通过")
		}
		app.ApplyType = applyType
		app.RealName = realName
		app.IdCardNo = idCardNo
		app.QualificationUrls = qualJSON
		app.Contact = contact
		app.Status = DistributorAppStatusPending
		app.RejectReason = ""
		app.ReviewerId = 0
		app.ReviewedAt = 0
		app.UpdatedAt = ts
		return DB.Save(&app).Error
	}
	// rejected -> resubmit
	app.ApplyType = applyType
	app.RealName = realName
	app.IdCardNo = idCardNo
	app.QualificationUrls = qualJSON
	app.Contact = contact
	app.Status = DistributorAppStatusPending
	app.RejectReason = ""
	app.ReviewerId = 0
	app.ReviewedAt = 0
	app.UpdatedAt = ts
	return DB.Save(&app).Error
}

// GetDistributorWithdrawAccountType 提现账户类型与主体名称（来自入驻申请，无申请时默认个人）
func GetDistributorWithdrawAccountType(userId int) (accountType int, subjectName string, err error) {
	accountType = DistributorApplyTypePersonal
	app, err := GetDistributorApplicationByUserId(userId)
	if err != nil {
		return 0, "", err
	}
	if app == nil {
		return accountType, "", nil
	}
	if app.ApplyType == DistributorApplyTypeEnterprise {
		accountType = DistributorApplyTypeEnterprise
	}
	return accountType, strings.TrimSpace(app.RealName), nil
}

// GetDistributorApplicationByUserId 当前用户申请记录
func GetDistributorApplicationByUserId(userId int) (*DistributorApplication, error) {
	if userId <= 0 {
		return nil, errors.New("invalid user")
	}
	var apps []DistributorApplication
	if err := DB.Where("user_id = ?", userId).Limit(1).Find(&apps).Error; err != nil {
		return nil, err
	}
	if len(apps) == 0 {
		return nil, nil
	}
	return &apps[0], nil
}

// DistributorApplicationListQuery 管理端筛选
type DistributorApplicationListQuery struct {
	Keyword   string
	Status    int // 0 = 全部
	ApplyType int // 0 = 全部 1=个人 2=企业
	DateFrom  int64
	DateTo    int64
	PageInfo  *common.PageInfo
}

// ListDistributorApplicationsAdmin 分页列表（keyword 匹配姓名、用户名、联系方式）
func ListDistributorApplicationsAdmin(q DistributorApplicationListQuery) ([]DistributorApplication, []string, int64, error) {
	tx := DB.Model(&DistributorApplication{}).Joins("LEFT JOIN users ON users.id = distributor_applications.user_id")
	if q.Status > 0 {
		tx = tx.Where("distributor_applications.status = ?", q.Status)
	}
	if q.ApplyType == DistributorApplyTypePersonal || q.ApplyType == DistributorApplyTypeEnterprise {
		tx = tx.Where("distributor_applications.apply_type = ?", q.ApplyType)
	}
	if q.DateFrom > 0 {
		tx = tx.Where("distributor_applications.created_at >= ?", q.DateFrom)
	}
	if q.DateTo > 0 {
		tx = tx.Where("distributor_applications.created_at <= ?", q.DateTo)
	}
	kw := strings.TrimSpace(q.Keyword)
	if kw != "" {
		pattern := "%" + kw + "%"
		tx = tx.Where(
			"(distributor_applications.real_name LIKE ? OR distributor_applications.contact LIKE ? OR distributor_applications.id_card_no LIKE ? OR users.username LIKE ?)",
			pattern, pattern, pattern, pattern,
		)
	}
	var total int64
	if err := tx.Count(&total).Error; err != nil {
		return nil, nil, 0, err
	}
	var rows []DistributorApplication
	pi := q.PageInfo
	if pi == nil {
		pi = &common.PageInfo{}
	}
	err := tx.Select("distributor_applications.*").
		Order("distributor_applications.id desc").
		Limit(pi.GetPageSize()).
		Offset(pi.GetStartIdx()).
		Find(&rows).Error
	if err != nil {
		return nil, nil, 0, err
	}
	usernames := make([]string, len(rows))
	for i := range rows {
		var u User
		if e := DB.Select("username").Where("id = ?", rows[i].UserId).First(&u).Error; e == nil {
			usernames[i] = u.Username
		}
	}
	return rows, usernames, total, nil
}

// GetDistributorApplicationByIdAdmin 详情
func GetDistributorApplicationByIdAdmin(id int) (*DistributorApplication, string, error) {
	if id <= 0 {
		return nil, "", errors.New("invalid id")
	}
	var app DistributorApplication
	if err := DB.Where("id = ?", id).First(&app).Error; err != nil {
		return nil, "", err
	}
	var u User
	_ = DB.Select("username").Where("id = ?", app.UserId).First(&u).Error
	return &app, u.Username, nil
}

// ApproveDistributorApplication 通过：用户角色改为分销商，申请状态已通过。
// distributorCommissionBps 非 nil 时写入该用户的 distributor_commission_bps（0～10000，万分之一；0 表示跟随系统默认）；nil 表示不修改该字段（兼容无请求体调用）。
func ApproveDistributorApplication(appId, reviewerId int, distributorCommissionBps *int) error {
	if appId <= 0 || reviewerId <= 0 {
		return errors.New("invalid params")
	}
	return DB.Transaction(func(tx *gorm.DB) error {
		var app DistributorApplication
		if err := tx.Where("id = ?", appId).First(&app).Error; err != nil {
			return err
		}
		if app.Status != DistributorAppStatusPending {
			return errors.New("申请状态不是待审核")
		}
		var u User
		if err := tx.Where("id = ?", app.UserId).First(&u).Error; err != nil {
			return err
		}
		if u.Role >= common.RoleAdminUser {
			return errors.New("不能将管理员设为分销商")
		}
		if UserIsDistributor(&u) {
			return errors.New("用户已是分销商")
		}
		ts := common.GetTimestamp()
		app.Status = DistributorAppStatusApproved
		app.ReviewerId = reviewerId
		app.ReviewedAt = ts
		app.RejectReason = ""
		if err := tx.Save(&app).Error; err != nil {
			return err
		}
		if err := tx.Model(&User{}).Where("id = ?", app.UserId).Update("is_distributor", common.DistributorFlagYes).Error; err != nil {
			return err
		}
		if distributorCommissionBps != nil {
			b := *distributorCommissionBps
			if b < 0 || b > 10000 {
				return fmt.Errorf("commission bps must be 0..10000")
			}
			if err := tx.Model(&User{}).Where("id = ?", app.UserId).Update("distributor_commission_bps", b).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

// RejectDistributorApplication 驳回
func RejectDistributorApplication(appId, reviewerId int, reason string) error {
	reason = strings.TrimSpace(reason)
	if appId <= 0 || reviewerId <= 0 {
		return errors.New("invalid params")
	}
	if reason == "" {
		return errors.New("请填写驳回原因")
	}
	if len(reason) > 500 {
		return errors.New("驳回原因过长")
	}
	var app DistributorApplication
	if err := DB.Where("id = ?", appId).First(&app).Error; err != nil {
		return err
	}
	if app.Status != DistributorAppStatusPending {
		return errors.New("申请状态不是待审核")
	}
	ts := common.GetTimestamp()
	app.Status = DistributorAppStatusRejected
	app.RejectReason = reason
	app.ReviewerId = reviewerId
	app.ReviewedAt = ts
	return DB.Save(&app).Error
}

// DistributorAdminListItem 管理端分销商列表行（含申请真实姓名、是否需补录资料）
type DistributorAdminListItem struct {
	User
	ApplicationRealName  string `json:"application_real_name"`
	ApplicationApplyType int    `json:"application_apply_type"` // 无申请记录时为 0
	NeedsSupplement      bool   `json:"needs_supplement"`
}

// DistributorListAdminQuery 管理端代理人员列表筛选
type DistributorListAdminQuery struct {
	Keyword   string
	ApplyType int // 0=全部 1=个人 2=企业
	PageInfo  *common.PageInfo
}

// ListDistributorsAdmin 分销商用户列表（LEFT JOIN 申请资料；关键字可搜用户名、显示名、申请姓名、联系方式、身份证）
func ListDistributorsAdmin(param DistributorListAdminQuery) ([]DistributorAdminListItem, int64, error) {
	tx := DB.Table("users").
		Joins("LEFT JOIN distributor_applications ON distributor_applications.user_id = users.id").
		Where("users.is_distributor = ? AND users.role < ?", common.DistributorFlagYes, common.RoleAdminUser)
	if param.ApplyType == DistributorApplyTypePersonal || param.ApplyType == DistributorApplyTypeEnterprise {
		tx = tx.Where("distributor_applications.apply_type = ?", param.ApplyType)
	}
	kw := strings.TrimSpace(param.Keyword)
	if kw != "" {
		pattern := "%" + kw + "%"
		tx = tx.Where(
			"(users.username LIKE ? OR users.display_name LIKE ? OR distributor_applications.real_name LIKE ? OR distributor_applications.contact LIKE ? OR distributor_applications.id_card_no LIKE ?)",
			pattern, pattern, pattern, pattern, pattern,
		)
	}
	var total int64
	if err := tx.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	pageInfo := param.PageInfo
	if pageInfo == nil {
		pageInfo = &common.PageInfo{}
	}
	type distAdminScan struct {
		User
		AppRealName  string `gorm:"column:app_rn"`
		AppIdCard    string `gorm:"column:app_ic"`
		AppContact   string `gorm:"column:app_ct"`
		AppQual      string `gorm:"column:app_ql"`
		AppApplyType int    `gorm:"column:app_at"`
	}
	var scans []distAdminScan
	err := tx.Select(`users.*, distributor_applications.real_name AS app_rn, distributor_applications.id_card_no AS app_ic, distributor_applications.contact AS app_ct, distributor_applications.qualification_urls AS app_ql, COALESCE(distributor_applications.apply_type, 1) AS app_at`).
		Order("users.id DESC").
		Limit(pageInfo.GetPageSize()).
		Offset(pageInfo.GetStartIdx()).
		Scan(&scans).Error
	if err != nil {
		return nil, 0, err
	}
	out := make([]DistributorAdminListItem, 0, len(scans))
	for i := range scans {
		s := scans[i]
		fake := &DistributorApplication{
			ApplyType:         s.AppApplyType,
			RealName:          s.AppRealName,
			IdCardNo:          s.AppIdCard,
			Contact:           s.AppContact,
			QualificationUrls: s.AppQual,
		}
		rn := strings.TrimSpace(s.AppRealName)
		out = append(out, DistributorAdminListItem{
			User:                 s.User,
			ApplicationRealName:  rn,
			ApplicationApplyType: s.AppApplyType,
			NeedsSupplement:      !IsDistributorApplicationProfileComplete(fake),
		})
	}
	return out, total, nil
}

// SetUserDistributorCommissionBps 管理员设置单个分销商默认分成比例（万分之一）
func SetUserDistributorCommissionBps(userId, bps int) error {
	if userId <= 0 {
		return errors.New("invalid user")
	}
	if bps < 0 || bps > 10000 {
		return fmt.Errorf("commission bps must be 0..10000")
	}
	var u User
	if err := DB.Where("id = ?", userId).First(&u).Error; err != nil {
		return err
	}
	if !UserIsDistributor(&u) {
		return errors.New("用户不是分销商")
	}
	return DB.Model(&User{}).Where("id = ?", userId).Update("distributor_commission_bps", bps).Error
}

// AdminSettleDistributorAffQuota 结账：清空待结算分销收益额度 aff_quota
func AdminSettleDistributorAffQuota(userId int) error {
	if userId <= 0 {
		return errors.New("invalid user")
	}
	var u User
	if err := DB.Where("id = ?", userId).First(&u).Error; err != nil {
		return err
	}
	if !UserIsDistributor(&u) {
		return errors.New("用户不是分销商")
	}
	return DB.Model(&User{}).Where("id = ?", userId).Update("aff_quota", 0).Error
}

// IsDistributorApplicationProfileComplete 判断分销商申请资料是否已完整（用于手工开通后补录提示）
func IsDistributorApplicationProfileComplete(app *DistributorApplication) bool {
	if app == nil {
		return false
	}
	if strings.TrimSpace(app.RealName) == "" || strings.TrimSpace(app.IdCardNo) == "" || strings.TrimSpace(app.Contact) == "" {
		return false
	}
	return distributorQualificationURLsNonEmpty(app.QualificationUrls)
}

// GetDistributorApplicationProfileByUserIdAdmin 管理端：某分销商的申请资料；无记录或资料不全时 needsManualEntry 为 true
func GetDistributorApplicationProfileByUserIdAdmin(userId int) (username string, app *DistributorApplication, needsManualEntry bool, err error) {
	if userId <= 0 {
		return "", nil, false, errors.New("invalid id")
	}
	u, err := GetUserById(userId, false)
	if err != nil {
		return "", nil, false, err
	}
	if !UserIsDistributor(u) {
		return "", nil, false, errors.New("用户不是分销商")
	}
	app, err = GetDistributorApplicationByUserId(userId)
	if err != nil {
		return "", nil, false, err
	}
	needsManualEntry = !IsDistributorApplicationProfileComplete(app)
	return u.Username, app, needsManualEntry, nil
}

// AdminUpsertDistributorApplicationByUser 管理端补录/修改分销商申请资料（无记录时创建为已通过）
func AdminUpsertDistributorApplicationByUser(userId, reviewerId, applyType int, realName, idCardNo, qualificationUrlsJSON, contact string) error {
	if userId <= 0 || reviewerId <= 0 {
		return errors.New("invalid params")
	}
	if applyType != DistributorApplyTypePersonal && applyType != DistributorApplyTypeEnterprise {
		return errors.New("申请类型无效")
	}
	realName = strings.TrimSpace(realName)
	idCardNo = strings.TrimSpace(idCardNo)
	contact = strings.TrimSpace(contact)
	qualJSON, err := NormalizeDistributorQualificationURLsJSON(qualificationUrlsJSON)
	if err != nil {
		return err
	}
	if !distributorQualificationURLsNonEmpty(qualJSON) {
		return errors.New("请上传资格证书")
	}
	if realName == "" || idCardNo == "" || contact == "" {
		return errors.New("请填写完整资料")
	}
	u, err := GetUserById(userId, false)
	if err != nil {
		return err
	}
	if !UserIsDistributor(u) {
		return errors.New("用户不是分销商")
	}
	if u.Role >= common.RoleAdminUser {
		return errors.New("管理员账号无需维护申请资料")
	}
	return DB.Transaction(func(tx *gorm.DB) error {
		var app DistributorApplication
		err := tx.Where("user_id = ?", userId).First(&app).Error
		ts := common.GetTimestamp()
		if errors.Is(err, gorm.ErrRecordNotFound) {
			app = DistributorApplication{
				UserId:            userId,
				ApplyType:         applyType,
				RealName:          realName,
				IdCardNo:          idCardNo,
				QualificationUrls: qualJSON,
				Contact:           contact,
				Status:            DistributorAppStatusApproved,
				RejectReason:      "",
				ReviewerId:        reviewerId,
				ReviewedAt:        ts,
				CreatedAt:         ts,
				UpdatedAt:         ts,
			}
			return tx.Create(&app).Error
		}
		if err != nil {
			return err
		}
		app.ApplyType = applyType
		app.RealName = realName
		app.IdCardNo = idCardNo
		app.QualificationUrls = qualJSON
		app.Contact = contact
		app.RejectReason = ""
		app.ReviewerId = reviewerId
		app.ReviewedAt = ts
		if app.Status != DistributorAppStatusApproved {
			app.Status = DistributorAppStatusApproved
		}
		app.UpdatedAt = ts
		return tx.Save(&app).Error
	})
}

// migrateDropDistributorApplicationIsStudentColumn 删除 distributor_applications 表中已废弃的 is_student 列（模型已不再映射该字段）。
func migrateDropDistributorApplicationIsStudentColumn() error {
	if DB == nil {
		return nil
	}
	var stmt string
	switch {
	case common.UsingPostgreSQL:
		stmt = `ALTER TABLE distributor_applications DROP COLUMN IF EXISTS is_student`
	case common.UsingSQLite:
		stmt = `ALTER TABLE distributor_applications DROP COLUMN is_student`
	default:
		stmt = `ALTER TABLE distributor_applications DROP COLUMN is_student`
	}
	err := DB.Exec(stmt).Error
	if err == nil {
		common.SysLog("migrate: dropped distributor_applications.is_student")
		return nil
	}
	msg := strings.ToLower(err.Error())
	if strings.Contains(msg, "unknown column") ||
		strings.Contains(msg, "doesn't exist") ||
		strings.Contains(msg, "no such column") ||
		strings.Contains(msg, "check that column") ||
		strings.Contains(msg, "does not exist") {
		return nil
	}
	if common.UsingSQLite &&
		(strings.Contains(msg, "syntax error") || strings.Contains(msg, "near \"drop\"")) {
		common.SysLog("migrate: skip DROP is_student (SQLite may not support DROP COLUMN): " + err.Error())
		return nil
	}
	return err
}
