package services

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestUpdateService_CheckForUpdates(t *testing.T) {
	// Mock GitHub API
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/releases/latest" {
			w.WriteHeader(http.StatusNotFound)
			return
		}

		release := githubRelease{
			TagName: "v1.0.0",
			HTMLURL: "https://github.com/Wikid82/charon/releases/tag/v1.0.0",
		}
		json.NewEncoder(w).Encode(release)
	}))
	defer server.Close()

	us := NewUpdateService()
	us.SetAPIURL(server.URL + "/releases/latest")
	// us.currentVersion is private, so we can't set it directly in test unless we export it or add a setter.
	// However, NewUpdateService sets it from version.Version.
	// We can temporarily change version.Version if it's a var, but it's likely a const or var in another package.
	// Let's check version package.
	// Assuming version.Version is a var we can change, or we add a SetCurrentVersion method for testing.
	// For now, let's assume we can't change it easily without a setter.
	// Let's add SetCurrentVersion to UpdateService for testing purposes.
	us.SetCurrentVersion("0.9.0")

	// Test Update Available
	info, err := us.CheckForUpdates()
	assert.NoError(t, err)
	assert.True(t, info.Available)
	assert.Equal(t, "v1.0.0", info.LatestVersion)
	assert.Equal(t, "https://github.com/Wikid82/charon/releases/tag/v1.0.0", info.ChangelogURL)

	// Test No Update Available
	us.SetCurrentVersion("1.0.0")
	// us.cachedResult = nil // cachedResult is private
	// us.lastCheck = time.Time{} // lastCheck is private
	us.ClearCache() // Add this method

	info, err = us.CheckForUpdates()
	assert.NoError(t, err)
	assert.False(t, info.Available)
	assert.Equal(t, "v1.0.0", info.LatestVersion)

	// Test Cache
	// If we call again immediately, it should use cache.
	// We can verify this by closing the server or changing the response, but cache logic is simple.
	// Let's change the server handler? No, httptest server handler is fixed.
	// But we can check if it returns the same object.
	info2, err := us.CheckForUpdates()
	assert.NoError(t, err)
	assert.Equal(t, info, info2)

	// Test Error (Server Down)
	server.Close()
	us.cachedResult = nil
	us.lastCheck = time.Time{}

	// Depending on implementation, it might return error or just available=false
	// Implementation:
	// resp, err := client.Do(req) -> returns error if connection refused
	// if err != nil { return nil, err }
	_, err = us.CheckForUpdates()
	assert.Error(t, err)
}
