package financewithdrawal

import (
	"context"
	"fmt"
	"strings"
	"time"

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

type markdownSender interface {
	SendMarkdown(ctx context.Context, title string, text string) error
}

// ReviewPendingNotifier 只通知“当前待谁处理”，不参与提现创建、冻结或审核事务。
type ReviewPendingNotifier interface {
	NotifyReviewPending(ctx context.Context, application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) error
}

type dingTalkReviewPendingNotifier struct {
	sender markdownSender
}

func NewDingTalkReviewPendingNotifier(sender markdownSender) ReviewPendingNotifier {
	if sender == nil {
		return nil
	}
	return &dingTalkReviewPendingNotifier{sender: sender}
}

func (n *dingTalkReviewPendingNotifier) NotifyReviewPending(ctx context.Context, application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) error {
	if n == nil || n.sender == nil {
		return nil
	}
	title, text := withdrawalReviewPendingMarkdown(application, stage)
	return n.sender.SendMarkdown(ctx, title, text)
}

func withdrawalReviewPendingMarkdown(application model.UserWithdrawalApplication, stage repository.WithdrawalApplicationReviewStage) (string, string) {
	stageName := "运营审核阶段"
	pageURL := "https://admin-acc.global-interaction.com/finance/?view=withdrawalOperations"
	if stage == repository.WithdrawalApplicationReviewStageFinance {
		stageName = "财务审核阶段"
		pageURL = "https://admin-acc.global-interaction.com/finance/?view=withdrawalFinance"
	}
	title := fmt.Sprintf("用户提现待处理【%s】", stageName)
	lines := []string{
		fmt.Sprintf("### 用户提现待处理【%s】", stageName),
		"",
		fmt.Sprintf("- 当前阶段：**%s**", stageName),
		fmt.Sprintf("- 申请ID：%d", application.ID),
		fmt.Sprintf("- APP：%s", withdrawalMarkdownValue(application.AppCode)),
		fmt.Sprintf("- 来源系统：%s", withdrawalMarkdownValue(application.SourceSystem)),
		fmt.Sprintf("- 来源单号：%s", withdrawalMarkdownValue(application.SourceApplicationID)),
		fmt.Sprintf("- 用户ID：%s", withdrawalMarkdownValue(application.UserID)),
		fmt.Sprintf("- 申请金额：$ %s", withdrawalMarkdownValue(application.WithdrawAmount)),
		fmt.Sprintf("- 提现方式：%s", withdrawalMarkdownValue(application.WithdrawMethod)),
		fmt.Sprintf("- 提现地址：%s", withdrawalMarkdownValue(application.WithdrawAddress)),
		fmt.Sprintf("- 申请时间：%s", formatWithdrawalNotifyMillis(application.CreatedAtMS)),
	}
	if hasWithdrawalPayoutSnapshot(application) {
		// 协作通知展示来源申请时的不可变快照，财务不应在审核时按当前费率重算。
		lines = append(lines,
			fmt.Sprintf("- 手续费：$ %s（费率 %s%%）", withdrawalOptionalMarkdownValue(application.ServiceCharge), withdrawalOptionalMarkdownValue(application.ServiceChargeRatio)),
			fmt.Sprintf("- 实际打款金额：$ %s", withdrawalOptionalMarkdownValue(application.ActualAmount)),
		)
	}
	if stage == repository.WithdrawalApplicationReviewStageFinance {
		// 财务提醒保留运营审核快照，接收人无需先打开后台就能确认这是一张已完成初审的申请。
		lines = append(lines,
			fmt.Sprintf("- 运营审核人：%s", withdrawalMarkdownValue(application.OperationsReviewerName)),
			fmt.Sprintf("- 运营审核备注：%s", withdrawalMarkdownValue(application.OperationsAuditRemark)),
			fmt.Sprintf("- 运营通过时间：%s", formatWithdrawalNotifyMillis(int64Value(application.OperationsReviewedAtMS))),
		)
	}
	lines = append(lines, "- 后台地址："+pageURL)
	return title, strings.Join(lines, "\n")
}

func hasWithdrawalPayoutSnapshot(application model.UserWithdrawalApplication) bool {
	return application.ServiceChargeRatio != nil || application.ServiceCharge != nil || application.ActualAmount != nil || application.ActualAmountMinor != nil
}

func withdrawalOptionalMarkdownValue(value *string) string {
	if value == nil {
		return "-"
	}
	return withdrawalMarkdownValue(*value)
}

func formatWithdrawalNotifyMillis(value int64) string {
	if value <= 0 {
		return "-"
	}
	// 协作消息按运营团队使用的北京时间展示；接口和数据库仍以 Unix 毫秒 UTC 事实为准。
	return time.UnixMilli(value).In(time.FixedZone("UTC+8", 8*60*60)).Format("2006-01-02 15:04:05")
}

func int64Value(value *int64) int64 {
	if value == nil {
		return 0
	}
	return *value
}

func withdrawalMarkdownValue(value string) string {
	value = strings.TrimSpace(value)
	if value == "" {
		return "-"
	}
	runes := []rune(value)
	if len(runes) > 240 {
		value = string(runes[:240]) + "..."
	}
	return strings.NewReplacer("\r", " ", "\n", " ", "\t", " ").Replace(value)
}
