package bridge

import (
	"context"
	"errors"
	"os"
	"testing"
	"time"
)

type fakeFileInfo struct{}

func (fakeFileInfo) Name() string       { return "fake" }
func (fakeFileInfo) Size() int64        { return 0 }
func (fakeFileInfo) Mode() os.FileMode  { return 0 }
func (fakeFileInfo) ModTime() time.Time { return time.Time{} }
func (fakeFileInfo) IsDir() bool        { return false }
func (fakeFileInfo) Sys() any           { return nil }

func TestWaitForLocalAPIReadyRetriesUntilSuccess(t *testing.T) {
	t.Parallel()

	attempts := 0
	err := waitForLocalAPIReady(context.Background(), 200*time.Millisecond, 5*time.Millisecond, func(context.Context) error {
		attempts++
		if attempts < 3 {
			return errors.New("not ready")
		}
		return nil
	})
	if err != nil {
		t.Fatalf("waitForLocalAPIReady() error = %v", err)
	}
	if attempts != 3 {
		t.Fatalf("attempts = %d, want 3", attempts)
	}
}

func TestWaitForLocalAPIReadyReturnsLastErrorOnTimeout(t *testing.T) {
	t.Parallel()

	wantErr := errors.New("still down")
	err := waitForLocalAPIReady(context.Background(), 30*time.Millisecond, 5*time.Millisecond, func(context.Context) error {
		return wantErr
	})
	if !errors.Is(err, wantErr) {
		t.Fatalf("waitForLocalAPIReady() error = %v, want %v", err, wantErr)
	}
}

func TestProbeServiceStatusReportsReadyWhenSocketExists(t *testing.T) {
	t.Parallel()

	status := probeServiceStatus(
		"/run/mirage/miraged.sock",
		func(string) (string, error) { return "", errors.New("no systemctl") },
		func(args ...string) ([]byte, error) { return nil, errors.New("unexpected run") },
		func(string) (os.FileInfo, error) { return fakeFileInfo{}, nil },
	)

	if !status.SocketReady {
		t.Fatalf("SocketReady = false, want true")
	}
	if status.Message != "后台服务已就绪" {
		t.Fatalf("Message = %q, want 后台服务已就绪", status.Message)
	}
}

func TestProbeServiceStatusReportsStartingWhenActiveWithoutSocket(t *testing.T) {
	t.Parallel()

	status := probeServiceStatus(
		"/run/mirage/miraged.sock",
		func(string) (string, error) { return "/bin/systemctl", nil },
		func(args ...string) ([]byte, error) {
			switch args[0] {
			case "is-active":
				return []byte("active\n"), nil
			case "is-enabled":
				return []byte("enabled\n"), nil
			default:
				return nil, errors.New("unexpected args")
			}
		},
		func(string) (os.FileInfo, error) { return nil, os.ErrNotExist },
	)

	if !status.Active {
		t.Fatalf("Active = false, want true")
	}
	if status.SocketReady {
		t.Fatalf("SocketReady = true, want false")
	}
	if status.Message != "后台服务正在启动" {
		t.Fatalf("Message = %q, want 后台服务正在启动", status.Message)
	}
}

func TestProbeServiceStatusReportsStoppedWhenInactiveAndNoSocket(t *testing.T) {
	t.Parallel()

	status := probeServiceStatus(
		"/run/mirage/miraged.sock",
		func(string) (string, error) { return "/bin/systemctl", nil },
		func(args ...string) ([]byte, error) { return nil, errors.New("inactive") },
		func(string) (os.FileInfo, error) { return nil, os.ErrNotExist },
	)

	if status.Active {
		t.Fatalf("Active = true, want false")
	}
	if status.SocketReady {
		t.Fatalf("SocketReady = true, want false")
	}
	if status.Message != "后台服务未启动" {
		t.Fatalf("Message = %q, want 后台服务未启动", status.Message)
	}
}
