package cmd

import (
	"archive/zip"
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"

	"omixlab.com/mosis-portal/pkg/mospkg"
)

// SignCmd returns the sign command
func SignCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "sign <package>",
		Short: "Sign a .mosis package",
		Long:  "Sign a Mosis package with your Ed25519 developer key.",
		Args:  cobra.ExactArgs(1),
		RunE:  runSign,
	}

	cmd.Flags().StringP("key", "k", "", "Path to private key (default: ~/.mosis/signing_key.pem)")
	cmd.Flags().Bool("verify", false, "Verify existing signature instead of signing")
	cmd.Flags().StringP("output", "o", "", "Output path (default: overwrite input)")

	return cmd
}

func runSign(cmd *cobra.Command, args []string) error {
	packagePath := args[0]

	// Check package exists
	if _, err := os.Stat(packagePath); os.IsNotExist(err) {
		return fmt.Errorf("package not found: %s", packagePath)
	}

	// Verify mode
	verify, _ := cmd.Flags().GetBool("verify")
	if verify {
		return verifyPackage(cmd, packagePath)
	}

	// Sign mode
	keyPath, _ := cmd.Flags().GetString("key")
	if keyPath == "" {
		keyPath = filepath.Join(ConfigDir(), "signing_key.pem")
	}

	// Load private key
	keyData, err := os.ReadFile(keyPath)
	if err != nil {
		return fmt.Errorf("failed to read key: %s\n\nGenerate a key with: mosis keys generate", keyPath)
	}

	privateKey, err := mospkg.LoadPrivateKey(keyData)
	if err != nil {
		return fmt.Errorf("invalid key: %w", err)
	}

	// Get public key fingerprint
	publicKey := privateKey.Public().(interface{ Bytes() []byte })
	fingerprint := mospkg.PublicKeyFingerprint(publicKey.Bytes())

	fmt.Printf("Using key: %s\n", keyPath)
	fmt.Printf("Fingerprint: %s\n\n", fingerprint)

	// Determine output path
	output, _ := cmd.Flags().GetString("output")
	if output == "" {
		// Sign in place by creating temp file
		output = packagePath + ".signed"
	}

	// Generate manifest and sign
	fmt.Println("Generating file hashes...")
	fmt.Println("Signing MANIFEST.MF...")

	if err := mospkg.SignPackage(packagePath, output, privateKey); err != nil {
		return fmt.Errorf("sign package: %w", err)
	}

	// If signing in place, replace original
	if output == packagePath+".signed" {
		if err := os.Rename(output, packagePath); err != nil {
			return fmt.Errorf("replace original: %w", err)
		}
		output = packagePath
	}

	// Count files in package
	fileCount := countPackageFiles(output)

	fmt.Printf("\n✓ Package signed: %s\n", output)
	fmt.Println("\nSignature details:")
	fmt.Println("  Algorithm: Ed25519")
	fmt.Printf("  Key fingerprint: %s\n", fingerprint)
	fmt.Printf("  Files signed: %d\n", fileCount)

	return nil
}

func verifyPackage(cmd *cobra.Command, packagePath string) error {
	keyPath, _ := cmd.Flags().GetString("key")

	// Try to load public key
	var pubKeyPath string
	if keyPath != "" {
		pubKeyPath = keyPath
	} else {
		// Try default locations
		pubKeyPath = filepath.Join(ConfigDir(), "signing_key.pub")
	}

	keyData, err := os.ReadFile(pubKeyPath)
	if err != nil {
		return fmt.Errorf("public key not found: %s\n\nProvide key with --key flag", pubKeyPath)
	}

	publicKey, err := mospkg.LoadPublicKey(keyData)
	if err != nil {
		return fmt.Errorf("invalid public key: %w", err)
	}

	fmt.Printf("Verifying: %s\n", packagePath)
	fmt.Printf("Using key: %s\n\n", pubKeyPath)

	valid, err := mospkg.VerifyPackageSignature(packagePath, publicKey)
	if err != nil {
		return fmt.Errorf("verification failed: %w", err)
	}

	if valid {
		fmt.Println("✓ Signature is valid")
		fmt.Println("✓ All file hashes match")
		return nil
	}

	return fmt.Errorf("✗ Signature verification failed")
}

func countPackageFiles(path string) int {
	reader, err := zip.OpenReader(path)
	if err != nil {
		return 0
	}
	defer reader.Close()

	count := 0
	for _, f := range reader.File {
		if !f.FileInfo().IsDir() {
			count++
		}
	}
	return count
}
