package cmd

import (
	"fmt"
	"os"

	"git.wntrmute.dev/kyle/arca/internal/config"
	"git.wntrmute.dev/kyle/arca/internal/cryptsetup"
	"git.wntrmute.dev/kyle/arca/internal/udisks"
	"git.wntrmute.dev/kyle/arca/internal/unlock"
	"github.com/spf13/cobra"
	"golang.org/x/term"
)

var mountpoint string

var mountCmd = &cobra.Command{
	Use:               "mount <device|alias>",
	Short:             "Unlock and mount a LUKS volume",
	Args:              cobra.ExactArgs(1),
	RunE:              runMount,
	ValidArgsFunction: completeDeviceOrAlias,
}

func init() {
	mountCmd.Flags().StringVarP(&mountpoint, "mountpoint", "m", "", "mount point override (privileged path only)")
	rootCmd.AddCommand(mountCmd)
}

func runMount(cmd *cobra.Command, args []string) error {
	cfg := config.Load()
	target := args[0]

	client, err := udisks.NewClient()
	if err != nil {
		return fmt.Errorf("connecting to udisks2: %w", err)
	}
	defer client.Close()

	devCfg := cfg.ResolveDevice(target)

	// CLI flag overrides config mountpoint.
	mp := devCfg.Mountpoint
	if mountpoint != "" {
		mp = mountpoint
	}

	dev, err := client.FindDevice(devCfg.UUID, target)
	if err != nil {
		return err
	}

	// Check if already unlocked.
	if cleartext, err := client.CleartextDevice(dev); err == nil {
		// Already unlocked — check if mounted too.
		if existing, mounted := client.IsMounted(cleartext); mounted {
			fmt.Println(existing)
			return nil
		}
		// Unlocked but not mounted — just mount it.
		return doMount(client, cleartext, mp)
	}

	// Need to unlock.
	u := unlock.New(client, unlock.Options{
		ReadPassphrase: readPassphrase,
		KeyfilePath:    devCfg.Keyfile,
	})

	result, err := u.Unlock(dev, devCfg.Methods)
	if err != nil {
		return err
	}

	if result.Privileged {
		mnt, err := cryptsetup.Mount(result.Device.DevicePath, mp)
		if err != nil {
			return fmt.Errorf("mounting: %w", err)
		}
		fmt.Println(mnt)
		return nil
	}

	if mp != "" {
		fmt.Fprintf(os.Stderr, "warning: --mountpoint is ignored for udisks2 mounts (passphrase/keyfile path)\n")
	}
	return doMount(client, result.Device, "")
}

func doMount(client *udisks.Client, cleartext *udisks.BlockDevice, mp string) error {
	if mp != "" {
		// udisks2 doesn't support custom mount points; use privileged mount.
		mnt, err := cryptsetup.Mount(cleartext.DevicePath, mp)
		if err != nil {
			return fmt.Errorf("mounting: %w", err)
		}
		fmt.Println(mnt)
		return nil
	}
	mnt, err := client.Mount(cleartext)
	if err != nil {
		return fmt.Errorf("mounting: %w", err)
	}
	fmt.Println(mnt)
	return nil
}

func readPassphrase() (string, error) {
	fmt.Fprint(os.Stderr, "Passphrase: ")
	pass, err := term.ReadPassword(int(os.Stdin.Fd()))
	fmt.Fprintln(os.Stderr)
	if err != nil {
		return "", fmt.Errorf("reading passphrase: %w", err)
	}
	return string(pass), nil
}
