// Copyright 2021 Google LLC
//
// 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.

// Implementation of the Reporter interface that gathers instance status from
// the update-engine and the /etc/lsb-release file.
package imgstatus

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"policy_manager/dbus"
	"policy_manager/sysapi"
	"regexp"
	"strconv"
	"strings"

	"policy_manager/policyenforcer"
	pmpb "policy_manager/policymanagerproto"

	"github.com/golang/protobuf/proto"
)

// Constants related to lsb-release file.
const (
	lsbFile                        = "/etc/lsb-release"
	lsbChromeOSReleaseKey          = "CHROMEOS_RELEASE_VERSION"
	lsbChromeOSReleaseChannelKey   = "CHROMEOS_RELEASE_TRACK"
	lsbChromeOSReleaseMilestoneKey = "CHROMEOS_RELEASE_CHROME_MILESTONE"
)

// reporterImpl implements the Reporter interface. It talks to the underlying
// system through the sysapi handler so it can be run on both COS and non-COS
// machines.
type reporterImpl struct {
	// currentOSVersion is a protobuf containing informatin of the current
	// OS version being run.
	currentOSVersion *pmpb.OSVersion

	// api is the APIHandler to use for making calls that depend on the
	// system we are running on.
	api sysapi.APIHandler

	// ueClient is the UpdateEngineClient for interacting with the update
	// engine.
	ueClient dbus.UpdateEngineClient

	// policyEnforcer is the PolicyEnforcer for interacting with
	// enforcement around COS device policy, including health monitor logging
	// and monitoring.
	policyEnforcer policyenforcer.PolicyEnforcer

	// instanceID is the instance ID of the GCE instance.
	instanceID uint64
}

// parseKeyValuePairs parses text with the form
//      key1=value1
//      key2=value2
//      ...
// into a map.
// All keys must have the format: "[a-zA-Z_]*".
// Any non-conforming lines are ignored.
func parseKeyValuePairs(reader io.Reader) (map[string]string, error) {
	content, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	pairs := make(map[string]string)

	// Regexp for matching key-value pairs.
	matchPair := regexp.MustCompile(`[a-zA-Z_]*=.*$`)

	// Extract release version string.
	lines := strings.Split(string(content), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if matchPair.MatchString(line) {
			pair := strings.Split(line, "=")
			key := strings.TrimSpace(pair[0])
			val := strings.TrimSpace(pair[1])
			pairs[key] = val
		}
	}

	return pairs, nil
}

// convertOSReleaseChannel takes in a release channel string from the
// lsb-release file and converts it into a ReleaseChannel type.
// If the release channel string cannot be parsed,
// RELEASE_CHANNEL_UNSPECIFIED will be returned.
func convertOSReleaseChannel(channelString string) pmpb.ReleaseChannel {
	// Regexp for matching release channel strings.
	// Release channel strings have the format "<name>-channel". For
	// example, "dev-channel".
	pattern := `^([a-z]{1,}-channel)$`
	matchVersionString := regexp.MustCompile(pattern)

	// Check we have a valid release channel string.
	if matchVersionString.MatchString(channelString) {
		ch := strings.ToUpper(strings.Split(channelString, "-")[0])
		if c, ok := pmpb.ReleaseChannel_value[ch]; ok {
			return pmpb.ReleaseChannel(c)
		}
	}

	// Unable to parse release channel.
	return pmpb.ReleaseChannel_RELEASE_CHANNEL_UNSPECIFIED
}

