package cli

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/urfave/cli/v2"
	"sneak.berlin/go/mfer/internal/log"
	"sneak.berlin/go/mfer/internal/scanner"
)

func (mfa *CLIApp) generateManifestOperation(ctx *cli.Context) error {
	log.Debug("generateManifestOperation()")

	opts := &scanner.Options{
		IgnoreDotfiles: ctx.Bool("IgnoreDotfiles"),
		FollowSymLinks: ctx.Bool("FollowSymLinks"),
		Fs:             mfa.Fs,
	}

	s := scanner.NewWithOptions(opts)

	// Phase 1: Enumeration - collect paths and stat files
	args := ctx.Args()
	showProgress := ctx.Bool("progress")

	// Set up enumeration progress reporting
	var enumProgress chan scanner.EnumerateStatus
	if showProgress {
		enumProgress = make(chan scanner.EnumerateStatus, 1)
		go func() {
			for status := range enumProgress {
				log.Progressf("Enumerating: %d files, %.1f MB",
					status.FilesFound,
					float64(status.BytesFound)/1e6)
			}
			log.ProgressDone()
		}()
	}

	if args.Len() == 0 {
		// Default to current directory
		if err := s.EnumeratePath(".", enumProgress); err != nil {
			return err
		}
	} else {
		// Collect all paths first
		paths := make([]string, 0, args.Len())
		for i := 0; i < args.Len(); i++ {
			ap, err := filepath.Abs(args.Get(i))
			if err != nil {
				return err
			}
			log.Debugf("enumerating path: %s", ap)
			paths = append(paths, ap)
		}
		if err := s.EnumeratePaths(enumProgress, paths...); err != nil {
			return err
		}
	}

	log.Debugf("enumerated %d files, %d bytes total", s.FileCount(), s.TotalBytes())

	// Open output file
	outputPath := ctx.String("output")
	outFile, err := mfa.Fs.Create(outputPath)
	if err != nil {
		return fmt.Errorf("failed to create output file: %w", err)
	}
	defer outFile.Close()

	// Phase 2: Scan - read file contents and generate manifest
	var scanProgress chan scanner.ScanStatus
	if showProgress {
		scanProgress = make(chan scanner.ScanStatus, 1)
		go func() {
			for status := range scanProgress {
				log.Progressf("Scanning: %d/%d files, %.1f MB/s",
					status.ScannedFiles,
					status.TotalFiles,
					status.BytesPerSec/1e6)
			}
			log.ProgressDone()
		}()
	}

	err = s.ToManifest(ctx.Context, outFile, scanProgress)
	if err != nil {
		return fmt.Errorf("failed to generate manifest: %w", err)
	}

	if !ctx.Bool("quiet") {
		elapsed := time.Since(mfa.startupTime).Seconds()
		rate := float64(s.TotalBytes()) / elapsed / 1e6
		log.Infof("wrote %d files (%.1f MB) to %s in %.1fs (%.1f MB/s)", s.FileCount(), float64(s.TotalBytes())/1e6, outputPath, elapsed, rate)
	}

	return nil
}
