package host

import (
	"context"
	"regexp"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"hyapp/pkg/appcode"
	hostdomain "hyapp/services/user-service/internal/domain/host"
)

func TestGetHostEngagementStatsAggregatesOwnedFacts(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("create sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectQuery("FROM user_mic_daily_stats").
		WithArgs(validMicDayThresholdMS, "fami", int64(42), "2026-07-06", "2026-07-12").
		WillReturnRows(sqlmock.NewRows([]string{"mic_ms", "valid_days"}).AddRow(int64(5400000), int64(1)))
	mock.ExpectQuery(regexp.QuoteMeta(`
			SELECT COUNT(DISTINCT matched.sender_user_id)
			FROM (
			  SELECT sender_user_id
			  FROM user_private_message_events FORCE INDEX (idx_private_message_target_time)
			  WHERE app_code = ? AND target_user_id = ?
			    AND occurred_at_ms >= ? AND occurred_at_ms < ?
			  UNION ALL
			  SELECT sender_user_id
			  FROM user_private_message_events FORCE INDEX (idx_private_message_target_time)
			  WHERE app_code = ? AND target_user_id = ?
			    AND occurred_at_ms >= ? AND occurred_at_ms < ?
			) matched
		INNER JOIN users sender
			  ON sender.user_id = matched.sender_user_id AND sender.app_code = ?`)).
		WithArgs(
			"fami", int64(42), int64(1783296000000), int64(1783900800000),
			"lalu", int64(42), int64(1783296000000), int64(1783900800000),
			"fami",
		).
		WillReturnRows(sqlmock.NewRows([]string{"senders"}).AddRow(int64(6)))
	mock.ExpectQuery("FROM user_follow_events").
		WithArgs("fami", int64(42), int64(1783296000000), int64(1783900800000)).
		WillReturnRows(sqlmock.NewRows([]string{"followers"}).AddRow(int64(4)))
	mock.ExpectQuery(regexp.QuoteMeta(`
		SELECT created_at_ms, last_heartbeat_at_ms
		FROM auth_sessions
		WHERE app_code = ? AND user_id = ?
		  AND last_heartbeat_at_ms >= ? AND created_at_ms < ?`)).
		WithArgs("fami", int64(42), int64(1783296000000), int64(1783900800000)).
		WillReturnRows(sqlmock.NewRows([]string{"created_at_ms", "last_heartbeat_at_ms"}).
			AddRow(int64(1783299600000), int64(1783303200000)).
			AddRow(int64(1783301400000), int64(1783306800000)))

	repo := New(db)
	stats, err := repo.GetHostEngagementStats(appcode.WithContext(context.Background(), "fami"), hostdomain.EngagementStatsQuery{
		HostUserID: 42,
		StartAtMS:  1783296000000,
		EndAtMS:    1783900800000,
	})
	if err != nil {
		t.Fatalf("GetHostEngagementStats failed: %v", err)
	}
	// 两个重叠 session 按当天最早开始到最晚心跳合并，不能相加成重复在线时长。
	if stats.OnlineDurationMS != 7200000 || stats.ValidMicDurationMS != 5400000 || stats.ValidMicDays != 1 || stats.PrivateMessageSenders != 6 || stats.NewFollowers != 4 {
		t.Fatalf("unexpected engagement stats: %+v", stats)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("unmet SQL expectations: %v", err)
	}
}

func TestRecordPrivateMessageEventResolvesAppFromUsers(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("create sqlmock: %v", err)
	}
	defer db.Close()

	mock.ExpectExec(regexp.QuoteMeta(`
		INSERT IGNORE INTO user_private_message_events (
		  app_code, event_id, sender_user_id, target_user_id, occurred_at_ms, created_at_ms
		)
		SELECT target.app_code, ?, sender.user_id, target.user_id, ?, ?
		FROM users target
		INNER JOIN users sender
		  ON sender.user_id = ? AND sender.app_code = target.app_code
		WHERE target.user_id = ?`)).
		WithArgs("im-message-1", int64(1783296000000), sqlmock.AnyArg(), int64(41), int64(42)).
		WillReturnResult(sqlmock.NewResult(0, 1))

	repo := New(db)
	created, err := repo.RecordPrivateMessageEvent(appcode.WithContext(context.Background(), "lalu"), hostdomain.PrivateMessageEvent{
		EventID:      "im-message-1",
		SenderUserID: 41,
		TargetUserID: 42,
		OccurredAtMS: 1783296000000,
	})
	if err != nil {
		t.Fatalf("RecordPrivateMessageEvent failed: %v", err)
	}
	if !created {
		t.Fatal("event must be created for users in the same authoritative app")
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatalf("unmet SQL expectations: %v", err)
	}
}
