/*
Copyright © 2024-2025 Thomas von Dein

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rest

import (
	//"github.com/alecthomas/repr"

	"encoding/json"
	"log"
	"net/http"

	"codeberg.org/scip/anydb/app"
	"codeberg.org/scip/anydb/cfg"
)

type SetContext struct {
	Query string `json:"query" form:"query"`
}

type ListResponse struct {
	Success bool
	Code    int
	Entries app.DbEntries
}

type SingleResponse struct {
	Success bool
	Code    int
	Entry   *app.DbEntry
}

func RestList(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
	attr := new(app.DbAttr)

	err := json.NewDecoder(req.Body).Decode(&attr)
	if err != nil {
		if err.Error() != `EOF` {
			http.Error(resp, err.Error(), http.StatusBadRequest)
			return
		}
	}

	// get list
	entries, err := conf.DB.List(attr, attr.Fulltext)
	if err != nil {
		JsonStatus(resp, http.StatusForbidden, "Unable to list keys: "+err.Error())
		return
	}

	resp.Header().Set("Content-Type", "application/json")

	err = json.NewEncoder(resp).Encode(
		ListResponse{
			Code:    http.StatusOK,
			Success: true,
			Entries: entries,
		})

	if err != nil {
		log.Fatal(err)
	}
}

func RestGet(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
	if key == "" {
		JsonStatus(resp, http.StatusForbidden, "key not provided")
		return
	}

	// get list
	entry, err := conf.DB.Get(&app.DbAttr{Key: key})
	if err != nil {
		JsonStatus(resp, http.StatusForbidden, "Unable to get key: "+err.Error())
		return
	}
	if entry.Key == "" {
		JsonStatus(resp, http.StatusForbidden, "Key does not exist")
		return
	}

	resp.Header().Set("Content-Type", "application/json")

	err = json.NewEncoder(resp).Encode(
		SingleResponse{
			Code:    http.StatusOK,
			Success: true,
			Entry:   entry,
		})

	if err != nil {
		log.Fatal(err)
	}
}

func RestDelete(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
	if key == "" {
		JsonStatus(resp, http.StatusForbidden, "key not provided")
		return
	}

	// get list
	err := conf.DB.Del(&app.DbAttr{Key: key})
	if err != nil {
		JsonStatus(resp, http.StatusForbidden, "Unable to delete key: "+err.Error())
		return
	}

	JsonStatus(resp, http.StatusOK, "key deleted")
}

func RestSet(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
	attr := new(app.DbAttr)

	err := json.NewDecoder(req.Body).Decode(&attr)
	if err != nil {
		http.Error(resp, err.Error(), http.StatusBadRequest)
		return
	}

	// attr.Data is a string, thus the decoder doesn't expect it to be
	// base64  encoded. However, internally we  need []byte, therefore
	// we  copy a  cast to .Val.  We also need  to setup  the .Preview
	// value here.
	attr.Val = []byte(attr.Data)
	attr.SetPreview()

	err = conf.DB.Set(attr)
	if err != nil {
		JsonStatus(resp, http.StatusForbidden, "Unable to set key: "+err.Error())
		return
	}

	JsonStatus(resp, http.StatusOK, "key added/updated")
}

func Home(resp http.ResponseWriter) {
	_, err := resp.Write([]byte("Use the REST API on " + apiprefix + "\r\n"))
	if err != nil {
		log.Fatal(err)
	}
}
