// Package route provides structures and functions to represent a route.
package route

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
)

// Schema represents the schema of the route.
type Schema struct {
	PathRegex       string      `json:"pathRegex"`       // Regular expression of the path
	RequiredHeaders []string    `json:"requiredHeaders"` // Headers required by the route
	JSONBodyModel   interface{} `json:"body"`            // JSON model of the request body
}

// Validate validates the given request with the schema.
func (s *Schema) Validate(r *http.Request) error {
	for _, headerKey := range s.RequiredHeaders {
		if value := r.Header.Get(headerKey); value == "" {
			return fmt.Errorf("required header key %s not found in the request header %v", headerKey, r.Header)
		}
	}
	reg := regexp.MustCompile(s.PathRegex)
	if !reg.MatchString(r.URL.Path) {
		return fmt.Errorf("path %s does not match the pattern rules", r.URL.Path)
	}
	if s.JSONBodyModel != nil {
		data, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return fmt.Errorf("unable to read request body: %v", err)
		}
		if err = json.Unmarshal(data, s.JSONBodyModel); err != nil {
			return fmt.Errorf("unable to unmarshal the request body %s: %v", data, err)
		}
		// Rewrite the body for the next read.
		r.Body = ioutil.NopCloser(bytes.NewReader(data))
	}
	return nil
}
