// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package devices

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

// PDUConn encapsultes PDU connection settings.
type PDUConn struct {
	// Client is the client used to perform all requests.
	Client *http.Client

	// Host is the network hostname of the PDU.
	Host string

	// Username is the username by which we can log in to the PDU.
	Username string

	// Password is the password by which we can log in to the PDU.
	Password string

	// token is the authentication token obtained by Login.
	token string
}

type message struct {
	ID    int             `json:"msgid,omitempty"`
	Reply string          `json:"reply,omitempty"`
	Data  json.RawMessage `json:"data,omitempty"`
	Error struct {
		Name    string `json:"name"`
		Message string `json:"message"`
		Status  int    `json:"status"`
	} `json:"error,omitempty"`
}

// NewPDUConn initializes and returns a new PDUConn struct.
func NewPDUConn(host string, uname string, pwd string) *PDUConn {
	return &PDUConn{
		Client: &http.Client{
			Transport: &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			},
		},
		Host:     host,
		Username: uname,
		Password: pwd,
	}
}

// Login performs a login and obtains authorization token used for other calls.
func (c *PDUConn) Login() error {
	q := make(url.Values)
	q.Set("username", c.Username)
	q.Set("password", c.Password)

	u := url.URL{
		Scheme:   "https",
		Host:     c.Host,
		Path:     "/api/AuthenticationControllers/login",
		RawQuery: q.Encode(),
	}

	l := struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}{
		Username: c.Username,
		Password: c.Password,
	}

	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(l); err != nil {
		return err
	}

	req, err := http.NewRequest("POST", u.String(), b)
	req.Header.Add("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		return err
	}
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusCreated {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	if token, ok := resp.Header["Authorization"]; ok {
		c.token = token[0]
	}

	return nil
}

// PDUReboot powercycles the given outlet.
func PDUReboot(outlet int, host, uname, pwd string) error {
	conn := NewPDUConn(host, uname, pwd)
	if err := conn.Login(); err != nil {
		return err
	}
	defer conn.Logout()
	return conn.Loads(outlet, "Cycle")
}

// Loads changes the outlet state.
func (c *PDUConn) Loads(outlet int, state string) error {
	u := url.URL{
		Scheme: "https",
		Host:   c.Host,
		Path:   fmt.Sprintf("/api/device/loads/%d", outlet),
	}

	s := struct {
		LoadFireState string `json:"loadFireState"`
	}{
		LoadFireState: state,
	}

	b := new(bytes.Buffer)
	if err := json.NewEncoder(b).Encode(s); err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", u.String(), b)
	if err != nil {
		return err
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Authorization", c.token)
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	return nil
}

// Logout performs a logout and discards the authorization token.
func (c *PDUConn) Logout() error {
	u := url.URL{
		Scheme: "https",
		Host:   c.Host,
		Path:   "/api/AuthenticationControllers/logout",
	}

	req, err := http.NewRequest("POST", u.String(), nil)
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Authorization", c.token)
	req.Header.Set("Content-Type", "application/json")
	if err != nil {
		return err
	}
	resp, err := c.Client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	var msg message
	err = json.NewDecoder(resp.Body).Decode(&msg)

	if resp.StatusCode != http.StatusOK {
		if err != nil {
			return fmt.Errorf("request failed: %d", resp.StatusCode)
		} else {
			return fmt.Errorf("request failed: %s", msg.Error.Message)
		}
	}

	c.token = ""

	return nil
}
