package jobqueue

import (
	"context"
	"fmt"
	"github.com/docker/go-connections/nat"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
	"time"
)

func startTestSMTPDockerImageAndContainer(t *testing.T, ctx context.Context) (string, error) {
	t.Helper()

	smtpPortMap := nat.PortMap{
		"1025/tcp": []nat.PortBinding{
			{
				HostIP:   "0.0.0.0",
				HostPort: "",
			},
		},
		"8025/tcp": []nat.PortBinding{
			{
				HostIP:   "0.0.0.0",
				HostPort: "8025",
			},
		},
	}

	smtpCmd := []string{} // Ihr Command hier, falls nötig
	smtpVolume := ""      // Ihr Volume hier
	smtpPorts, err := startTestDockerImageAndContainer(t, ctx, "axllent/mailpit", smtpPortMap, smtpCmd, smtpVolume)

	if err != nil {
		return "", err
	}

	pp := *smtpPorts

	px, ok := pp["1025/tcp"]
	if !ok {
		return "", fmt.Errorf("1025/tcp port not found")
	}

	smtpPort := px[0].HostPort

	return smtpPort, nil

	//cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
	//if err != nil {
	//	return err
	//}
	//
	//imageName := "axllent/mailpit"
	//
	//reader, err := cli.ImagePull(ctx, imageName, types.ImagePullOptions{})
	//if err != nil {
	//	return err
	//}
	//
	//// if debug image pull, comment out the following lines
	////_, _ = io.Copy(os.Stdout, reader)
	//_ = reader
	//
	//host, _, _ := net.SplitHostPort(cli.DaemonHost())
	//if host == "" || host == "unix" {
	//	host = DOCKER_TEST_HOST_IP
	//}
	//
	//hostConfig := &container.HostConfig{
	//	PortBindings: nat.PortMap{
	//		"1025/tcp": []nat.PortBinding{
	//			{
	//				HostIP:   host,
	//				HostPort: port,
	//			},
	//		},
	//		"8025/tcp": []nat.PortBinding{
	//			{
	//				HostIP:   host,
	//				HostPort: "8025",
	//			},
	//		},
	//	},
	//}
	//
	//resp, err := cli.ContainerCreate(ctx, &container.Config{
	//	Image: imageName,
	//}, hostConfig, nil, nil, "")
	//
	//if err != nil {
	//	return err
	//}
	//
	//if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
	//	return err
	//}
	//
	//go func() {
	//	<-ctx.Done()
	//
	//	timeout := 0
	//	stopOptions := container.StopOptions{
	//		Timeout: &timeout,
	//		Signal:  "SIGKILL",
	//	}
	//	newCtx, _ := context.WithTimeout(context.Background(), 60*time.Second)
	//	if err := cli.ContainerStop(newCtx, resp.ID, stopOptions); err != nil {
	//		t.Errorf("ContainerStop returned error: %v", err)
	//	}
	//	if err := cli.ContainerRemove(newCtx, resp.ID, types.ContainerRemoveOptions{
	//		Force: true,
	//	}); err != nil {
	//		t.Errorf("ContainerRemove returned error: %v", err)
	//	}
	//
	//}()
	//
	//statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
	//select {
	//case err := <-errCh:
	//	if err != nil {
	//		// empty error means container exited normally (see container_wait.go)
	//		if err.Error() == "" {
	//			return nil
	//		}
	//
	//		return err
	//	}
	//case <-statusCh:
	//
	//}
	//
	//return nil
}

func TestMailRunner(t *testing.T) {
	ctb := context.Background()
	ctx, cancel := context.WithCancel(ctb)
	t.Cleanup(func() {
		cancel()
		time.Sleep(1 * time.Second)
	})

	//listener, err := net.Listen("tcp", DOCKER_TEST_HOST_IP+":0")
	//if err != nil {
	//	t.Errorf("Unexpected error: %v", err)
	//	return
	//}
	//portAsInt := listener.Addr().(*net.TCPAddr).Port
	//portAsString := fmt.Sprintf("%d", portAsInt)
	//_ = listener.Close()

	var portAsString string
	var err error

	done := make(chan bool)
	go func() {
		portAsString, err = startTestSMTPDockerImageAndContainer(t, ctx)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
			cancel()
		}
		done <- true
	}()

	waitCtx, waitCancel := context.WithTimeout(ctx, 60*time.Second)
	defer waitCancel()
	for {
		conn, err := net.DialTimeout("tcp", net.JoinHostPort(DOCKER_TEST_HOST_IP, portAsString), 1*time.Second)
		if err == nil {
			err = conn.Close()
			assert.Nil(t, err)
			break
		}
		select {
		case <-waitCtx.Done():
			t.Error("Timeout waiting for container service")
			cancel()
			return
		default:
			time.Sleep(1 * time.Second)
		}
	}

	time.Sleep(1 * time.Second)

	mailRunnable := &MailRunnable{
		To:       "to@example.com",
		From:     "from@example.com",
		Subject:  "this is a test",
		Body:     "this is the body",
		Server:   DOCKER_TEST_HOST_IP,
		Port:     portAsString,
		Username: "",
		Password: "",
		Headers: map[string]string{
			"X-Test": "test",
		},
	}

	result, err := mailRunnable.Run()

	// Assertions
	assert.NoError(t, err)
	assert.Equal(t, ResultStatusSuccess, result.Status)
	assert.IsType(t, MailResult{}, result.Data)

	// check result.Data contains 4 files
	mailResult := result.Data.Sent
	assert.Equal(t, true, mailResult)

	cancel()

	select {
	case <-done:
		time.Sleep(1 * time.Second)
	case <-time.After(1 * time.Minute):
		t.Error("test hangs, timeout reached")
	}

}