package ordertimeout

import (
	"testing"
	"time"

	"hfb_sys/backend/internal/model"
	"hfb_sys/backend/internal/modules/chat"

	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func setupOrderTimeoutTestDB(t *testing.T) *gorm.DB {
	t.Helper()
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		t.Fatalf("无法创建测试数据库: %v", err)
	}
	if err := db.AutoMigrate(
		&model.RentalOrder{},
		&model.HandoffRecord{},
		&model.Notification{},
		&model.ChatConversation{},
		&model.ChatParticipant{},
		&model.ChatMessage{},
		&model.SystemConfig{},
		&model.AuditLog{},
	); err != nil {
		t.Fatalf("数据库迁移失败: %v", err)
	}
	return db
}

func TestHandleEndedOrderRenterRetention(t *testing.T) {
	db := setupOrderTimeoutTestDB(t)
	job := New(db, nil, zap.NewNop())
	now := time.Date(2026, 6, 18, 12, 0, 0, 0, time.UTC)

	oldSettledAt := now.AddDate(0, 0, -6)
	recentSettledAt := now.AddDate(0, 0, -2)
	oldOrder := model.RentalOrder{
		OrderNo:   "ORDER-OLD",
		ListingID: 101,
		AccountID: 201,
		OwnerID:   301,
		RenterID:  401,
		Status:    "completed",
		SettledAt: &oldSettledAt,
	}
	recentOrder := model.RentalOrder{
		OrderNo:   "ORDER-RECENT",
		ListingID: 102,
		AccountID: 202,
		OwnerID:   302,
		RenterID:  402,
		Status:    "completed",
		SettledAt: &recentSettledAt,
	}
	if err := db.Create(&oldOrder).Error; err != nil {
		t.Fatalf("创建旧订单失败: %v", err)
	}
	if err := db.Create(&recentOrder).Error; err != nil {
		t.Fatalf("创建新订单失败: %v", err)
	}

	oldConv := model.ChatConversation{
		ListingID: &oldOrder.ListingID,
		Type:      chat.ConversationTypeListingGroup,
		Title:     "旧发布群",
		Status:    "active",
	}
	recentConv := model.ChatConversation{
		ListingID: &recentOrder.ListingID,
		Type:      chat.ConversationTypeListingGroup,
		Title:     "新发布群",
		Status:    "active",
	}
	if err := db.Create(&oldConv).Error; err != nil {
		t.Fatalf("创建旧会话失败: %v", err)
	}
	if err := db.Create(&recentConv).Error; err != nil {
		t.Fatalf("创建新会话失败: %v", err)
	}
	participants := []model.ChatParticipant{
		{ConversationID: oldConv.ID, ParticipantType: "user", ParticipantID: oldOrder.RenterID, Role: "renter", JoinedAt: oldSettledAt},
		{ConversationID: recentConv.ID, ParticipantType: "user", ParticipantID: recentOrder.RenterID, Role: "renter", JoinedAt: recentSettledAt},
	}
	if err := db.Create(&participants).Error; err != nil {
		t.Fatalf("创建成员失败: %v", err)
	}

	count, err := job.handleEndedOrderRenterRetention(t.Context(), now, thresholds{
		RenterRetentionDaysAfterOrderEnd: 5,
	})
	if err != nil {
		t.Fatalf("清退任务失败: %v", err)
	}
	if count != 1 {
		t.Fatalf("清退数量 = %d, want 1", count)
	}

	var oldCount int64
	if err := db.Model(&model.ChatParticipant{}).
		Where("conversation_id = ? AND participant_id = ? AND role = ?", oldConv.ID, oldOrder.RenterID, "renter").
		Count(&oldCount).Error; err != nil {
		t.Fatalf("统计旧租客失败: %v", err)
	}
	if oldCount != 0 {
		t.Fatalf("旧租客成员数 = %d, want 0", oldCount)
	}

	var recentCount int64
	if err := db.Model(&model.ChatParticipant{}).
		Where("conversation_id = ? AND participant_id = ? AND role = ?", recentConv.ID, recentOrder.RenterID, "renter").
		Count(&recentCount).Error; err != nil {
		t.Fatalf("统计新租客失败: %v", err)
	}
	if recentCount != 1 {
		t.Fatalf("新租客成员数 = %d, want 1", recentCount)
	}

	var auditCount int64
	if err := db.Model(&model.AuditLog{}).
		Where("action = ?", "chat.renter_retention.remove").
		Count(&auditCount).Error; err != nil {
		t.Fatalf("统计清退审计失败: %v", err)
	}
	if auditCount != 1 {
		t.Fatalf("清退审计数 = %d, want 1", auditCount)
	}

	count, err = job.handleEndedOrderRenterRetention(t.Context(), now, thresholds{
		RenterRetentionDaysAfterOrderEnd: 5,
	})
	if err != nil {
		t.Fatalf("重复清退任务失败: %v", err)
	}
	if count != 0 {
		t.Fatalf("重复清退数量 = %d, want 0", count)
	}

	if err := db.Model(&model.AuditLog{}).
		Where("action = ?", "chat.renter_retention.remove").
		Count(&auditCount).Error; err != nil {
		t.Fatalf("重复统计清退审计失败: %v", err)
	}
	if auditCount != 1 {
		t.Fatalf("重复清退审计数 = %d, want 1", auditCount)
	}
}

