// Copyright 2019 Yunion
//
// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package compute

import (
	"fmt"
	"strings"

	"yunion.io/x/jsonutils"
	"yunion.io/x/log"
	"yunion.io/x/pkg/util/httputils"
	"yunion.io/x/pkg/util/printutils"
	"yunion.io/x/pkg/utils"

	"yunion.io/x/onecloud/pkg/httperrors"
	"yunion.io/x/onecloud/pkg/mcclient"
	"yunion.io/x/onecloud/pkg/mcclient/modulebase"
	"yunion.io/x/onecloud/pkg/mcclient/modules"
)

const MACAddressPattern = `(([a-fA-F0-9]{2}[:-]){5}([a-fA-F0-9]{2}))`

type HostManager struct {
	modulebase.ResourceManager
}

func (this *HostManager) GetLoginInfo(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
	data, e := this.GetMetadata(s, id, nil)
	if e != nil {
		return nil, e
	}
	ret := jsonutils.NewDict()
	login_key, e := data.GetString("password")
	if e != nil {
		return nil, httperrors.NewNotFoundError("No ssh password: %s", e)
	}
	passwd, e := utils.DescryptAESBase64(id, login_key)
	if e != nil {
		return nil, e
	}
	passwd, e = utils.DescryptAESBase64(id, passwd)
	if e != nil {
		return nil, e
	}
	ret.Add(jsonutils.NewString(passwd), "password")
	v, e := data.Get("username")
	if e == nil {
		ret.Add(v, "username")
	}
	v, e = data.Get("ip")
	if e == nil {
		ret.Add(v, "ip")
	}
	return ret, nil
}

func (this *HostManager) GetIpmiInfo(s *mcclient.ClientSession, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) {
	data, e := this.GetSpecific(s, id, "ipmi", nil)
	if e != nil {
		return nil, e
	}

	ret := jsonutils.NewDict()
	passwd, e := data.GetString("password")
	if e != nil {
		return nil, fmt.Errorf("No IPMI password: %s", e)
	}

	ret.Add(jsonutils.NewString(passwd), "password")
	v, e := data.Get("username")
	if e == nil {
		ret.Add(v, "username")
	}
	v, e = data.Get("ip_addr")
	if e == nil {
		ret.Add(v, "ip")
	}
	return ret, nil
}

func parseHosts(titles []string, data string) []*jsonutils.JSONDict {
	hosts := strings.Split(data, "\n")
	ret := []*jsonutils.JSONDict{}
	for i, host := range hosts {
		host = strings.TrimSpace(host)
		if len(host) == 0 {
			log.Warningf("DoBatchRegister 第%d行： 空白行（已忽略）\n", i)
			continue
		}

		fields := strings.Split(host, ",")

		params := jsonutils.NewDict()
		params.Add(jsonutils.NewString("baremetal"), "host_type")

		for i := range fields {
			field := fields[i]
			if len(field) > 0 {
				params.Add(jsonutils.NewString(field), titles[i])
			}
		}

		ret = append(ret, params)
	}

	return ret
}

func (this *HostManager) BatchRegister(s *mcclient.ClientSession, titles []string, params jsonutils.JSONObject) ([]printutils.SubmitResult, error) {
	data, err := params.GetString("hosts")
	if err != nil {
		return nil, err
	}
	input := params.(*jsonutils.JSONDict)
	input.Remove("hosts")

	hosts := parseHosts(titles, data)

	results := make(chan printutils.SubmitResult, len(hosts))
	for _, host := range hosts {
		host.Update(input)
		go func(data jsonutils.JSONObject) {
			ret, e := this.Create(s, data)
			id, _ := data.GetString("access_mac")
			if e != nil {
				ecls, ok := e.(*httputils.JSONClientError)
				if ok {
					results <- printutils.SubmitResult{Status: ecls.Code, Id: id, Data: jsonutils.Marshal(ecls)}
				} else {
					results <- printutils.SubmitResult{Status: 400, Id: id, Data: jsonutils.NewString(e.Error())}
				}
			} else {
				results <- printutils.SubmitResult{Status: 200, Id: id, Data: ret}
			}
		}(host)
	}

	ret := make([]printutils.SubmitResult, len(hosts))
	for i := 0; i < len(hosts); i++ {
		ret[i] = <-results
	}
	close(results)

	return ret, nil
}

func (this *HostManager) DoBatchRegister(s *mcclient.ClientSession, params jsonutils.JSONObject) ([]printutils.SubmitResult, error) {
	titles := []string{"access_mac", "name", "ipmi_ip_addr", "ipmi_username", "ipmi_password"}
	return this.BatchRegister(s, titles, params)
}

var (
	Hosts HostManager
)

func init() {
	Hosts = HostManager{modules.NewComputeManager("host", "hosts",
		[]string{"ID", "Name", "Access_mac", "Access_ip", "Ipmi_Ip",
			"Ovn_Mapped_Ip_Addr", "Ovn_Mapped_Ip6_Addr",
			"Manager_URI",
			"Status", "enabled", "host_status",
			"Guests", "Running_guests",
			"storage", "storage_used",
			"storage_virtual", "disk_used",
			"storage_free", "storage_commit_rate",
			"mem_size", "mem_used", "mem_free",
			"mem_commit", "cpu_count", "cpu_used",
			"cpu_commit", "cpu_commit_rate",
			"mem_commit_rate", "cpu_commit_bound",
			"mem_commit_bound", "node_count", "sn", "storage_type",
			"host_type", "version", "schedtags",
			"storage_size",
			"expired_at",
			"domain_id", "project_domain",
			"public_scope",
		},
		[]string{})}
	modules.RegisterCompute(&Hosts)
}
