package plugins

import (
	"context"
	"path/filepath"
	"time"

	"github.com/navidrome/navidrome/core/scrobbler"
	"github.com/navidrome/navidrome/model"
	"github.com/navidrome/navidrome/tests"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

var _ = Describe("removePluginFromDB", func() {
	It("discards buffered scrobbles for the removed plugin", func() {
		ctx := context.Background()
		buffer := tests.CreateMockedScrobbleBufferRepo()
		Expect(buffer.Enqueue("my-plugin", "user1", "track1", time.Now())).To(Succeed())
		Expect(buffer.Enqueue("other-plugin", "user1", "track2", time.Now())).To(Succeed())

		repo := tests.CreateMockPluginRepo()
		plugin := model.Plugin{ID: "my-plugin", Enabled: false}
		repo.SetData(model.Plugins{plugin})

		// No broker: sendPluginRefreshEvent is nil-safe, and testBroker is
		// defined in manager_test.go, which is excluded on Windows.
		m := &Manager{
			ds: &tests.MockDataStore{MockedScrobbleBuffer: buffer},
		}
		Expect(m.removePluginFromDB(ctx, repo, &plugin)).To(Succeed())

		_, err := repo.Get("my-plugin")
		Expect(err).To(MatchError(model.ErrNotFound))

		remaining, err := buffer.Length()
		Expect(err).ToNot(HaveOccurred())
		Expect(remaining).To(Equal(int64(1)))
		entry, err := buffer.Next("other-plugin", "user1")
		Expect(err).ToNot(HaveOccurred())
		Expect(entry).ToNot(BeNil(), "entries of other services must be kept")
	})

	It("keeps buffered scrobbles of a builtin scrobbler sharing the removed plugin's name", func() {
		ctx := context.Background()
		scrobbler.Register("builtin-svc", func(model.DataStore) scrobbler.Scrobbler { return nil })
		buffer := tests.CreateMockedScrobbleBufferRepo()
		Expect(buffer.Enqueue("builtin-svc", "user1", "track1", time.Now())).To(Succeed())

		repo := tests.CreateMockPluginRepo()
		plugin := model.Plugin{ID: "builtin-svc", Enabled: false}
		repo.SetData(model.Plugins{plugin})

		m := &Manager{
			ds: &tests.MockDataStore{MockedScrobbleBuffer: buffer},
		}
		Expect(m.removePluginFromDB(ctx, repo, &plugin)).To(Succeed())

		remaining, err := buffer.Length()
		Expect(err).ToNot(HaveOccurred())
		Expect(remaining).To(Equal(int64(1)), "builtin scrobbler queue must not be wiped")
	})
})

var _ = Describe("ComputeFileSHA256", func() {
	It("returns a consistent 64-char lowercase hex hash for the same file", func() {
		dir := GinkgoT().TempDir()
		ndpPath := filepath.Join(dir, "test.ndp")
		err := createTestPackage(ndpPath, &Manifest{Name: "S", Author: "a", Version: "1.0.0"}, []byte{0x00, 0x61, 0x73, 0x6d})
		Expect(err).ToNot(HaveOccurred())

		hash1, err := ComputeFileSHA256(ndpPath)
		Expect(err).ToNot(HaveOccurred())
		hash2, err := ComputeFileSHA256(ndpPath)
		Expect(err).ToNot(HaveOccurred())

		Expect(hash1).To(Equal(hash2))
		Expect(hash1).To(MatchRegexp(`^[0-9a-f]{64}$`))
	})

	It("returns an error for a non-existent path", func() {
		_, err := ComputeFileSHA256(filepath.Join(GinkgoT().TempDir(), "does-not-exist.ndp"))
		Expect(err).To(HaveOccurred())
	})
})
