package client

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/manager/api"
	"github.com/pingcap/schrodinger/pkg/types"
	"github.com/pingcap/schrodinger/util"
)

// CreateBox creates a box by schrodinger api
func (c *Client) CreateBox(box *types.Box) (*types.Box, error) {
	b, err := json.Marshal(box)
	if err != nil {
		return nil, errors.Trace(err)
	}

	url := fmt.Sprintf("%s/boxes", c.cfg.Addr)
	_, err = util.PostAndExtract(c.client, url, b)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return box, nil
}

// UpdateBox updates a box by schrodinger api
func (c *Client) UpdateBox(box *types.Box) (*types.Box, error) {
	b, err := json.Marshal(box)
	if err != nil {
		return nil, errors.Trace(err)
	}

	url := fmt.Sprintf("%s/boxes/%d", c.cfg.Addr, box.ID)
	_, err = util.PutAndExtract(c.client, url, b)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return box, nil
}

// SetBox sets a box by schrodinger api,
// if the box is exists, `SetBox` will update this box.
func (c *Client) SetBox(box *types.Box) (*types.Box, error) {
	getURL := fmt.Sprintf("%s/boxes/byname/%s", c.cfg.Addr, box.Name)
	respData, err := util.GetAndExtract(c.client, getURL)
	if err == nil {
		respBox := &types.Box{}
		if err = json.Unmarshal(respData, respBox); err != nil {
			return nil, errors.Trace(err)
		}

		box.ID = respBox.ID
		return c.UpdateBox(box)
	}

	if strings.Contains(err.Error(), "not found") {
		return c.CreateBox(box)
	}

	return nil, errors.Trace(err)
}

// ListBoxes lists config templates
func (c *Client) ListBoxes(limit, offset int64) (types.Boxes, error) {
	listURL := fmt.Sprintf("%s/boxes?size=%d&offset=%d", c.cfg.Addr, limit, offset)

	respData, err := util.GetAndExtract(c.client, listURL)
	if err != nil {
		return nil, errors.Trace(err)
	}

	listData := api.ListData{}
	if err = json.Unmarshal(respData, &listData); err != nil {
		return nil, errors.Trace(err)
	}

	boxesJSON, _ := json.Marshal(listData.List)

	var respBoxes types.Boxes
	if err = json.Unmarshal(boxesJSON, &respBoxes); err != nil {
		return nil, errors.Trace(err)
	}

	return respBoxes, nil
}
