/*
Package handler provides the HTTP handlers for the serverless API.
This file contains the handler for the /book endpoint.
*/
package handler

import (
	"fmt"
	"net/http"
	"strings"

	"go.mongodb.org/mongo-driver/bson"
)

// GetHadithByBookRefNo returns a hadith by its collection ID, book number and
// book reference number. These are all required query parameters.
func GetHadithByBookRefNo(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	collectionID := r.URL.Query().Get("collection_id")
	book := r.URL.Query().Get("book")
	refNo := r.URL.Query().Get("ref_no")
	if reason, ok := validateGetHadithByBookRefNoQueryParams(collectionID, book, refNo); !ok {
		sendBadRequestResp(w, reason)
		return
	}

	client, err := getMongoClient()
	if err != nil {
		sendServerErrorResp(w, err)
		return
	}
	collection := client.Database("hadith").Collection("hadiths")

	var resp BookResponse
	if err := collection.FindOne(
		ctx,
		bson.M{
			"collection_id": collectionID,
			"book_no":       book,
			"book_ref_no":   refNo,
		},
	).
		Decode(&resp); err != nil {
		sendServerErrorResp(w, err)
		return
	}

	resp.Base64 = hadithToBase64(*resp.HadithResponse)

	sendResp(w, resp)
}

func validateGetHadithByBookRefNoQueryParams(collectionID, book, refNo string) (string, bool) {
	if reason, ok := validateCollectionID(collectionID); !ok {
		return reason, false
	}
	if reason, ok := validateBook(book); !ok {
		return reason, false
	}
	if reason, ok := validateRefNo(refNo); !ok {
		return reason, false
	}

	return "", true
}

func validateCollectionID(collectionID string) (string, bool) {
	if collectionID == "" {
		return "collection_id is required", false
	}
	if !contains(shortNames, collectionID) {
		return fmt.Sprintf("collection_id must be one of %s", strings.Join(shortNames, ", ")), false
	}

	return "", true
}

func validateBook(book string) (string, bool) {
	if book == "" {
		return "book is required", false
	}
	if !isNumber(book) {
		return "book must be a number", false
	}

	return "", true
}

func validateRefNo(refNo string) (string, bool) {
	if refNo == "" {
		return "ref_no is required", false
	}
	if !isNumber(refNo) {
		return "ref_no must be a number", false
	}

	return "", true
}

type BookResponse struct {
	*HadithResponse `bson:",inline" json:",inline"`
	Base64          string `json:"base64"`
}
