/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025-2026. All rights reserved.
 * KubernetesPlugin is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// Package main run score plugin
package main

import (
	"context"
	"fmt"
	"os"
	"testing"
	"time"

	"bou.ke/monkey"
	"github.com/stretchr/testify/assert"

	"matrixplugin/pkg/communication"
	"matrixplugin/pkg/constant"
	"matrixplugin/pkg/health"
	"matrixplugin/pkg/shmproxy/shmhandle"
)

func TestRunHealthCheckMode(t *testing.T) {
	oldHealthz := *healthz
	defer func() {
		*healthz = oldHealthz
	}()

	*healthz = true

	monkeyRunHealthCheck := monkey.Patch(runHealthCheck, func() int {
		return 0
	})
	defer monkeyRunHealthCheck.Unpatch()

	exitCode := run()

	assert.Equal(t, 0, exitCode)
}

func TestPrepareIpcFailure(t *testing.T) {
	oldHealthz := *healthz
	defer func() {
		*healthz = oldHealthz
	}()

	*healthz = false
	defer monkey.UnpatchAll()
	monkey.Patch(PrepareIpc, func() error {
		return fmt.Errorf("test preipcfailure")
	})

	// run test
	exitCode := run()

	// result verify
	assert.Equal(t, constant.PrepareIPCFailedCode, exitCode)
}

func TestRunUdsServerFailure(t *testing.T) {
	oldHealthz := *healthz
	defer func() {
		*healthz = oldHealthz
	}()

	*healthz = false
	defer monkey.UnpatchAll()
	monkey.Patch(startUdsServer, func() error {
		return fmt.Errorf("test udsserverfailure")
	})
	monkey.Patch(PrepareIpc, func() error { return nil })

	// run test
	exitCode := run()

	// result verify
	assert.Equal(t, constant.StartUdsServerFailedCode, exitCode)
}

func TestRunNormalMode(t *testing.T) {
	oldHealthz := *healthz
	defer func() {
		*healthz = oldHealthz
	}()
	*healthz = false
	defer monkey.UnpatchAll()
	monkey.Patch(startUdsServer, func() error {
		return nil
	})

	monkey.Patch(StartCentralNode, func(fatalErrorChan chan<- error) {
		return
	})

	monkey.Patch(communication.StartServer, func(socketPath string) error {
		return nil
	})

	monkey.Patch(PrepareIpc, func() error { return nil })
	exitCode := 0
	go func() {
		exitCode = run()
	}()

	time.Sleep(sleepDuration)

	assert.Equal(t, 0, exitCode)
}

func TestRunHealthCheckSuccess(t *testing.T) {
	monkeyRunHealthCheck := monkey.Patch(health.RunHealthCheck, func(socketPath string) error {
		return nil
	})
	defer monkeyRunHealthCheck.Unpatch()
	res := runHealthCheck()
	assert.Equal(t, 0, res)
}

func TestRunHealthCheckFail(t *testing.T) {
	monkeyRunHealthCheck := monkey.Patch(health.RunHealthCheck, func(socketPath string) error {
		return fmt.Errorf("test runhealthcheck fail")
	})
	defer monkeyRunHealthCheck.Unpatch()
	res := runHealthCheck()
	assert.Equal(t, 1, res)
}

func TestStartUdsServerSuccess(t *testing.T) {
	monkeyStartUdsServer := monkey.Patch(health.StartUdsServer, func(socketPath string) error {
		return nil
	})
	defer monkeyStartUdsServer.Unpatch()
	res := startUdsServer()
	assert.Equal(t, nil, res)
}

func TestStartUdsServerFail(t *testing.T) {
	monkeyStartUdsServer := monkey.Patch(health.StartUdsServer, func(socketPath string) error {
		return fmt.Errorf("test runhealthcheck fail")
	})
	defer monkeyStartUdsServer.Unpatch()
	err := startUdsServer()
	assert.Error(t, err)
}

func TestStartPeriodicClean(t *testing.T) {
	err := os.Setenv("TIMER_RETRY_INTERVAL", "1")
	if err != nil {
		return
	}
	defer os.Unsetenv("TIMER_RETRY_INTERVAL")

	monkeyIpcCleanEmptyCr := monkey.Patch(shmhandle.CleanEmptyCr, func() {
		return
	})
	defer monkeyIpcCleanEmptyCr.Unpatch()

	_, cancel := context.WithTimeout(context.Background(), sleepDuration)
	defer cancel()
}

func TestStartPeriodicCleanInvalidEnv(t *testing.T) {
	err := os.Setenv("TIMER_RETRY_INTERVAL", "invalid")
	if err != nil {
		return
	}
	defer os.Unsetenv("TIMER_RETRY_INTERVAL")

	monkeyIpcCleanEmptyCr := monkey.Patch(shmhandle.CleanEmptyCr, func() {
		return
	})
	defer monkeyIpcCleanEmptyCr.Unpatch()

	_, cancel := context.WithTimeout(context.Background(), sleepDuration)
	defer cancel()
}