// parseOSInfoFromLSB returns the current OS version and release channel as
// provided by the lsb-release file. An error is returned only if the lsb file
// cannot be parsed.
func parseOSInfoFromLSB(apiHandler sysapi.APIHandler) (*pmpb.OSVersion, error) {
	content, err := apiHandler.ReadFile(lsbFile)
	if err != nil {
		return nil, err
	}

	// Parse lsb-release file as key value pairs.
	pairs, err := parseKeyValuePairs(bytes.NewReader(content))
	if err != nil {
		return nil, fmt.Errorf("unable to parse '%s': %s", lsbFile, err)
	}

	osVersion := new(pmpb.OSVersion)

	// Get release version string.
	if version, ok := pairs[lsbChromeOSReleaseKey]; ok {
		osVersion.VersionString = proto.String(version)
	}

	// Get the release channel.
	if channel, ok := pairs[lsbChromeOSReleaseChannelKey]; ok {
		ch := convertOSReleaseChannel(channel)
		osVersion.Channel = &ch
	}

	// Get release milestone.
	if milestone, ok := pairs[lsbChromeOSReleaseMilestoneKey]; ok {
		if n, err := strconv.ParseUint(milestone, 10, 32); err == nil {
			osVersion.Milestone = proto.Uint32(uint32(n))
		}
	}

	return osVersion, nil
}

// getStatusFromUpdateEngine returns the pmpb.InstanceStatus protobuf
// with the update status filled in.
func getStatusFromUpdateEngine(ueClient dbus.UpdateEngineClient) (*pmpb.InstanceStatus, error) {
	response, err := ueClient.GetStatus()

	if err != nil {
		return nil, err
	}

	status := new(pmpb.InstanceStatus)

	// Set update status.
	status.UpdateStatus = response.UpdateStatus
	if status.UpdateStatus == nil {
		return nil, fmt.Errorf("failed to fetch update status: It is possible that update_engine has not fetched the status yet.")
	}

	// Set new OS version.
	status.NewOsVersion = new(pmpb.OSVersion)
	status.NewOsVersion.VersionString = proto.String(*response.NewVersion)

	// Set last update check timestamp.
	status.UpdateCheckTimestamp = proto.Int64(*response.LastCheckedTime)

	return status, nil
}

// NewReporter creates a new Reporter.
func NewReporter(api sysapi.APIHandler, ueClient dbus.UpdateEngineClient,
	policyEnforcer policyenforcer.PolicyEnforcer, instanceID uint64) Reporter {
	return &reporterImpl{nil, api, ueClient, policyEnforcer, instanceID}
}

// GetStatus() returns the current status of the instance as given by
// /etc/lsb-release file and update-engine.
// If an error occured, the error will be returned along with a status protobuf
// where the error field is set to the message describing the error. If the
// error field is set, all other fields other than the InstanceId are invalid.
// Note that this function must always return a status with InstanceId field
// populated regardless of whether an error occurred or not.
func (rep *reporterImpl) GetStatus() (*pmpb.InstanceStatus, error) {
	status := new(pmpb.InstanceStatus)

	status.InstanceId = proto.Uint64(rep.instanceID)

	// Get OS version.
	// Check if we already know the current OS version.
	if rep.currentOSVersion == nil {
		// Get OS version from lsb-release file.
		osVersion, err := parseOSInfoFromLSB(rep.api)
		if err != nil {
			status.Error = proto.String(err.Error())
			return status, err
		}

		rep.currentOSVersion = osVersion
	}

	status.OsVersion = rep.currentOSVersion

	// Get update status from update-engine via dbus.
	updateStatus, err := getStatusFromUpdateEngine(rep.ueClient)
	if err != nil {
		status.UpdateStatus = nil
		status.Error = proto.String(err.Error())
		return status, err
	}

	proto.Merge(status, updateStatus)

	// Get healthmonitor logging and monitoring status health monitor Client.
	healthMonitorStatus, err := rep.policyEnforcer.GetHealthMonitorStatus()
	status.HealthMonitorStatus = healthMonitorStatus
	if err != nil {
		status.Error = proto.String(err.Error())
		return status, err
	}

	return status, nil
}

// GetOSVersion parses and returns the OS Version from /etc/lsb-release file.
// It returns error if unable to parse /etc/lsb-release file.
func (rep *reporterImpl) GetOSVersion() (*pmpb.OSVersion, error) {
	return parseOSInfoFromLSB(rep.api)
}
