package exporter

import (
	"context"
	"time"

	"gorm.io/gorm"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
)

// RefundDataSource 退款记录导出数据源。
type RefundDataSource struct {
	db *gorm.DB
}

// NewRefundDataSource 创建退款记录导出数据源。
func NewRefundDataSource(db *gorm.DB) *RefundDataSource {
	return &RefundDataSource{db: db}
}

// Scene 返回导出场景编码。
func (s *RefundDataSource) Scene() string {
	return constants.ExportTaskSceneRefund
}

// Count 统计退款记录导出行数。
func (s *RefundDataSource) Count(ctx context.Context, params ExportParams) (int, error) {
	var total int64
	query := s.applyFilters(s.baseQuery(ctx), params)
	if err := query.Count(&total).Error; err != nil {
		return 0, err
	}
	return int(total), nil
}

// Headers 返回退款记录导出表头。
func (s *RefundDataSource) Headers(context.Context, ExportParams) ([]string, error) {
	return []string{
		"退款单号", "代理店铺名称", "关联的支付订单号", "资产类型", "资产标识", "套餐名称", "原订单金额(元)",
		"实收金额(元)", "可退金额(元)", "申请退款金额(元)", "实际退款金额(元)", "状态", "退款原因", "审批备注",
		"审批来源", "审批状态", "退款处理状态", "退款申请时间", "退款审批时间", "提交人", "退款凭证",
	}, nil
}

// Fetch 按 offset/limit 查询退款记录导出数据。
func (s *RefundDataSource) Fetch(ctx context.Context, params ExportParams, offset, limit int) ([][]string, error) {
	if limit <= 0 {
		return [][]string{}, nil
	}

	var items []refundExportRow
	query := s.applyFilters(s.baseQuery(ctx), params).
		Select(`
			r.refund_no,
			r.order_no,
			r.order_type,
			r.asset_identifier,
			r.actual_received_amount,
			r.requested_refund_amount,
			r.approved_refund_amount,
			r.status,
			r.refund_reason,
			r.remark,
			r.commission_deducted,
			r.asset_reset,
			r.created_at,
			r.processed_at,
			COALESCE(sh.shop_name, '') AS shop_name,
			o.total_amount AS original_amount,
			o.actual_paid_amount AS refundable_amount,
			COALESCE(pu.package_name, items.package_names, '') AS package_name,
			COALESCE(ac.username, '') AS submitter_name,
			ai.provider AS approval_provider,
			ai.status AS approval_status,
			COALESCE((SELECT string_agg(voucher.value, ',' ORDER BY voucher.ordinality)
				FROM jsonb_array_elements_text(COALESCE(r.refund_voucher_key, '[]'::jsonb)) WITH ORDINALITY AS voucher(value, ordinality)), '') AS voucher_keys
		`).
		Joins("LEFT JOIN tb_shop AS sh ON sh.id = r.shop_id").
		Joins("LEFT JOIN tb_order AS o ON o.id = r.order_id AND o.deleted_at IS NULL").
		Joins("LEFT JOIN tb_package_usage AS pu ON pu.id = r.package_usage_id AND pu.deleted_at IS NULL").
		Joins("LEFT JOIN tb_account AS ac ON ac.id = r.creator").
		Joins("LEFT JOIN tb_approval_instance AS ai ON ai.id = r.approval_instance_id").
		Joins(`LEFT JOIN LATERAL (
			SELECT string_agg(oi.package_name, ',' ORDER BY oi.id) AS package_names
			FROM tb_order_item AS oi
			WHERE oi.order_id = r.order_id AND oi.deleted_at IS NULL
		) AS items ON TRUE`).
		Order("r.id ASC").
		Limit(limit).
		Offset(offset)
	if err := query.Scan(&items).Error; err != nil {
		return nil, err
	}

	rows := make([][]string, 0, len(items))
	for _, item := range items {
		rows = append(rows, []string{
			item.RefundNo,
			item.ShopName,
			item.OrderNo,
			formatRefundAssetType(item.OrderType),
			item.AssetIdentifier,
			item.PackageName,
			formatOptionalMoneyYuan(item.OriginalAmount),
			formatMoneyYuan(item.ActualReceivedAmount),
			formatOptionalMoneyYuan(item.RefundableAmount),
			formatMoneyYuan(item.RequestedRefundAmount),
			formatOptionalMoneyYuan(item.ApprovedRefundAmount),
			constants.GetRefundStatusName(item.Status),
			item.RefundReason,
			item.Remark,
			formatRefundApprovalSource(item.ApprovalProvider),
			formatOptionalApprovalStatus(item.ApprovalStatus),
			formatRefundProcessingStatus(item.Status, item.CommissionDeducted, item.AssetReset),
			item.CreatedAt.Format(exportTimeLayout),
			formatOptionalTime(item.ProcessedAt),
			item.SubmitterName,
			item.VoucherKeys,
		})
	}
	return rows, nil
}

