package cloud

import (
	"context"

	"github.com/safedep/dry/log"
	"github.com/safedep/pmg/config"
	"github.com/safedep/pmg/internal/audit"
	"github.com/spf13/cobra"
)

// newSyncBackgroundCommand returns the hidden subcommand invoked by the
// detached child that audit.MaybeSpawnBackgroundSync forks. Always exits 0:
// the parent has already returned to the user's shell by the time this runs,
// so a non-zero exit would only show up to whatever (init / launchd) reaped
// the orphaned process.
func newSyncBackgroundCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:    audit.SyncBackgroundSubcommand,
		Short:  "Internal: drain the cloud sync WAL from a detached child process",
		Hidden: true,
		RunE:   runSyncBackground,
	}
	return cmd
}

func runSyncBackground(cmd *cobra.Command, args []string) error {
	audit.MarkBackgroundSyncChild()

	cfg := config.Get()

	if !cfg.Config.Cloud.Enabled || !cfg.Config.Cloud.AutoSync.Enabled {
		log.Debugf("Auto-sync: cloud or auto_sync disabled; exiting")
		return nil
	}

	lock := audit.NewSyncLock(cfg.CloudSyncLockPath())

	locked, err := lock.TryLock()
	if err != nil {
		log.Warnf("Auto-sync: failed to acquire lock: %v", err)
		return nil
	}
	if !locked {
		log.Debugf("Auto-sync: another sync is in progress; exiting")
		return nil
	}
	defer func() {
		if err := lock.Unlock(); err != nil {
			log.Warnf("Auto-sync: failed to release lock: %v", err)
		}
	}()

	// Re-check cooldown under the lock to close the TOCTOU window between the
	// parent's pre-fork stat and our acquisition.
	if !audit.SyncCooldownElapsed(cfg.CloudSyncLastRunPath(), cfg.Config.Cloud.AutoSync.MinInterval) {
		log.Debugf("Auto-sync: cooldown still in effect under lock; exiting")
		return nil
	}

	ctx, cancel := context.WithTimeout(cmd.Context(), cfg.Config.Cloud.AutoSync.Timeout)
	defer cancel()

	bundle, err := audit.NewSyncClientBundle(cfg)
	if err != nil {
		log.Warnf("Auto-sync: failed to initialize sync client: %v", err)
		recordLastSyncAttempt(cfg)
		return nil
	}
	defer func() {
		if err := bundle.Close(); err != nil {
			log.Warnf("Auto-sync: failed to close sync client: %v", err)
		}
	}()

	synced, err := bundle.Sync(ctx)
	recordLastSyncAttempt(cfg)
	if err != nil {
		log.Warnf("Auto-sync: sync failed after %d events: %v", synced, err)
		return nil
	}

	log.Infof("Auto-sync: drained %d events to SafeDep Cloud", synced)
	return nil
}

// recordLastSyncAttempt updates the cooldown timestamp on every attempt so a
// failing cloud endpoint does not cause every PMG invocation to retry.
func recordLastSyncAttempt(cfg *config.RuntimeConfig) {
	if err := audit.WriteLastSyncAttempt(cfg.CloudSyncLastRunPath()); err != nil {
		log.Warnf("failed to update cloud sync lastrun: %v", err)
	}
}
