// Package debugbundle owns explicitly requested per-run debug bundles.
package debugbundle

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

type Bundle struct {
	path, summaryRoot, traceRoot string
	createdAt                    time.Time
}

func Allocate(parent, runID string, startedAt time.Time) (*Bundle, error) {
	parent = strings.TrimSpace(parent)
	if parent == "" {
		return nil, fmt.Errorf("debug parent must not be empty")
	}
	if err := validateRunID(runID); err != nil {
		return nil, err
	}
	if err := os.MkdirAll(parent, 0o700); err != nil {
		return nil, fmt.Errorf("create debug parent %q: %w", parent, err)
	}
	path := filepath.Join(parent, runID)
	if err := os.Mkdir(path, 0o700); err != nil {
		if os.IsExist(err) {
			return nil, fmt.Errorf("debug bundle %q already exists", path)
		}
		return nil, fmt.Errorf("create debug bundle %q: %w", path, err)
	}
	summary, trace := filepath.Join(path, "summary"), filepath.Join(path, "trace")
	if err := os.Mkdir(summary, 0o700); err != nil {
		_ = os.Remove(path)
		return nil, fmt.Errorf("create debug summary %q: %w", summary, err)
	}
	if err := os.Mkdir(trace, 0o700); err != nil {
		_ = os.RemoveAll(path)
		return nil, fmt.Errorf("create debug trace %q: %w", trace, err)
	}
	return &Bundle{path: path, summaryRoot: summary, traceRoot: trace, createdAt: startedAt}, nil
}

func validateRunID(runID string) error {
	if runID == "" {
		return fmt.Errorf("debug run ID must not be empty")
	}
	if runID != strings.TrimSpace(runID) || strings.ContainsAny(runID, `/\\`) || filepath.IsAbs(runID) || filepath.Clean(runID) != runID || runID == "." || runID == ".." {
		return fmt.Errorf("debug run ID %q must be one safe path component", runID)
	}
	return nil
}
func (b *Bundle) Path() string {
	if b == nil {
		return ""
	}
	return b.path
}
func (b *Bundle) SummaryRoot() string {
	if b == nil {
		return ""
	}
	return b.summaryRoot
}
func (b *Bundle) TraceRoot() string {
	if b == nil {
		return ""
	}
	return b.traceRoot
}
func (b *Bundle) RunID() string {
	if b == nil {
		return ""
	}
	return filepath.Base(b.path)
}
func (b *Bundle) CreatedAt() time.Time {
	if b == nil {
		return time.Time{}
	}
	return b.createdAt
}
func (b *Bundle) Summary() *SummaryWriter {
	if b == nil {
		return nil
	}
	return &SummaryWriter{root: b.summaryRoot, runID: b.RunID(), createdAt: b.createdAt}
}