func (s *RefundDataSource) baseQuery(ctx context.Context) *gorm.DB {
	return s.db.WithContext(ctx).Table("tb_refund_request AS r").Where("r.deleted_at IS NULL")
}

func (s *RefundDataSource) applyFilters(query *gorm.DB, params ExportParams) *gorm.DB {
	query = applyExportShopScope(query, params, "r.shop_id")
	if status, ok := filterInt(params.Filters, "status"); ok {
		query = query.Where("r.status = ?", status)
	}
	if orderID, ok := filterUint(params.Filters, "order_id"); ok {
		query = query.Where("r.order_id = ?", orderID)
	}
	if shopID, ok := filterUint(params.Filters, "shop_id"); ok {
		query = query.Where("r.shop_id = ?", shopID)
	}
	if identifier, ok := filterString(params.Filters, "asset_identifier"); ok {
		query = query.Where("r.asset_identifier = ?", identifier)
	}
	return query
}

type refundExportRow struct {
	RefundNo              string     `gorm:"column:refund_no"`
	ShopName              string     `gorm:"column:shop_name"`
	OrderNo               string     `gorm:"column:order_no"`
	OrderType             string     `gorm:"column:order_type"`
	AssetIdentifier       string     `gorm:"column:asset_identifier"`
	PackageName           string     `gorm:"column:package_name"`
	OriginalAmount        *int64     `gorm:"column:original_amount"`
	ActualReceivedAmount  int64      `gorm:"column:actual_received_amount"`
	RefundableAmount      *int64     `gorm:"column:refundable_amount"`
	RequestedRefundAmount int64      `gorm:"column:requested_refund_amount"`
	ApprovedRefundAmount  *int64     `gorm:"column:approved_refund_amount"`
	Status                int        `gorm:"column:status"`
	RefundReason          string     `gorm:"column:refund_reason"`
	Remark                string     `gorm:"column:remark"`
	ApprovalProvider      *string    `gorm:"column:approval_provider"`
	ApprovalStatus        *int       `gorm:"column:approval_status"`
	CommissionDeducted    bool       `gorm:"column:commission_deducted"`
	AssetReset            bool       `gorm:"column:asset_reset"`
	CreatedAt             time.Time  `gorm:"column:created_at"`
	ProcessedAt           *time.Time `gorm:"column:processed_at"`
	SubmitterName         string     `gorm:"column:submitter_name"`
	VoucherKeys           string     `gorm:"column:voucher_keys"`
}

func formatRefundAssetType(orderType string) string {
	switch orderType {
	case model.OrderTypeSingleCard:
		return "物联网卡"
	case model.OrderTypeDevice:
		return "设备"
	case "":
		return ""
	default:
		return "未知"
	}
}

func formatRefundApprovalSource(provider *string) string {
	if provider == nil || *provider == "" {
		return "历史审批"
	}
	return formatApprovalProvider(provider)
}

func formatRefundProcessingStatus(status int, commissionDeducted, assetReset bool) string {
	switch status {
	case model.RefundStatusPending, model.RefundStatusReturned:
		return "待审批"
	case model.RefundStatusRejected:
		return "无需处理"
	case model.RefundStatusApproved:
		if commissionDeducted && assetReset {
			return "已完成"
		}
		return "处理中"
	default:
		return "未知"
	}
}
