// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.package spec

package util

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/pingcap/tidb-cloud-manager/pkg/server"
)

const defaultTimeout = 5 * time.Second

type Client interface {
	// DoDelete delete a resource specified by url
	DoDelete(url string) (*server.Response, error)
	// DoGet get a resource specified by url
	DoGet(url string) (*server.Response, error)
	// DoPost create a resource specified by url and data
	DoPost(url, bodyType string, body []byte) (*server.Response, error)
	// DoPut modify a resource specified by url and data
	DoPut(url, bodyType string, body []byte) (*server.Response, error)
}

type HttpClient struct {
	*http.Client
}

func NewHttpClient() *HttpClient {
	hc := &HttpClient{}
	hc.Client = &http.Client{
		Timeout: defaultTimeout,
	}
	return hc
}

func (hc *HttpClient) SetRequestTimeout(t time.Duration) {
	hc.Client.Timeout = t
}

func (hc *HttpClient) DoPost(url string, bodyType string, body []byte) (*server.Response, error) {
	ioBody := bytes.NewReader(body)
	resp, err := hc.Client.Post(url, bodyType, ioBody)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	response := &server.Response{}
	err = json.Unmarshal(respBody, response)

	return response, err
}

func (hc *HttpClient) DoPut(url string, bodyType string, body []byte) (*server.Response, error) {
	ioBody := bytes.NewReader(body)
	req, err := http.NewRequest("PUT", url, ioBody)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", bodyType)

	resp, err := hc.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	response := &server.Response{}
	err = json.Unmarshal(respBody, response)

	return response, err
}

func (hc *HttpClient) DoGet(url string) (*server.Response, error) {
	resp, err := hc.Client.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	response := &server.Response{}
	err = json.Unmarshal(respBody, response)

	return response, err
}

func (hc *HttpClient) DoDelete(url string) (*server.Response, error) {
	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		return nil, err
	}
	resp, err := hc.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	response := &server.Response{}
	err = json.Unmarshal(respBody, response)

	return response, err
}
