// Package errors defines the cp9 error model with categories and exit codes.
package errors

import (
	"encoding/json"
	"fmt"
)

// Category classifies an error for agent consumption.
type Category string

const (
	CategoryConfig    Category = "config"    // Bad configuration (cp9.yaml, cp9.local.yaml)
	CategoryTransient Category = "transient" // Retriable failure (network, timeout)
	CategoryPermanent Category = "permanent" // Non-retriable failure (missing binary, bad input)
	CategoryResource  Category = "resource"  // Infrastructure issue (k3d, AWS, TiDB)
)

// Exit codes for cp9.
const (
	ExitOK             = 0
	ExitConfig         = 1
	ExitTransient      = 2
	ExitPermanent      = 3
	ExitResource       = 4
	ExitNotImplemented = 10
	ExitUnknown        = 99
)

// Error is a structured error that can be serialized to JSON.
type Error struct {
	Category Category `json:"category"`
	Message  string   `json:"message"`
	ExitCode int      `json:"exit_code"`
}

func (e *Error) Error() string {
	return fmt.Sprintf("[%s] %s", e.Category, e.Message)
}

// JSON returns the JSON representation of the error.
func (e *Error) JSON() []byte {
	b, _ := json.Marshal(e)
	return b
}

// ExitCodeFor returns the exit code for a given category.
func ExitCodeFor(cat Category) int {
	switch cat {
	case CategoryConfig:
		return ExitConfig
	case CategoryTransient:
		return ExitTransient
	case CategoryPermanent:
		return ExitPermanent
	case CategoryResource:
		return ExitResource
	default:
		return ExitUnknown
	}
}

// New creates a new cp9 error.
func New(cat Category, msg string) *Error {
	return &Error{
		Category: cat,
		Message:  msg,
		ExitCode: ExitCodeFor(cat),
	}
}

// Newf creates a new cp9 error with a formatted message.
func Newf(cat Category, format string, args ...any) *Error {
	return New(cat, fmt.Sprintf(format, args...))
}

// NotImplemented returns a standard "not implemented" error for stub commands.
func NotImplemented(command string) *Error {
	return &Error{
		Category: CategoryPermanent,
		Message:  fmt.Sprintf("command %q is not yet implemented", command),
		ExitCode: ExitNotImplemented,
	}
}
