package repos

import (
	"errors"
	"net/http"
)

var (
	ErrUnauthorized    = errors.New("unauthorized")
	ErrInvalidArgument = errors.New("invalid argument")
	ErrForbidden       = errors.New("forbidden")
	ErrNotFound        = errors.New("not found")
	ErrConflict        = errors.New("conflict")
)

type domainError struct {
	kind    error
	msg     string
	code    string
	details any
}

// Error returns the caller-safe lifecycle service message.
func (e domainError) Error() string { return e.msg }

// Unwrap exposes the stable lifecycle error kind for errors.Is matching.
func (e domainError) Unwrap() error { return e.kind }

func unauthorized(message string) error { return domainError{kind: ErrUnauthorized, msg: message} }
func invalidArgument(message string) error {
	return domainError{kind: ErrInvalidArgument, msg: message}
}
func forbidden(message string) error { return domainError{kind: ErrForbidden, msg: message} }
func notFound(message string) error  { return domainError{kind: ErrNotFound, msg: message} }
func conflict(message string) error  { return domainError{kind: ErrConflict, msg: message} }
func codedUnauthorized(code, message string) error {
	return domainError{kind: ErrUnauthorized, msg: message, code: code}
}
func codedForbidden(code, message string) error {
	return domainError{kind: ErrForbidden, msg: message, code: code}
}
func codedNotFound(code, message string) error {
	return domainError{kind: ErrNotFound, msg: message, code: code}
}
func codedInvalidArgument(code, message string) error {
	return domainError{kind: ErrInvalidArgument, msg: message, code: code}
}
func codedInvalidArgumentDetails(code, message string, details any) error {
	return domainError{kind: ErrInvalidArgument, msg: message, code: code, details: details}
}
func codedConflict(code, message string, details any) error {
	return domainError{kind: ErrConflict, msg: message, code: code, details: details}
}

// Code returns the optional stable lifecycle error code without exposing store
// or AGS implementation errors.
func Code(err error) string {
	var domain domainError
	if errors.As(err, &domain) {
		return domain.code
	}
	return ""
}

// Details returns optional structured lifecycle conflict or validation data.
// Callers must still classify the error kind separately.
func Details(err error) any {
	var domain domainError
	if errors.As(err, &domain) {
		return domain.details
	}
	return nil
}

// HTTPStatus maps service-domain errors to HTTP status codes.
func HTTPStatus(err error) int {
	switch {
	case errors.Is(err, ErrUnauthorized):
		return http.StatusUnauthorized
	case errors.Is(err, ErrInvalidArgument):
		return http.StatusBadRequest
	case errors.Is(err, ErrForbidden):
		return http.StatusForbidden
	case errors.Is(err, ErrNotFound):
		return http.StatusNotFound
	case errors.Is(err, ErrConflict):
		return http.StatusConflict
	default:
		return http.StatusInternalServerError
	}
}
