package course

import (
	"bytes"
	"fmt"
	"github.com/stretchr/testify/require"
	"htwkalender/data-manager/model"
	"htwkalender/data-manager/model/serviceModel"
	"htwkalender/data-manager/service/events/mock"
	"log/slog"
	"regexp"
	"testing"
)

// CustomWriter is a custom writer to capture log output
type CustomWriter struct {
	Buffer bytes.Buffer
}

func (w *CustomWriter) Write(p []byte) (n int, err error) {
	return w.Buffer.Write(p)
}

func TestUpdateCourse(t *testing.T) {
	// Create mock services
	mockCourseService := new(mock.MockCourseService)
	mockEventService := new(mock.MockEventService)

	events := model.Events{}

	// Set up expectations
	mockCourseService.On("GetAllCourses").Return([]string{"Course1", "Course2"})
	mockEventService.On("UpdateModulesForCourse", "Course1").Return(events, nil)
	mockEventService.On("UpdateModulesForCourse", "Course2").Return(events, nil)

	// Inject mocks into the UpdateCourse function
	service := serviceModel.Service{
		CourseService: mockCourseService,
		EventService:  mockEventService,
		App:           nil,
	}
	UpdateCourse(service)

	// Assert that the expectations were met
	mockCourseService.AssertExpectations(t)
	mockEventService.AssertExpectations(t)

	// Assert that the UpdateCourse function was called twice
	mockCourseService.AssertNumberOfCalls(t, "GetAllCourses", 1)
	mockEventService.AssertNumberOfCalls(t, "UpdateModulesForCourse", 2)

	// Assert that the UpdateCourse function was called with the correct arguments
	mockEventService.AssertCalled(t, "UpdateModulesForCourse", "Course1")
	mockEventService.AssertCalled(t, "UpdateModulesForCourse", "Course2")
}

func TestUpdateCourseErr(t *testing.T) {
	// Create mock services
	mockCourseService := new(mock.MockCourseService)
	mockEventService := new(mock.MockEventService)

	events := model.Events{}

	// Set up expectations
	mockCourseService.On("GetAllCourses").Return([]string{"Course1", "Course2"})
	mockEventService.On("UpdateModulesForCourse", "Course1").Return(events, fmt.Errorf("error"))
	mockEventService.On("UpdateModulesForCourse", "Course2").Return(events, fmt.Errorf("error"))

	// Create a custom writer to capture log output
	customWriter := &CustomWriter{}
	originalLogger := slog.Default()
	defer slog.SetDefault(originalLogger)

	// Replace the default logger with a custom logger
	slog.SetDefault(slog.New(slog.NewTextHandler(customWriter, nil)))

	// Inject mocks into the UpdateCourse function
	service := serviceModel.Service{
		CourseService: mockCourseService,
		EventService:  mockEventService,
		App:           nil,
	}
	UpdateCourse(service)

	// Assert that the expectations were met
	mockCourseService.AssertExpectations(t)
	mockEventService.AssertExpectations(t)

	// Assert that the UpdateCourse function was called twice
	mockCourseService.AssertNumberOfCalls(t, "GetAllCourses", 1)
	mockEventService.AssertNumberOfCalls(t, "UpdateModulesForCourse", 2)

	// Check the captured log output for the expected messages
	logOutput := customWriter.Buffer.String()
	require.Regexp(t, regexp.MustCompile(`Update Course: Course1 failed:.*error`), logOutput)
	require.Regexp(t, regexp.MustCompile(`Update Course: Course2 failed:.*error`), logOutput)
}
