//go:build linux || (darwin && amd64)

package mount

import (
	fusefs "github.com/hanwen/go-fuse/v2/fs"
	"github.com/hanwen/go-fuse/v2/fuse"
	"gitlink.org.cn/cloudream/common/pkgs/async"
	db2 "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
	"gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader"
	"gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/config"
	fuse2 "gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/fuse"
	"gitlink.org.cn/cloudream/jcs-pub/client/internal/mount/vfs"
	"gitlink.org.cn/cloudream/jcs-pub/client/internal/uploader"
	clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
)

type Mount struct {
	cfg        *config.Config
	vfs        *vfs.Vfs
	fuse       *fuse2.Fuse
	fuseServer *fuse.Server
	eventChan  *MountEventChan
}

func NewMount(cfg *config.Config, db *db2.DB, uploader *uploader.Uploader, downloader *downloader.Downloader) *Mount {
	mnt := &Mount{
		cfg:       cfg,
		eventChan: async.NewUnboundChannel[MountEvent](),
	}

	if cfg != nil {
		mnt.vfs = vfs.NewVfs(cfg, db, uploader, downloader)
		mnt.fuse = fuse2.NewFuse(cfg, mnt.vfs)
	}

	return mnt
}

func (m *Mount) Start() *MountEventChan {
	if m.cfg == nil {
		return m.eventChan
	}

	go func() {
		m.vfs.Start()
		defer m.vfs.Stop()

		nodeFsOpt := &fusefs.Options{
			MountOptions: fuse.MountOptions{
				AllowOther: true,
				FsName:     "CDS",
				// Debug:  true,
			},
			GID: m.cfg.GID,
			UID: m.cfg.UID,
		}
		rawFs := fusefs.NewNodeFS(m.fuse.Root(), nodeFsOpt)

		svr, err := fuse.NewServer(rawFs, m.cfg.MountPoint, &nodeFsOpt.MountOptions)
		if err != nil {
			m.eventChan.Send(ExitEvent{Err: err})
			return
		}

		m.fuseServer = svr

		svr.Serve()
		m.eventChan.Send(ExitEvent{})
	}()
	return m.eventChan
}

func (m *Mount) Stop() {
	if m.fuseServer == nil {
		m.eventChan.Send(ExitEvent{})
		return
	}

	m.fuseServer.Unmount()
}

func (m *Mount) MountPoint() string {
	if m.cfg == nil {
		return ""
	}

	return m.cfg.MountPoint
}

func (m *Mount) Dump() MountStatus {
	if m.vfs == nil {
		return MountStatus{}
	}

	cacheStatus := m.vfs.Dump()
	return MountStatus{
		Cache: cacheStatus,
	}
}

func (m *Mount) NotifyObjectInvalid(obj clitypes.Object) {

}

func (m *Mount) NotifyPackageInvalid(pkg clitypes.Package) {

}

func (m *Mount) NotifyBucketInvalid(bkt clitypes.Bucket) {

}
