package networkmonitor

import (
	"context"
	"errors"
	"testing"
	"time"

	"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
)

type MocMultiEvent struct {
	counter int
}

func (m *MocMultiEvent) checkChange(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
	if m.counter == 0 {
		<-ctx.Done()
		return ctx.Err()
	}

	time.Sleep(1 * time.Second)
	m.counter--
	return nil
}

func TestNetworkMonitor_Close(t *testing.T) {
	checkChangeFn = func(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
		<-ctx.Done()
		return ctx.Err()
	}
	nw := New()

	var resErr error
	done := make(chan struct{})
	go func() {
		resErr = nw.Listen(context.Background())
		close(done)
	}()

	time.Sleep(1 * time.Second) // wait for the goroutine to start
	nw.Stop()

	<-done
	if !errors.Is(resErr, context.Canceled) {
		t.Errorf("unexpected error: %v", resErr)
	}
}

func TestNetworkMonitor_Event(t *testing.T) {
	checkChangeFn = func(ctx context.Context, nexthopv4, nexthopv6 systemops.Nexthop) error {
		timeout, cancel := context.WithTimeout(ctx, 3*time.Second)
		defer cancel()
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-timeout.Done():
			return nil
		}
	}
	nw := New()
	defer nw.Stop()

	var resErr error
	done := make(chan struct{})
	go func() {
		resErr = nw.Listen(context.Background())
		close(done)
	}()

	<-done
	if !errors.Is(resErr, nil) {
		t.Errorf("unexpected error: %v", nil)
	}
}

func TestNetworkMonitor_MultiEvent(t *testing.T) {
	eventsRepeated := 3
	me := &MocMultiEvent{counter: eventsRepeated}
	checkChangeFn = me.checkChange

	nw := New()
	defer nw.Stop()

	done := make(chan struct{})
	started := time.Now()
	go func() {
		if resErr := nw.Listen(context.Background()); resErr != nil {
			t.Errorf("unexpected error: %v", resErr)
		}
		close(done)
	}()

	<-done
	expectedResponseTime := time.Duration(eventsRepeated)*time.Second + debounceTime
	if time.Since(started) < expectedResponseTime {
		t.Errorf("unexpected duration: %v", time.Since(started))
	}
}
