// Copyright 2018 Open Networking Foundation
//
// 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 main

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

	"github.com/sirupsen/logrus"

	"github.com/gorilla/mux"
)

func (c *Config) getSubscriberHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	sadisRequestID := vars["id"]

	log.WithFields(logrus.Fields{
		"sadisId": sadisRequestID,
	}).Infof("Looking for object %s in XOS database", sadisRequestID)

	defer r.Body.Close()

	subscribers := subscribers{}

	log.Debug("Checking subscribers")

	err := c.fetch("/xosapi/v1/rcord/rcordsubscribers", &subscribers)
	if err != nil {
		log.Errorf("Unable to retrieve subscriber information from XOS: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return

	}

	for _, sub := range subscribers.Subscribers {
		if sub.OnuSerialNumber == sadisRequestID {
			log.Infof("Found subscriber with ID %s", sub.OnuSerialNumber)
			sadisSubscriber := sadisSubscriber{
				ID:                   sub.OnuSerialNumber,
				CTag:                 sub.CTag,
				STag:                 sub.STag,
				NasPortID:            sub.NasPortID,
				CircuitID:            sub.CircuitID,
				RemoteID:             sub.RemoteID,
				TechnologyProfileID:  64,
			}

			log.Debugf("Fetching bandwidth profiles for subscriber %s", sub.OnuSerialNumber)

			dsBandwidthprofile := bandwidthprofile{}
			err = c.getOneBandwidthProfileHandler(sub.DownstreamBandwidthProfile, &dsBandwidthprofile)
			if err != nil {
				log.Errorf("Cannot fetch downstream bandwidth profile %s for subscriber %s", strconv.Itoa(sub.DownstreamBandwidthProfile), sub.OnuSerialNumber)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if (bandwidthprofile{}) == dsBandwidthprofile {
				// it's empty
				log.WithFields(logrus.Fields{
					"DownstreamBandwidthProfile": sub.DownstreamBandwidthProfile,
					"Subscriber":                 sub.OnuSerialNumber,
					"sadisId":                    sadisRequestID,
				}).Error("Downstream bandwidth profile not found in XOS")
				http.Error(w, "Downstream bandwidth profile not found in XOS", http.StatusInternalServerError)
				return
			}
			sadisSubscriber.DownstreamBandwidthProfile = dsBandwidthprofile.Name

			usBandwidthprofile := bandwidthprofile{}
			err = c.getOneBandwidthProfileHandler(sub.UpstreamBandwidthProfile, &usBandwidthprofile)
			if err != nil {
				log.Errorf("Cannot fetch upstream bandwidth profile %s for subscriber %s", strconv.Itoa(sub.UpstreamBandwidthProfile), sub.OnuSerialNumber)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if (bandwidthprofile{}) == usBandwidthprofile {
				// it's empty
				log.WithFields(logrus.Fields{
					"UpstreamBandwidthProfile": usBandwidthprofile.Name,
					"Subscriber":               sub.OnuSerialNumber,
					"sadisId":                  sadisRequestID,
				}).Error("Upstream bandwidth profile not found in XOS")
				http.Error(w, "Upstream bandwidth profile not found in XOS", http.StatusInternalServerError)
				return
			}
			sadisSubscriber.UpstreamBandwidthProfile = usBandwidthprofile.Name

			log.WithFields(logrus.Fields{
				"UpstreamBandwidthProfile":   usBandwidthprofile.Name,
				"DownstreamBandwidthProfile": dsBandwidthprofile.Name,
				"Subscriber":                 sub.OnuSerialNumber,
				"sadisId":                    sadisRequestID,
			}).Debug("Bandwidth profiles for subscriber")

			json, e := json.Marshal(&sadisSubscriber)
			if e != nil {
				log.Errorf("Unable to marshal JSON: %s", e)
				http.Error(w, e.Error(), http.StatusInternalServerError)
				return
			}
			w.Write(json)
			return
		}
	}

	log.Debug("Checking devices")

	devices := oltDevices{}

	err = c.fetch("/xosapi/v1/volt/oltdevices", &devices)
	if err != nil {
		log.Errorf("Unable to retrieve device information from XOS: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return

	}

	for _, device := range devices.OltDevices {
		// NOTE if it's an OLT then sadisRequestID is the device serial number
		devID := device.SerialNumber
		if devID == sadisRequestID {
			log.Infof("Found OLT device with ID %s", devID)

			ipaddr := device.Host
			addr, err := net.ResolveIPAddr("ip", device.Host)
			if err != nil {
				log.Errorf("Resolution error: %s", err.Error())
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			} else {
				ipaddr = addr.String()
			}
			log.Debugf("ID: %s, Uplink: %d, IPAddress: %s, NasID: %s", devID, toInt(device.Uplink), ipaddr, device.NasID)
			sadisDevice := sadisDevice{
				ID:         devID,
				Uplink:     toInt(device.Uplink),
				HardwareID: "de:ad:be:ef:ba:11", // TODO do we really need to configure this?
				IPAddress:  ipaddr,
				NasID:      device.NasID,
			}

			json, e := json.Marshal(&sadisDevice)
			if e != nil {
				log.Errorf("Unable to marshal JSON: %s", e)
				http.Error(w, e.Error(), http.StatusInternalServerError)
				return
			}
			w.Write(json)
			return
		}
	}

	log.WithFields(logrus.Fields{
		"sadisId": sadisRequestID,
	}).Infof("Couldn't find object %s in XOS database", sadisRequestID)

	http.NotFound(w, r)
}

func (c *Config) getBandwidthProfileHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	sadisRequestID := vars["id"]

	log.WithFields(logrus.Fields{
		"sadisId": sadisRequestID,
	}).Infof("Fetching BandwidthProfiles from XOS database")
	defer r.Body.Close()

	bandwidthprofiles := bandwidthprofiles{}

	err := c.fetch("/xosapi/v1/rcord/bandwidthprofiles", &bandwidthprofiles)

	if err != nil {
		log.Errorf("Unable to retrieve bandwidth profiles information from XOS: %s", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	for _, profile := range bandwidthprofiles.Profiles {
		profileID := profile.Name
		if profileID == sadisRequestID {
			sadisProfile := sadisBandwidthProfile{
				ID:  profile.Name,
				Cir: profile.Cir,
				Cbs: profile.Cbs,
				Eir: profile.Eir,
				Ebs: profile.Ebs,
				Air: profile.Air,
			}
			json, e := json.Marshal(&sadisProfile)
			if e != nil {
				log.Errorf("Unable to marshal JSON: %s", e)
				http.Error(w, e.Error(), http.StatusInternalServerError)
				return
			}
			w.Write(json)
			return
		}
	}

	log.WithFields(logrus.Fields{
		"sadisId": sadisRequestID,
	}).Infof("Couldn't find object %s in XOS database", sadisRequestID)

	http.NotFound(w, r)
}

func (c *Config) getOneBandwidthProfileHandler(id int, data interface{}) error {
	err := c.fetch("/xosapi/v1/rcord/bandwidthprofiles/"+strconv.Itoa(id), &data)
	if err != nil {
		log.Errorf("Unable to retrieve bandwidth profile information from XOS: %s", err)
		return err
	}
	return nil
}

func toInt(value string) int {
	r, _ := strconv.Atoi(value)
	return r
}

func (c *Config) fetch(path string, data interface{}) error {
	resp, err := http.Get(c.connect + path)

	if err != nil {
		return err
	}

	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(data)
	log.WithFields(logrus.Fields{
		"path":   path,
		"resp":   data,
		"status": resp.Status,
	}).Debug("Received data from XOS")
	return err
}
