package mapping

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"iwarma.ru/console/correlator/config"
)

type Meta struct {
	Description string `json:"description"`
}

type Index struct {
	IndexPatterns []string               `json:"index_patterns"`
	Template      map[string]interface{} `json:"template"`
	Priority      int                    `json:"priority"`
	ComposedOf    []string               `json:"composed_of"`
	Version       int                    `json:"version"`
	MetaInfo      Meta                   `json:"_meta,omitempty"`
}

type IndexResponseItem struct {
	Name     string `json:"name"`
	Template Index  `json:"index_template"`
}

type IndexResponse struct {
	Templates []IndexResponseItem `json:"index_templates"`
}

func ReadIndex(reader io.Reader) (Index, error) {
	byteValue, err := ioutil.ReadAll(reader)
	if err != nil {
		log.Errorf("Can't read index: %v", err)
		return Index{}, err
	}

	var result Index
	err = json.Unmarshal(byteValue, &result)
	if err != nil {
		log.Errorf("Can't unmarshall index: %v", err)
		return Index{}, err
	}

	return result, nil
}

func ReadIndexFromFile(fileName string) (Index, error) {
	file, err := os.Open(fileName)
	if err != nil {
		log.Errorf("Can't open file: %v", err)
		return Index{}, err
	}
	defer file.Close()

	return ReadIndex(file)
}

func ReadIndexResponse(reader io.Reader) (IndexResponse, error) {
	byteValue, err := ioutil.ReadAll(reader)
	if err != nil {
		log.Errorf("Can't read index response: %v", err)
		return IndexResponse{}, err
	}

	var result IndexResponse
	err = json.Unmarshal(byteValue, &result)
	if err != nil {
		log.Errorf("Can't unmarshall index response: %v", err)
		return IndexResponse{}, err
	}

	return result, nil
}

func CheckIndextUpdate(url string, index Index) (bool, error) {
	// Get current mapping for index
	http_client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Errorf("Can't create get index mapping request: %v", err)
		return false, err
	}

	// Set auth
	req.SetBasicAuth(viper.GetString(config.ElasticUsername), viper.GetString(config.ElasticPassword))

	resp, err := http_client.Do(req)
	if err != nil {
		log.Errorf("Can't send index get index mapping request: %v", err)
		return false, err
	}
	defer resp.Body.Close()

	responseComponent, err := ReadIndexResponse(resp.Body)
	if err != nil {
		log.Errorf("Can't read get mappint for index response: %v", err)
		return false, err
	}

	// Now, check version
	max_version := 0
	for _, cur := range responseComponent.Templates {
		if cur.Template.Version > max_version {
			max_version = cur.Template.Version
		}
	}

	log.Debugf("After checking %v versions, found max version %v, index version is %v", len(responseComponent.Templates), max_version, index.Version)

	return index.Version > max_version, nil
}

func UpdateIndex(url string, index Index) error {

	byteValue, err := json.Marshal(index)
	if err != nil {
		log.Errorf("Can't marshall index: %v", err)
		return err
	}

	buffer := bytes.NewBuffer(byteValue)

	req, err := http.NewRequest("PUT", url, buffer)
	if err != nil {
		log.Errorf("Can't create index update request: %v", err)
		return err
	}

	req.SetBasicAuth(viper.GetString(config.ElasticUsername), viper.GetString(config.ElasticPassword))
	req.Header.Add("Content-Type", "application/json")

	http_client := &http.Client{}
	resp, err := http_client.Do(req)
	if err != nil {
		log.Errorf("Can't exec index update request: %v", err)
		return err
	}
	defer resp.Body.Close()

	response, err := ReadUpdateResponse(resp.Body)
	if err != nil {
		log.Errorf("Can't read index update response")
		return err
	}

	if response.Acknowledged != true {
		return errors.New("Server didn't accept index")
	}

	return nil
}
