package zap

import (
	"context"
	"fmt"

	"git.perx.ru/perxis/perxis-go/id"
	"git.perx.ru/perxis/perxis-go/pkg/auth"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

const (
	unknownObject = "unknown"
	unknownCaller = "unknown"
)

func Category(category string) zapcore.Field {
	return zap.String("category", category)
}

func Component(component string) zapcore.Field {
	return zap.String("component", component)
}

func Event(event string) zapcore.Field {
	return zap.String("event", event)
}

// Object возвращает поле и устанавливает передаваемый аргумент в качестве идентификатора объекта в формате ObjectID.
// Поддерживаемые типы: string, fmt.Stringer.
// Если передан аргумент другого типа, будет произведена попытка привести переданное значение к ObjectID.
func Object(v any) zapcore.Field {
	var object = unknownObject
	switch value := v.(type) {
	case string:
		object = value
	case fmt.Stringer:
		object = value.String()
	default:
		oid, err := id.FromObject(v)
		if err == nil {
			object = oid.String()
		}
	}
	return zap.String("object", object)
}

// Caller возвращает поле и устанавливает передаваемый аргумент в качестве "вызывающего" в формате ObjectID.
// Поддерживаемые типы: string, fmt.Stringer.
// Если передан аргумент другого типа, будет произведена попытка привести переданное значение к ObjectID.
func Caller(v any) zapcore.Field {
	var caller = unknownCaller
	switch value := v.(type) {
	case string:
		caller = value
	case fmt.Stringer:
		caller = value.String()
	default:
		oid, err := id.FromObject(v)
		if err == nil {
			caller = oid.String()
		}
	}
	return zap.String("caller", caller)
}

// CallerFromContext извлекает auth.Principal из контекста и устанавливает его в качестве "вызывающего" в формате ObjectID.
func CallerFromContext(ctx context.Context) zapcore.Field {
	return Caller(auth.GetPrincipal(ctx))
}

func Attr(attr any) zapcore.Field {
	return zap.Any("attr", attr)
}

func Tags(tags ...string) zapcore.Field {
	return zap.Strings("tags", tags)
}