package testutils

import (
	"errors"
	"testing"
)

func TestRunTableTests(t *testing.T) {
	testCases := []TableTestCase{
		{
			Name:     "test case 1",
			Input:    1,
			Expected: 2,
		},
		{
			Name:     "test case 2",
			Input:    2,
			Expected: 4,
		},
		{
			Name:     "test case 3",
			Input:    3,
			Expected: 6,
		},
	}

	RunTableTests(t, testCases, func(t *testing.T, tc TableTestCase) {
		result := tc.Input.(int) * 2
		AssertEqual(t, tc.Expected, result)
	})
}

func TestRunTableTests_WithSetupAndCleanup(t *testing.T) {
	setupCalled := false
	cleanupCalled := false

	testCases := []TableTestCase{
		{
			Name:  "test with setup/cleanup",
			Input: "test",
			SetupFunc: func() interface{} {
				setupCalled = true
				return "setup-result"
			},
			CleanupFunc: func(result interface{}) {
				cleanupCalled = true
				AssertEqual(t, "setup-result", result)
			},
		},
	}

	RunTableTests(t, testCases, func(t *testing.T, tc TableTestCase) {
		AssertTrue(t, setupCalled, "Setup should have been called")
		AssertNotNil(t, tc.Input)
	})

	AssertTrue(t, cleanupCalled, "Cleanup should have been called")
}

func TestRunTableTests_WithError(t *testing.T) {
	testCases := []TableTestCase{
		{
			Name:        "test with expected error",
			Input:       -1,
			ExpectedErr: errors.New("negative not allowed"),
		},
		{
			Name:        "test with no error",
			Input:       1,
			ExpectedErr: nil,
		},
	}

	RunTableTests(t, testCases, func(t *testing.T, tc TableTestCase) {
		if tc.ExpectedErr != nil {
			// Simuler une fonction qui retourne une erreur
			result, err := processWithError(tc.Input.(int))
			RequireError(t, err)
			AssertNil(t, result)
		} else {
			result, err := processWithError(tc.Input.(int))
			RequireNoError(t, err)
			AssertNotNil(t, result)
		}
	})
}

func TestRunTableSubTests(t *testing.T) {
	testCases := []TableTestCase{
		{
			Name:     "subtest 1",
			Input:    10,
			Expected: 20,
		},
		{
			Name:     "subtest 2",
			Input:    20,
			Expected: 40,
		},
	}

	RunTableSubTests(t, testCases, func(t *testing.T, tc TableTestCase) {
		result := tc.Input.(int) * 2
		AssertEqual(t, tc.Expected, result)
	})
}

func TestAssertEqual(t *testing.T) {
	AssertEqual(t, 1, 1)
	AssertEqual(t, "hello", "hello")
	AssertEqual(t, []int{1, 2, 3}, []int{1, 2, 3})
}

func TestAssertNotEqual(t *testing.T) {
	AssertNotEqual(t, 1, 2)
	AssertNotEqual(t, "hello", "world")
}

func TestRequireNoError(t *testing.T) {
	RequireNoError(t, nil)
}

func TestRequireError(t *testing.T) {
	RequireError(t, errors.New("test error"))
}

func TestAssertNil(t *testing.T) {
	var ptr *int
	AssertNil(t, ptr)
	AssertNil(t, nil)
}

func TestAssertNotNil(t *testing.T) {
	value := 42
	AssertNotNil(t, value)
	AssertNotNil(t, &value)
}

func TestAssertTrue(t *testing.T) {
	AssertTrue(t, true)
}

func TestAssertFalse(t *testing.T) {
	AssertFalse(t, false)
}

// Helper function for testing error cases
func processWithError(input int) (interface{}, error) {
	if input < 0 {
		return nil, errors.New("negative not allowed")
	}
	return input * 2, nil
}
