package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func orasLogin(registry, username, password string) error {
	if strings.TrimSpace(username) == "" || strings.TrimSpace(password) == "" {
		return fmt.Errorf("harbor credentials missing")
	}
	cmd := exec.Command("oras", "login", registry, "-u", username, "-p", password)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%w: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func orasPush(ref, imagePath, metadataPath string) error {
	dir, args, err := orasPushInvocation(ref, imagePath, metadataPath)
	if err != nil {
		return err
	}
	cmd := exec.Command("oras", args...)
	cmd.Dir = dir
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%w: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func orasPushInvocation(ref, imagePath, metadataPath string) (string, []string, error) {
	imageDir := filepath.Dir(imagePath)
	metadataDir := filepath.Dir(metadataPath)
	if imageDir != metadataDir {
		return "", nil, fmt.Errorf("oras push requires artifacts in one directory: %s vs %s", imageDir, metadataDir)
	}
	return imageDir, []string{
		"push",
		ref,
		fmt.Sprintf("%s:application/x-raw-disk-image", filepath.Base(imagePath)),
		fmt.Sprintf("%s:application/json", filepath.Base(metadataPath)),
	}, nil
}

func orasTag(ref string, tags ...string) error {
	args := append([]string{"tag", ref}, tags...)
	cmd := exec.Command("oras", args...)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%w: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func orasPull(ref, outDir string) error {
	cmd := exec.Command("oras", "pull", ref, "-o", outDir)
	if out, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("%w: %s", err, strings.TrimSpace(string(out)))
	}
	return nil
}

func resolvePulledArtifact(dir string) (string, bool, error) {
	var rawPath string
	var compressedPath string
	err := filepath.WalkDir(dir, func(path string, d os.DirEntry, walkErr error) error {
		if walkErr != nil {
			return walkErr
		}
		if d.IsDir() {
			return nil
		}
		switch {
		case strings.HasSuffix(path, ".img.xz"):
			compressedPath = path
		case strings.HasSuffix(path, ".img"):
			rawPath = path
		}
		return nil
	})
	if err != nil {
		return "", false, err
	}
	if compressedPath != "" {
		return compressedPath, true, nil
	}
	if rawPath != "" {
		return rawPath, false, nil
	}
	return "", false, fmt.Errorf("no .img or .img.xz artifact found in %s", dir)
}
