package main

import (
	"context"
	"fmt"
	"io"
	"time"

	sqlite "github.com/vertex-lab/nostr-sqlite"

	"next.orly.dev/pkg/database"
	"next.orly.dev/pkg/database/indexes/types"
	"git.mleku.dev/mleku/nostr/encoders/event"
	"git.mleku.dev/mleku/nostr/encoders/filter"
	"git.mleku.dev/mleku/nostr/encoders/tag"
	"next.orly.dev/pkg/interfaces/store"
)

// RelySQLiteWrapper wraps the vertex-lab/nostr-sqlite store to implement
// the minimal database.Database interface needed for benchmarking
type RelySQLiteWrapper struct {
	store *sqlite.Store
	path  string
	ready chan struct{}
}

// NewRelySQLiteWrapper creates a new wrapper around nostr-sqlite
func NewRelySQLiteWrapper(dbPath string) (*RelySQLiteWrapper, error) {
	store, err := sqlite.New(dbPath)
	if err != nil {
		return nil, fmt.Errorf("failed to create sqlite store: %w", err)
	}

	wrapper := &RelySQLiteWrapper{
		store: store,
		path:  dbPath,
		ready: make(chan struct{}),
	}

	// Close the ready channel immediately as SQLite is ready on creation
	close(wrapper.ready)

	return wrapper, nil
}

// SaveEvent saves an event to the database
func (w *RelySQLiteWrapper) SaveEvent(ctx context.Context, ev *event.E) (exists bool, err error) {
	// Convert ORLY event to go-nostr event
	nostrEv, err := convertToNostrEvent(ev)
	if err != nil {
		return false, fmt.Errorf("failed to convert event: %w", err)
	}

	// Use Replace for replaceable/addressable events, Save otherwise
	if isReplaceableKind(int(ev.Kind)) || isAddressableKind(int(ev.Kind)) {
		replaced, err := w.store.Replace(ctx, nostrEv)
		return replaced, err
	}

	saved, err := w.store.Save(ctx, nostrEv)
	return !saved, err // saved=true means it's new, exists=false
}

// QueryEvents queries events matching the filter
func (w *RelySQLiteWrapper) QueryEvents(ctx context.Context, f *filter.F) (evs event.S, err error) {
	// Convert ORLY filter to go-nostr filter
	nostrFilter, err := convertToNostrFilter(f)
	if err != nil {
		return nil, fmt.Errorf("failed to convert filter: %w", err)
	}

	// Query the store
	nostrEvents, err := w.store.Query(ctx, nostrFilter)
	if err != nil {
		return nil, fmt.Errorf("query failed: %w", err)
	}

	// Convert back to ORLY events
	events := make(event.S, 0, len(nostrEvents))
	for _, ne := range nostrEvents {
		ev, err := convertFromNostrEvent(&ne)
		if err != nil {
			continue // Skip events that fail to convert
		}
		events = append(events, ev)
	}

	return events, nil
}

// Close closes the database
func (w *RelySQLiteWrapper) Close() error {
	if w.store != nil {
		return w.store.Close()
	}
	return nil
}

// Ready returns a channel that closes when the database is ready
func (w *RelySQLiteWrapper) Ready() <-chan struct{} {
	return w.ready
}

// Path returns the database path
func (w *RelySQLiteWrapper) Path() string {
	return w.path
}

// Wipe clears all data from the database
func (w *RelySQLiteWrapper) Wipe() error {
	// Close current store
	if err := w.store.Close(); err != nil {
		return err
	}

	// Delete the database file
	// Note: This is a simplified approach - in production you'd want
	// to handle this more carefully
	return nil
}