func TestHandleRenterConfirmTimeoutUsesRefreshedStageTime(t *testing.T) {
	db := setupOrderTimeoutTestDB(t)
	job := New(db, nil, zap.NewNop())
	now := time.Date(2026, 6, 18, 12, 0, 0, 0, time.UTC)
	oldHandoffAt := now.Add(-2 * time.Hour)
	refreshedAt := now.Add(-5 * time.Minute)

	order := model.RentalOrder{
		OrderNo:          "ORDER-RENTER-CONFIRM-RESET",
		ListingID:        101,
		AccountID:        201,
		OwnerID:          301,
		RenterID:         401,
		Status:           "pending_handoff",
		HandoffStatus:    "pending_renter_confirm",
		HandoffStartedAt: &refreshedAt,
	}
	if err := db.Create(&order).Error; err != nil {
		t.Fatalf("创建订单失败: %v", err)
	}
	record := model.HandoffRecord{
		OrderID:    order.ID,
		FromUserID: order.OwnerID,
		ToUserID:   order.RenterID,
		Type:       "owner_handoff",
		Content:    "交接说明",
		CreatedAt:  oldHandoffAt,
	}
	if err := db.Create(&record).Error; err != nil {
		t.Fatalf("创建交接记录失败: %v", err)
	}

	count, err := job.handleRenterConfirmTimeout(t.Context(), now, thresholds{
		RenterConfirmTimeoutMinutes: 30,
	})
	if err != nil {
		t.Fatalf("确认收号超时任务失败: %v", err)
	}
	if count != 0 {
		t.Fatalf("处理数量 = %d, want 0", count)
	}

	var saved model.RentalOrder
	if err := db.First(&saved, order.ID).Error; err != nil {
		t.Fatalf("读取订单失败: %v", err)
	}
	if saved.Status != "pending_handoff" || saved.HandoffStatus != "pending_renter_confirm" {
		t.Fatalf("订单状态 = %s/%s, want pending_handoff/pending_renter_confirm", saved.Status, saved.HandoffStatus)
	}
}

func TestHandleOwnerReturnConfirmTimeoutUsesStageTime(t *testing.T) {
	db := setupOrderTimeoutTestDB(t)
	job := New(db, nil, zap.NewNop())
	now := time.Date(2026, 6, 18, 12, 0, 0, 0, time.UTC)
	oldUpdatedAt := now.Add(-2 * time.Hour)
	refreshedAt := now.Add(-5 * time.Minute)

	order := model.RentalOrder{
		OrderNo:          "ORDER-CHECKOUT-CONFIRM-RESET",
		ListingID:        102,
		AccountID:        202,
		OwnerID:          302,
		RenterID:         402,
		Status:           "pending_checkout_confirm",
		HandoffStatus:    "pending_owner_checkout",
		HandoffStartedAt: &refreshedAt,
		UpdatedAt:        oldUpdatedAt,
	}
	if err := db.Create(&order).Error; err != nil {
		t.Fatalf("创建订单失败: %v", err)
	}
	if err := db.Model(&model.RentalOrder{}).Where("id = ?", order.ID).Update("updated_at", oldUpdatedAt).Error; err != nil {
		t.Fatalf("回写旧更新时间失败: %v", err)
	}

	count, err := job.handleOwnerReturnConfirmTimeout(t.Context(), now, thresholds{
		OwnerReturnConfirmTimeoutMinutes: 30,
	})
	if err != nil {
		t.Fatalf("号主确认结账超时任务失败: %v", err)
	}
	if count != 0 {
		t.Fatalf("处理数量 = %d, want 0", count)
	}

	var saved model.RentalOrder
	if err := db.First(&saved, order.ID).Error; err != nil {
		t.Fatalf("读取订单失败: %v", err)
	}
	if saved.Status != "pending_checkout_confirm" || saved.HandoffStatus != "pending_owner_checkout" {
		t.Fatalf("订单状态 = %s/%s, want pending_checkout_confirm/pending_owner_checkout", saved.Status, saved.HandoffStatus)
	}
}

func TestClampRenterRetentionDays(t *testing.T) {
	tests := []struct {
		value int
		want  int
	}{
		{value: 1, want: 3},
		{value: 5, want: 5},
		{value: 9, want: 7},
	}
	for _, tt := range tests {
		if got := clampRenterRetentionDays(tt.value); got != tt.want {
			t.Fatalf("clampRenterRetentionDays(%d) = %d, want %d", tt.value, got, tt.want)
		}
	}
}
