// download.go fetches a remote file (presigned MinIO URL or any HTTP URL) and
// saves it to a local path. Uses stdlib only — no external HTTP client needed.
package runner

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
)

// DownloadFile fetches the resource at rawURL and writes it to destPath,
// creating parent directories as needed. Returns the number of bytes written.
func DownloadFile(ctx context.Context, rawURL, destPath string) (int64, error) {
	if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
		return 0, fmt.Errorf("mkdir: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)
	if err != nil {
		return 0, fmt.Errorf("new request: %w", err)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return 0, fmt.Errorf("GET: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return 0, fmt.Errorf("server returned %d", resp.StatusCode)
	}

	f, err := os.Create(destPath)
	if err != nil {
		return 0, fmt.Errorf("create file: %w", err)
	}
	defer f.Close()

	n, err := io.Copy(f, resp.Body)
	if err != nil {
		return 0, fmt.Errorf("write: %w", err)
	}
	return n, nil
}

// UploadFile PUTs a local file to a presigned MinIO/S3 URL.
// MinIO presigned PUT expects the raw bytes in the request body with
// Content-Type application/octet-stream.
func UploadFile(ctx context.Context, rawURL, filePath string) (int64, error) {
	f, err := os.Open(filePath)
	if err != nil {
		return 0, fmt.Errorf("open: %w", err)
	}
	defer f.Close()

	stat, err := f.Stat()
	if err != nil {
		return 0, fmt.Errorf("stat: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPut, rawURL, f)
	if err != nil {
		return 0, fmt.Errorf("new request: %w", err)
	}
	req.ContentLength = stat.Size()
	req.Header.Set("Content-Type", "application/octet-stream")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return 0, fmt.Errorf("PUT: %w", err)
	}
	defer resp.Body.Close()

	// MinIO returns 200 on successful PUT of presigned objects
	if resp.StatusCode >= 300 {
		return 0, fmt.Errorf("upload server returned %d", resp.StatusCode)
	}
	return stat.Size(), nil
}
