package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	mcpv1 "git.wntrmute.dev/kyle/mcp/gen/mcp/v1"
	"git.wntrmute.dev/kyle/mcp/internal/config"
	"github.com/spf13/cobra"
)

func pushCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "push <local-file> <service> [path]",
		Short: "Copy a local file into /srv/<service>/[path]",
		Args:  cobra.RangeArgs(2, 3),
		RunE:  runPush,
	}
}

func pullCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "pull <service> <path> [local-file]",
		Short: "Copy a file from /srv/<service>/<path> to local",
		Args:  cobra.RangeArgs(2, 3),
		RunE:  runPull,
	}
}

func runPush(_ *cobra.Command, args []string) error {
	localFile := args[0]
	serviceName := args[1]

	remotePath := filepath.Base(localFile)
	if len(args) == 3 {
		remotePath = args[2]
	}

	f, err := os.Open(localFile) //nolint:gosec // user-specified path
	if err != nil {
		return fmt.Errorf("open local file %q: %w", localFile, err)
	}
	defer func() { _ = f.Close() }()

	info, err := f.Stat()
	if err != nil {
		return fmt.Errorf("stat local file %q: %w", localFile, err)
	}
	mode := uint32(info.Mode().Perm())

	content, err := io.ReadAll(f)
	if err != nil {
		return fmt.Errorf("read local file %q: %w", localFile, err)
	}

	cfg, err := config.LoadCLIConfig(cfgPath)
	if err != nil {
		return fmt.Errorf("load config: %w", err)
	}

	_, address, err := findServiceNode(cfg, serviceName)
	if err != nil {
		return err
	}

	client, conn, err := dialAgent(address, cfg)
	if err != nil {
		return fmt.Errorf("dial agent: %w", err)
	}
	defer func() { _ = conn.Close() }()

	resp, err := client.PushFile(context.Background(), &mcpv1.PushFileRequest{
		Service: serviceName,
		Path:    remotePath,
		Content: content,
		Mode:    mode,
	})
	if err != nil {
		return fmt.Errorf("push file: %w", err)
	}

	if !resp.GetSuccess() {
		return fmt.Errorf("push file: %s", resp.GetError())
	}

	fmt.Printf("Pushed %s to %s:%s/%s\n", localFile, serviceName, "/srv/"+serviceName, remotePath)
	return nil
}

func runPull(_ *cobra.Command, args []string) error {
	serviceName := args[0]
	remotePath := args[1]

	localFile := filepath.Base(remotePath)
	if len(args) == 3 {
		localFile = args[2]
	}

	cfg, err := config.LoadCLIConfig(cfgPath)
	if err != nil {
		return fmt.Errorf("load config: %w", err)
	}

	_, address, err := findServiceNode(cfg, serviceName)
	if err != nil {
		return err
	}

	client, conn, err := dialAgent(address, cfg)
	if err != nil {
		return fmt.Errorf("dial agent: %w", err)
	}
	defer func() { _ = conn.Close() }()

	resp, err := client.PullFile(context.Background(), &mcpv1.PullFileRequest{
		Service: serviceName,
		Path:    remotePath,
	})
	if err != nil {
		return fmt.Errorf("pull file: %w", err)
	}

	if resp.GetError() != "" {
		return fmt.Errorf("pull file: %s", resp.GetError())
	}

	mode := os.FileMode(resp.GetMode())
	if mode == 0 {
		mode = 0o644
	}

	if err := os.WriteFile(localFile, resp.GetContent(), mode); err != nil {
		return fmt.Errorf("write local file %q: %w", localFile, err)
	}

	fmt.Printf("Pulled %s:%s to %s (mode %04o)\n", serviceName, remotePath, localFile, mode)
	return nil
}
