package common

import (
	"errors"
	"fmt"
)

type FilterResult byte

const (
	No FilterResult = iota
	Maybe
	Yes
)

func IfThenElse(condition bool, onSuccess, onFailure FilterResult) FilterResult {
	var res FilterResult
	if condition {
		res = onSuccess
	} else {
		res = onFailure
	}
	return res
}

type SchemaEntry interface {
	String() string
	DetailedString() string
	Filter(typ string, val any) FilterResult
}

type (
	Parser         func(key, value []byte) (SchemaEntry, Parser, error)
	FallbackParser func(key, value []byte) (SchemaEntry, Parser)
)

func Any(parsers ...Parser) Parser {
	return func(key, value []byte) (SchemaEntry, Parser, error) {
		var errs error
		for _, parser := range parsers {
			ret, next, err := parser(key, value)
			if err == nil {
				return ret, next, nil
			}
			errs = errors.Join(errs, err)
		}
		return nil, nil, fmt.Errorf("no parser succeeded: %w", errs)
	}
}

func WithFallback(parser Parser, fallback FallbackParser) Parser {
	if parser == nil {
		return fallback.ToParser()
	}
	return func(key, value []byte) (SchemaEntry, Parser, error) {
		entry, next, err := parser(key, value)
		if err == nil {
			return entry, WithFallback(next, fallback), nil
		}
		return fallback.ToParser()(key, value)
	}
}

func (fp FallbackParser) ToParser() Parser {
	return func(key, value []byte) (SchemaEntry, Parser, error) {
		entry, next := fp(key, value)
		return entry, next, nil
	}
}

func (p Parser) ToFallbackParser() FallbackParser {
	return func(key, value []byte) (SchemaEntry, Parser) {
		entry, next, err := p(key, value)
		if err != nil {
			panic(fmt.Errorf(
				"couldn't use that parser as a fallback parser, it returned an error: %w", err,
			))
		}
		return entry, next
	}
}