package client

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/util"
)

// TiDBService returs the load balance service of the tidb-cluster
func (c *Client) TiDBService() string {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}

	return c.conf.Cat.LBService
}

// PdService returns pd load balance service of pd-service
func (c *Client) PdService() string {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}

	return c.conf.Cat.PdService
}

// TiDBs returns addrs of the all tidbs
func (c *Client) TiDBs() []string {
	var tidbs []string
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	conf := c.conf.Cat
	for _, t := range conf.TiDBs {
		tidbs = append(tidbs, fmt.Sprintf("%s:%d", t.IP, t.ServicePort))
	}
	return tidbs
}

// TiDB returns addr of the specified tidb
func (c *Client) TiDB(podName string) (string, error) {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	conf := c.conf.Cat
	for _, p := range conf.TiDBs {
		if p.Name == podName {
			return fmt.Sprintf("%s:%d", p.IP, p.ServicePort), nil
		}
	}
	return "", errors.NotFoundf("ip of %s", podName)
}

// PDs returns addrs of the all pds
func (c *Client) PDs() []string {
	var pds []string
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	conf := c.conf.Cat
	for _, p := range conf.PDs {
		pds = append(pds, fmt.Sprintf("%s:%d", p.IP, p.ServicePort))
	}
	return pds
}

// PD returns addr of the specified pds
func (c *Client) PD(podName string) (string, error) {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	conf := c.conf.Cat
	for _, p := range conf.PDs {
		if p.Name == podName {
			return fmt.Sprintf("%s:%d", p.IP, p.ServicePort), nil
		}
	}
	return "", errors.NotFoundf("ip of %s", podName)
}

// TiKVs returns addrs of the all tikvs
func (c *Client) TiKVs() []string {
	var tikvs []string
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}

	conf := c.conf.Cat
	for _, t := range conf.TiKVs {
		tikvs = append(tikvs, fmt.Sprintf("%s:%d", t.IP, t.ServicePort))
	}
	return tikvs
}

// TiKV returns addr of the specified tikv
func (c *Client) TiKV(podName string) (string, error) {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	conf := c.conf.Cat
	for _, p := range conf.TiKVs {
		if p.Name == podName {
			return fmt.Sprintf("%s:%d", p.IP, p.ServicePort), nil
		}
	}
	return "", errors.NotFoundf("ip of %s", podName)
}

// PrometheusAddr returns address of prometheus
func (c *Client) PrometheusAddr() string {
	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}
	return c.conf.Cat.PrometheusAddr
}

// GetHostsByLabel returns all hosts with the specified label
func (c *Client) GetHostsByLabel(label string) ([]string, error) {
	return c.getHostsByLabel(label)
}

func (c *Client) getHostsByLabel(label string) ([]string, error) {
	url := util.GenURL(fmt.Sprintf("%s/hosts/label/%s", c.managerAddr, label))

	data, err := util.DoGet(http.DefaultClient, url)
	if err != nil {
		return nil, NewErrorf("get hosts with label:%s failed: %v", label, err)
	}

	jsonData, err := json.Marshal(data)
	if err != nil {
		return nil, NewErrorf("marshal hosts data %+v falled: %+v", data, err)
	}

	var hosts []string
	if err := json.Unmarshal(jsonData, &hosts); err != nil {
		return nil, NewErrorf("unmarshal hosts %s failed: %v", string(jsonData), err)
	}
	return hosts, nil
}

// StopTiDBs stops tidbs
func (c *Client) StopTiDBs() error {
	if !c.isOnline() {
		Warnf("only mode online is permitted. the mode is %s", c.mode)
		return nil
	}

	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}

	var tidbs []string

	conf := c.conf.Cat
	for _, t := range conf.TiDBs {
		tidbs = append(tidbs, t.IP)
	}

	tidbClients := genClients(tidbs)
	if err := agentDoKill(tidbClients, "tidb"); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// StartTiDBs starts tidbs
func (c *Client) StartTiDBs() error {
	if !c.isOnline() {
		Warnf("only mode online is permitted. the mode is %s", c.mode)
		return nil
	}

	if err := c.refreshConfig(); err != nil {
		Fatalf("init client config error %v", errors.ErrorStack(err))
	}

	var tidbs []string

	conf := c.conf.Cat
	for _, t := range conf.TiDBs {
		tidbs = append(tidbs, t.IP)
	}

	tidbClients := genClients(tidbs)
	if err := agentDoRestart(tidbClients, "tidb"); err != nil {
		return errors.Trace(err)
	}

	return nil
}
