//go:build !windows && !darwin

package updater

import (
	"context"
	"fmt"
	"path"
	"testing"
	"time"

	v "github.com/hashicorp/go-version"

	"github.com/netbirdio/netbird/client/internal/peer"
	"github.com/netbirdio/netbird/client/internal/statemanager"
)

// On Linux, only Mode 1 (downloadOnly) is supported.
// SetVersion is a no-op because auto-update installation is not supported.

func Test_LatestVersion_Linux(t *testing.T) {
	testMatrix := []struct {
		name                 string
		daemonVersion        string
		initialLatestVersion *v.Version
		latestVersion        *v.Version
		shouldUpdateInit     bool
		shouldUpdateLater    bool
	}{
		{
			name:                 "Should notify again when a newer version arrives even within 5 minutes",
			daemonVersion:        "1.0.0",
			initialLatestVersion: v.Must(v.NewSemver("1.0.1")),
			latestVersion:        v.Must(v.NewSemver("1.0.2")),
			shouldUpdateInit:     true,
			shouldUpdateLater:    true,
		},
		{
			name:                 "Shouldn't notify initially, but should notify as soon as latest version is fetched",
			daemonVersion:        "1.0.0",
			initialLatestVersion: nil,
			latestVersion:        v.Must(v.NewSemver("1.0.1")),
			shouldUpdateInit:     false,
			shouldUpdateLater:    true,
		},
	}

	for idx, c := range testMatrix {
		mockUpdate := &versionUpdateMock{latestVersion: c.initialLatestVersion}
		tmpFile := path.Join(t.TempDir(), fmt.Sprintf("update-test-%d.json", idx))
		recorder := peer.NewRecorder("")
		sub := recorder.SubscribeToEvents()
		defer recorder.UnsubscribeFromEvents(sub)

		m := NewManager(recorder, statemanager.New(tmpFile))
		m.update = mockUpdate
		m.currentVersion = c.daemonVersion
		m.Start(context.Background())
		m.SetDownloadOnly()

		ver, enforced := waitForUpdateEvent(sub, 500*time.Millisecond)
		triggeredInit := ver != ""
		if enforced {
			t.Errorf("%s: Linux Mode 1 must never have enforced metadata", c.name)
		}
		if triggeredInit != c.shouldUpdateInit {
			t.Errorf("%s: Initial notify mismatch, expected %v, got %v", c.name, c.shouldUpdateInit, triggeredInit)
		}
		if triggeredInit && c.initialLatestVersion != nil && ver != c.initialLatestVersion.String() {
			t.Errorf("%s: Initial version mismatch, expected %v, got %v", c.name, c.initialLatestVersion.String(), ver)
		}

		mockUpdate.latestVersion = c.latestVersion
		mockUpdate.onUpdate()

		ver, enforced = waitForUpdateEvent(sub, 500*time.Millisecond)
		triggeredLater := ver != ""
		if enforced {
			t.Errorf("%s: Linux Mode 1 must never have enforced metadata", c.name)
		}
		if triggeredLater != c.shouldUpdateLater {
			t.Errorf("%s: Later notify mismatch, expected %v, got %v", c.name, c.shouldUpdateLater, triggeredLater)
		}
		if triggeredLater && c.latestVersion != nil && ver != c.latestVersion.String() {
			t.Errorf("%s: Later version mismatch, expected %v, got %v", c.name, c.latestVersion.String(), ver)
		}

		m.Stop()
	}
}

func Test_SetVersion_NoOp_Linux(t *testing.T) {
	// On Linux, SetVersion should be a no-op — no events fired
	tmpFile := path.Join(t.TempDir(), "update-test-noop.json")
	recorder := peer.NewRecorder("")
	sub := recorder.SubscribeToEvents()
	defer recorder.UnsubscribeFromEvents(sub)

	m := NewManager(recorder, statemanager.New(tmpFile))
	m.update = &versionUpdateMock{latestVersion: v.Must(v.NewSemver("1.0.1"))}
	m.currentVersion = "1.0.0"
	m.Start(context.Background())
	m.SetVersion("1.0.1", false)

	ver, _ := waitForUpdateEvent(sub, 500*time.Millisecond)
	if ver != "" {
		t.Errorf("SetVersion should be a no-op on Linux, but got event with version %s", ver)
	}

	m.Stop()
}
