// Package connection defines small server-owned facts shared by provider
// validation, persistence, and runtime resolution without coupling those
// layers to one another.
package connection

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
)

const (
	maxConfigFields = 16
	maxFieldNameLen = 64
	maxTokenLen     = 64
)

// Config is a small, non-secret, code-owned fact map selected during live
// connection validation.
type Config map[string]string

// EnumField declares one code-owned connection fact and its complete value
// allowlist. Connection configs do not support arbitrary string fields.
type EnumField struct {
	Name     string
	Required bool
	Values   []string
}

// Contract is the startup-validated provider-specific allowlist for one
// connection config. An empty Contract permits only an empty Config.
type Contract struct {
	Fields []EnumField
}

// Validate enforces one bounded canonical representation before persistence
// or runtime use.
func (config Config) Validate() error {
	if len(config) > maxConfigFields {
		return errors.New("provider connection config has too many fields")
	}
	for key, value := range config {
		if !validKey(key) || !validToken(value) {
			return errors.New("provider connection config is invalid")
		}
	}
	return nil
}

// Clone returns a detached copy safe to retain beyond one connection lookup.
func (config Config) Clone() Config {
	if config == nil {
		return nil
	}
	cloned := make(Config, len(config))
	for key, value := range config {
		cloned[key] = value
	}
	return cloned
}

// MarshalJSONDocument encodes one already bounded config for persistence.
func (config Config) MarshalJSONDocument() ([]byte, error) {
	if err := config.Validate(); err != nil {
		return nil, err
	}
	if len(config) == 0 {
		return nil, nil
	}
	encoded, err := json.Marshal(config)
	if err != nil {
		return nil, fmt.Errorf("marshal provider connection config: %w", err)
	}
	return encoded, nil
}

// ParseJSONDocument decodes and shape-checks one persisted config. Exact
// provider-owned key/value validation remains the caller's Contract gate.
func ParseJSONDocument(raw []byte) (Config, error) {
	trimmed := bytes.TrimSpace(raw)
	if len(trimmed) == 0 || bytes.Equal(trimmed, []byte("null")) {
		return nil, nil
	}
	var config Config
	if err := json.Unmarshal(trimmed, &config); err != nil {
		return nil, fmt.Errorf("decode provider connection config: %w", err)
	}
	if err := config.Validate(); err != nil {
		return nil, err
	}
	return config, nil
}

// ValidateSpec checks the provider-owned field and enum allowlists during
// bootstrap before the Contract can participate in connection handling.
func (contract Contract) ValidateSpec() error {
	if len(contract.Fields) > maxConfigFields {
		return errors.New("provider connection config contract has too many fields")
	}
	seenFields := make(map[string]struct{}, len(contract.Fields))
	for _, field := range contract.Fields {
		if !validKey(field.Name) {
			return errors.New("provider connection config contract field is invalid")
		}
		if _, duplicate := seenFields[field.Name]; duplicate {
			return fmt.Errorf(
				"provider connection config contract field %q is duplicated",
				field.Name,
			)
		}
		seenFields[field.Name] = struct{}{}
		if len(field.Values) == 0 {
			return fmt.Errorf(
				"provider connection config contract field %q has no values",
				field.Name,
			)
		}
		seenValues := make(map[string]struct{}, len(field.Values))
		for _, value := range field.Values {
			if !validToken(value) {
				return fmt.Errorf(
					"provider connection config contract field %q has an invalid value",
					field.Name,
				)
			}
			if _, duplicate := seenValues[value]; duplicate {
				return fmt.Errorf(
					"provider connection config contract field %q has duplicate values",
					field.Name,
				)
			}
			seenValues[value] = struct{}{}
		}
	}
	return nil
}

// Validate checks one prepared Config against the exact provider-owned key and
// enum allowlists before persistence or connection-test comparison.
func (contract Contract) Validate(config Config) error {
	if err := contract.ValidateSpec(); err != nil {
		return err
	}
	if err := config.Validate(); err != nil {
		return err
	}
	remaining := make(map[string]struct{}, len(config))
	for key := range config {
		remaining[key] = struct{}{}
	}
	for _, field := range contract.Fields {
		value, exists := config[field.Name]
		if !exists {
			if field.Required {
				return fmt.Errorf(
					"provider connection config field %q is required",
					field.Name,
				)
			}
			continue
		}
		delete(remaining, field.Name)
		allowed := false
		for _, candidate := range field.Values {
			if value == candidate {
				allowed = true
				break
			}
		}
		if !allowed {
			return fmt.Errorf(
				"provider connection config field %q has an unsupported value",
				field.Name,
			)
		}
	}
	for key := range remaining {
		return fmt.Errorf(
			"provider connection config field %q is not declared",
			key,
		)
	}
	return nil
}

func validKey(key string) bool {
	if len(key) == 0 ||
		len(key) > maxFieldNameLen ||
		key[0] < 'a' ||
		key[0] > 'z' {
		return false
	}
	for index := 1; index < len(key); index++ {
		character := key[index]
		if (character < 'a' || character > 'z') &&
			(character < '0' || character > '9') &&
			character != '_' {
			return false
		}
	}
	return true
}

func validToken(value string) bool {
	if len(value) == 0 ||
		len(value) > maxTokenLen ||
		value[0] < 'a' ||
		value[0] > 'z' {
		return false
	}
	for index := 1; index < len(value); index++ {
		character := value[index]
		if (character < 'a' || character > 'z') &&
			(character < '0' || character > '9') &&
			character != '_' &&
			character != '-' {
			return false
		}
	}
	return true
}