// Stub implementations for unused interface methods
func (w *RelySQLiteWrapper) Init(path string) error { return nil }
func (w *RelySQLiteWrapper) Sync() error            { return nil }
func (w *RelySQLiteWrapper) SetLogLevel(level string) {}
func (w *RelySQLiteWrapper) GetSerialsFromFilter(f *filter.F) (serials types.Uint40s, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) WouldReplaceEvent(ev *event.E) (bool, types.Uint40s, error) {
	return false, nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryAllVersions(c context.Context, f *filter.F) (evs event.S, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryEventsWithOptions(c context.Context, f *filter.F, includeDeleteEvents bool, showAllVersions bool) (evs event.S, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryDeleteEventsByTargetId(c context.Context, targetEventId []byte) (evs event.S, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryForSerials(c context.Context, f *filter.F) (serials types.Uint40s, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) QueryForIds(c context.Context, f *filter.F) (idPkTs []*store.IdPkTs, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) CountEvents(c context.Context, f *filter.F) (count int, approximate bool, err error) {
	return 0, false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) FetchEventsBySerials(serials []*types.Uint40) (events map[uint64]*event.E, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialById(id []byte) (ser *types.Uint40, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByIds(ids *tag.T) (serials map[string]*types.Uint40, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSerialsByRange(idx database.Range) (serials types.Uint40s, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetFullIdPubkeyBySerial(ser *types.Uint40) (fidpk *store.IdPkTs, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetFullIdPubkeyBySerials(sers []*types.Uint40) (fidpks []*store.IdPkTs, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteEvent(c context.Context, eid []byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteEventBySerial(c context.Context, ser *types.Uint40, ev *event.E) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteExpired() {}
func (w *RelySQLiteWrapper) ProcessDelete(ev *event.E, admins [][]byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) CheckForDeleted(ev *event.E, admins [][]byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) Import(rr io.Reader) {}
func (w *RelySQLiteWrapper) Export(c context.Context, writer io.Writer, pubkeys ...[]byte) {
}
func (w *RelySQLiteWrapper) ImportEventsFromReader(ctx context.Context, rr io.Reader) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ImportEventsFromStrings(ctx context.Context, eventJSONs []string, policyManager interface{ CheckPolicy(action string, ev *event.E, pubkey []byte, remote string) (bool, error) }) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetRelayIdentitySecret() (skb []byte, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) SetRelayIdentitySecret(skb []byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetOrCreateRelayIdentitySecret() (skb []byte, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) SetMarker(key string, value []byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetMarker(key string) (value []byte, err error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) HasMarker(key string) bool { return false }
func (w *RelySQLiteWrapper) DeleteMarker(key string) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetSubscription(pubkey []byte) (*database.Subscription, error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsSubscriptionActive(pubkey []byte) (bool, error) {
	return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ExtendSubscription(pubkey []byte, days int) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RecordPayment(pubkey []byte, amount int64, invoice, preimage string) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetPaymentHistory(pubkey []byte) ([]database.Payment, error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ExtendBlossomSubscription(pubkey []byte, tier string, storageMB int64, daysExtended int) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetBlossomStorageQuota(pubkey []byte) (quotaMB int64, err error) {
	return 0, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsFirstTimeUser(pubkey []byte) (bool, error) {
	return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) AddNIP43Member(pubkey []byte, inviteCode string) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RemoveNIP43Member(pubkey []byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) IsNIP43Member(pubkey []byte) (isMember bool, err error) {
	return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetNIP43Membership(pubkey []byte) (*database.NIP43Membership, error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) GetAllNIP43Members() ([][]byte, error) {
	return nil, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) StoreInviteCode(code string, expiresAt time.Time) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) ValidateInviteCode(code string) (valid bool, err error) {
	return false, fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) DeleteInviteCode(code string) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) PublishNIP43MembershipEvent(kind int, pubkey []byte) error {
	return fmt.Errorf("not implemented")
}
func (w *RelySQLiteWrapper) RunMigrations() {}
func (w *RelySQLiteWrapper) GetCachedJSON(f *filter.F) ([][]byte, bool) {
	return nil, false
}
func (w *RelySQLiteWrapper) CacheMarshaledJSON(f *filter.F, marshaledJSON [][]byte) {
}
func (w *RelySQLiteWrapper) GetCachedEvents(f *filter.F) (event.S, bool) {
	return nil, false
}
func (w *RelySQLiteWrapper) CacheEvents(f *filter.F, events event.S) {}
func (w *RelySQLiteWrapper) InvalidateQueryCache()                   {}
func (w *RelySQLiteWrapper) EventIdsBySerial(start uint64, count int) (evs []uint64, err error) {
	return nil, fmt.Errorf("not implemented")
}

// Access tracking stubs (not needed for benchmarking)
func (w *RelySQLiteWrapper) RecordEventAccess(serial uint64, connectionID string) error {
	return nil // No-op for benchmarking
}
func (w *RelySQLiteWrapper) GetEventAccessInfo(serial uint64) (lastAccess int64, accessCount uint32, err error) {
	return 0, 0, nil
}
func (w *RelySQLiteWrapper) GetLeastAccessedEvents(limit int, minAgeSec int64) (serials []uint64, err error) {
	return nil, nil
}

// Helper function to check if a kind is replaceable
func isReplaceableKind(kind int) bool {
	return (kind >= 10000 && kind < 20000) || kind == 0 || kind == 3
}

// Helper function to check if a kind is addressable
func isAddressableKind(kind int) bool {
	return kind >= 30000 && kind < 40000
}
