package service_test

import (
	"context"
	"testing"
	"time"

	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/repository"
	"github.com/user-management-system/internal/service"
	gormsqlite "gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// =============================================================================
// Operation Log Service Tests
// =============================================================================

func setupOperationLogTestEnv(t *testing.T) (*service.OperationLogService, *gorm.DB) {
	t.Helper()

	db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
		DriverName: "sqlite",
		DSN:        "file:oplog_test?mode=memory&cache=shared",
	}), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	if err != nil {
		t.Fatalf("failed to connect database: %v", err)
	}

	if err := db.AutoMigrate(&domain.OperationLog{}); err != nil {
		t.Fatalf("failed to migrate: %v", err)
	}

	operationLogRepo := repository.NewOperationLogRepository(db)
	opLogSvc := service.NewOperationLogService(operationLogRepo)

	return opLogSvc, db
}

func TestOperationLogService_RecordOperation(t *testing.T) {
	svc, _ := setupOperationLogTestEnv(t)
	ctx := context.Background()

	t.Run("Record operation success", func(t *testing.T) {
		req := &service.RecordOperationRequest{
			UserID:         1,
			OperationType:  "create",
			OperationName:  "创建用户",
			RequestMethod:  "POST",
			RequestPath:    "/api/users",
			RequestParams:  `{"name":"test"}`,
			ResponseStatus: 200,
			IP:             "192.168.1.1",
			UserAgent:      "Mozilla/5.0",
		}
		err := svc.RecordOperation(ctx, req)
		if err != nil {
			t.Fatalf("RecordOperation failed: %v", err)
		}
	})

	t.Run("Record operation without user ID", func(t *testing.T) {
		req := &service.RecordOperationRequest{
			OperationType:  "delete",
			OperationName:  "删除用户",
			RequestMethod:  "DELETE",
			RequestPath:    "/api/users/1",
			ResponseStatus: 204,
			IP:             "192.168.1.2",
		}
		err := svc.RecordOperation(ctx, req)
		if err != nil {
			t.Fatalf("RecordOperation failed: %v", err)
		}
	})
}

func TestOperationLogService_GetOperationLogs(t *testing.T) {
	svc, _ := setupOperationLogTestEnv(t)
	ctx := context.Background()

	// Create test logs
	for i := 0; i < 5; i++ {
		req := &service.RecordOperationRequest{
			UserID:         1,
			OperationType:  "test",
			OperationName:  "测试操作",
			RequestMethod:  "GET",
			RequestPath:    "/api/test",
			ResponseStatus: 200,
			IP:             "192.168.1.1",
		}
		svc.RecordOperation(ctx, req)
	}

	t.Run("Get operation logs with pagination", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			Page:     1,
			PageSize: 3,
		}
		logs, total, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
		if len(logs) > 3 {
			t.Errorf("Expected max 3 logs, got %d", len(logs))
		}
		if total < 5 {
			t.Errorf("Expected total >= 5, got %d", total)
		}
	})

	t.Run("Get operation logs by user ID", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			UserID:   1,
			Page:     1,
			PageSize: 10,
		}
		logs, _, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
		if len(logs) < 5 {
			t.Errorf("Expected at least 5 logs, got %d", len(logs))
		}
	})

	t.Run("Get operation logs by method", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			Method:   "GET",
			Page:     1,
			PageSize: 10,
		}
		_, _, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
	})

	t.Run("Get operation logs by keyword", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			Keyword:  "测试",
			Page:     1,
			PageSize: 10,
		}
		logs, _, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
		if len(logs) < 5 {
			t.Errorf("Expected at least 5 logs, got %d", len(logs))
		}
	})

	t.Run("Get operation logs by time range", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			StartAt:  time.Now().Add(-24 * time.Hour).Format(time.RFC3339),
			EndAt:    time.Now().Add(24 * time.Hour).Format(time.RFC3339),
			Page:     1,
			PageSize: 10,
		}
		_, _, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
	})

	t.Run("Get operation logs with default pagination", func(t *testing.T) {
		req := &service.ListOperationLogRequest{}
		_, _, err := svc.GetOperationLogs(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogs failed: %v", err)
		}
	})
}

func TestOperationLogService_GetOperationLogsCursor(t *testing.T) {
	svc, _ := setupOperationLogTestEnv(t)
	ctx := context.Background()

	// Create test logs
	for i := 0; i < 5; i++ {
		req := &service.RecordOperationRequest{
			UserID:         1,
			OperationType:  "cursor_test",
			OperationName:  "游标测试",
			RequestMethod:  "GET",
			RequestPath:    "/api/cursor",
			ResponseStatus: 200,
			IP:             "192.168.1.1",
		}
		svc.RecordOperation(ctx, req)
	}

	t.Run("Get operation logs with cursor", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			Size: 3,
		}
		result, err := svc.GetOperationLogsCursor(ctx, req)
		if err != nil {
			t.Fatalf("GetOperationLogsCursor failed: %v", err)
		}
		if result.PageSize != 3 {
			t.Errorf("Expected page size 3, got %d", result.PageSize)
		}
	})

	t.Run("Get operation logs with invalid cursor", func(t *testing.T) {
		req := &service.ListOperationLogRequest{
			Cursor: "invalid-cursor",
		}
		_, err := svc.GetOperationLogsCursor(ctx, req)
		if err == nil {
			t.Error("Expected error for invalid cursor")
		}
	})
}

func TestOperationLogService_GetMyOperationLogs(t *testing.T) {
	svc, _ := setupOperationLogTestEnv(t)
	ctx := context.Background()

	// Create test logs
	for i := 0; i < 3; i++ {
		req := &service.RecordOperationRequest{
			UserID:         1,
			OperationType:  "my_test",
			OperationName:  "我的操作",
			RequestMethod:  "GET",
			RequestPath:    "/api/my",
			ResponseStatus: 200,
			IP:             "192.168.1.1",
		}
		svc.RecordOperation(ctx, req)
	}

	t.Run("Get my operation logs", func(t *testing.T) {
		logs, total, err := svc.GetMyOperationLogs(ctx, 1, 1, 10)
		if err != nil {
			t.Fatalf("GetMyOperationLogs failed: %v", err)
		}
		if total < 3 {
			t.Errorf("Expected total >= 3, got %d", total)
		}
		_ = logs
	})

	t.Run("Get my operation logs with default pagination", func(t *testing.T) {
		_, _, err := svc.GetMyOperationLogs(ctx, 1, 0, 0)
		if err != nil {
			t.Fatalf("GetMyOperationLogs failed: %v", err)
		}
	})
}

func TestOperationLogService_CleanupOldLogs(t *testing.T) {
	svc, _ := setupOperationLogTestEnv(t)
	ctx := context.Background()

	t.Run("Cleanup old logs", func(t *testing.T) {
		err := svc.CleanupOldLogs(ctx, 30)
		if err != nil {
			t.Fatalf("CleanupOldLogs failed: %v", err)
		}
	})
}
