package nostrfs

import (
	"context"
	"sync/atomic"
	"syscall"

	"github.com/hanwen/go-fuse/v2/fs"
	"github.com/hanwen/go-fuse/v2/fuse"
	"fiatjaf.com/nostr"
)

type AsyncFile struct {
	fs.Inode
	ctx     context.Context
	fetched atomic.Bool
	data    []byte
	ts      nostr.Timestamp
	load    func() ([]byte, nostr.Timestamp)
}

var (
	_ = (fs.NodeOpener)((*AsyncFile)(nil))
	_ = (fs.NodeGetattrer)((*AsyncFile)(nil))
)

func (af *AsyncFile) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
	if af.fetched.CompareAndSwap(false, true) {
		af.data, af.ts = af.load()
	}

	out.Size = uint64(len(af.data))
	out.Mtime = uint64(af.ts)
	return fs.OK
}

func (af *AsyncFile) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
	if af.fetched.CompareAndSwap(false, true) {
		af.data, af.ts = af.load()
	}

	return nil, fuse.FOPEN_KEEP_CACHE, 0
}

func (af *AsyncFile) Read(
	ctx context.Context,
	f fs.FileHandle,
	dest []byte,
	off int64,
) (fuse.ReadResult, syscall.Errno) {
	end := int(off) + len(dest)
	if end > len(af.data) {
		end = len(af.data)
	}
	return fuse.ReadResultData(af.data[off:end]), 0
}