// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.

package resource

import (
	"errors"
	"fmt"
	"net/url"
	"strings"
)

var (
	ErrUnknownResourceType        = errors.New("Unknown resource type")
	ResourceTypes          *Types = NewTypes()
)

type TypeName string //`json:"type"`

type TypeFactory func(*url.URL) Resource

type Types struct {
	registry map[string]TypeFactory
}

func NewTypes() *Types {
	return &Types{registry: make(map[string]TypeFactory)}
}

func (t *Types) Register(name string, factory TypeFactory) {
	t.registry[name] = factory
}

func (t *Types) New(uri string) (Resource, error) {
	u, e := url.Parse(uri)
	if u == nil || e != nil {
		return nil, fmt.Errorf("%w: %s", ErrUnknownResourceType, e)
	}

	if r, ok := t.registry[u.Scheme]; ok {
		return r(u), nil
	}
	return nil, fmt.Errorf("%w: %s", ErrUnknownResourceType, u.Scheme)
}

func (t *Types) Has(typename string) bool {
	if _, ok := t.registry[typename]; ok {
		return true
	}
	return false
}

func (n *TypeName) UnmarshalJSON(b []byte) error {
	ResourceTypeName := strings.Trim(string(b), "\"")
	if ResourceTypes.Has(ResourceTypeName) {
		*n = TypeName(ResourceTypeName)
		return nil
	}
	return fmt.Errorf("%w: %s", ErrUnknownResourceType, ResourceTypeName)
}
