package mongoClient

import (
	"encoding/json"
	"fmt"
	mgo "mongo"
	"mongo/bson"
	"ssp/constants"
	"ssp/logger"
	"ssp/redisClient"
	"strconv"
	"time"
)

var redisclient = redisClient.Initialize()

// SerializeRequestData Type
type SerializeRequestData struct {
	RequestId string      `bson:"requestId" json:"requestId,omitempty"`
	Data      interface{} `bson:"data" json:"data"`
	BidderID  int         `bson:"bidderid" json:"bidderid"`
	Version   string      `bson:"ver" json:"ver"`
	Datetime  string      `bson:"datetime" json:"datetime"`
}
type DummyData struct {
	Id        bson.ObjectId `bson:"_id" json:"_id,omitempty"`
	Dummydata string        `bson:"dummydata" json:"dummydata,omitempty"`
}

// SerializeResponseData Type
type SerializeResponseData struct {
	//~ Id         bson.ObjectId `bson:"_id" json:"_id,omitempty"`
	ResponseId string      `bson:"responseId" json:"responseId,omitempty"`
	Data       interface{} `bson:"data" json:"data"`
	RequestID  string      `bson:"requestid" json:"requestid"`
	BidderID   int         `bson:"bidderid" json:"bidderid"`
	Version    string      `bson:"ver" json:"ver"`
	Datetime   string      `bson:"datetime" json:"datetime"`
}

type SerializeWinData struct {
	//~ Id         bson.ObjectId `bson:"_id" json:"_id,omitempty"`
	ResponseId string      `bson:"responseId" json:"responseId,omitempty"`
	Data       interface{} `bson:"data" json:"data"`

	Impression int     `bson:"impression" json:"impression"`
	Win_notice int     `bson:"win_notice" json:"win_notice"`
	Price      float64 `bson:"price" json:"price"`

	RequestID string `bson:"requestid" json:"requestid"`
	BidderID  int    `bson:"bidderid" json:"bidderid"`
	Version   string `bson:"ver" json:"ver"`
	Datetime  string `bson:"datetime" json:"datetime"`
}

// VastCount Type
type VastCount struct {
	Id         bson.ObjectId `bson:"_id" json:"_id,omitempty"`
	Exchangeid int           `bson:"exchangeid" json:"exchangeid"`
	Zoneid     int           `bson:"zoneid" json:"zoneid"`
	Event      string        `bson:"event" json:"event"`
	Datetime   string        `bson:"datetime" json:"datetime"`
}

// Mongo Connection Function
func MongoConnect() *mgo.Session {

	fmt.Println("Mongo COnnect")
	defer func() {
		if err := recover(); err != nil {
			logger.Log.Println("Error occured : ", err, " Recovered from panic")
		}
	}()
	info := &mgo.DialInfo{
		Addrs:    []string{constants.MongoHost},
		Timeout:  30 * time.Second,
		Database: constants.MongoDbName,
		Username: constants.MongoUser,
		Password: constants.MongoPass,
	}
	Session, err := mgo.DialWithInfo(info)
	if err != nil {
		logger.Log.Println("Error in connecting to MongoDB! ", err)
	}
	return Session
}

// Mongo Collection Function
func MongoCollection(collectionName string) (*mgo.Session, *mgo.Collection) {
	defer func() {
		if err := recover(); err != nil {
			logger.Log.Println("Error occured : ", err, " Recovered from panic")
		}
	}()
	client := MongoConnect()
	collection := client.DB(constants.MongoDbName).C(collectionName)
	return client, collection
}

func MongoSaveDummyData() {

	//~ objid := bson.NewObjectId()

	//~ client, collection := MongoCollection("DummyData")
	//~ defer client.Close()
	//~ collection.Insert(DummyData{Id: objid})

}

// Save Request Function
func MongoSaveRequest(insertReq chan bool, reqId string, jsonReq []byte, dsp_id int, ver string) {

	//~ insertReq <- false
	//~ return

	defer func() {
		if err := recover(); err != nil {
			logger.Log.Println("Error occured : ", err, " Recovered from panic")
		}
	}()
	var reqData SerializeRequestData
	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMin(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	var jsonReq_data interface{}
	json.Unmarshal(jsonReq, &jsonReq_data)

	reqData = SerializeRequestData{RequestId: reqId, Data: get_details(jsonReq_data), BidderID: dsp_id, Version: ver, Datetime: time.Now().Format("2006-01-02 15:04:05")}

	redisclient.RPush("mongo_request"+tableSuffix, reqData, 500)

	insertReq <- true
}

// Save Response Function
func MongoSaveResponse(insertRes chan bool, responseId string, reqId string, jsonRes []byte, dsp_id int, ver string) {

	defer func() {
		if err := recover(); err != nil {
			logger.Log.Println("Error occured : ", err, " Recovered from panic")
		}
	}()
	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMin(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	var jsonRes_data interface{}
	json.Unmarshal(jsonRes, &jsonRes_data)

	resData := SerializeResponseData{ResponseId: responseId, Data: get_details(jsonRes_data), RequestID: reqId, BidderID: dsp_id, Version: ver, Datetime: time.Now().Format("2006-01-02 15:04:05")}

	redisclient.RPush("mongo_response"+tableSuffix, resData, 500)

	insertRes <- true
}

// Save Response Function
func MongoSaveWin(responseId string, jsonRes []byte, dsp_id int, price float64) {

	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMin(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	var jsonRes_data interface{}
	json.Unmarshal(jsonRes, &jsonRes_data)

	winData := SerializeWinData{Impression: 1, Win_notice: 1, Price: price, ResponseId: responseId, Data: get_details(jsonRes_data), BidderID: dsp_id, Datetime: time.Now().Format("2006-01-02 15:04:05")}

	//~ fmt.Println(winData)
	redisclient.RPush("mongo_win"+tableSuffix, winData, 500)

}

func MongoSaveWinAction(responseId string) {

	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMin(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	winData := SerializeWinData{}

	redisclient.GetKey(responseId, &winData)

	if winData.Impression == 1 {

		redisclient.RPush("mongo_win"+tableSuffix, winData, 500)

	}

}

func MongoRequestMove(tableSuffix2 string) {

	results := redisclient.LRange("mongo_request"+tableSuffix2, 20000)

	fmt.Println(results)

	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMinGoal(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)
	fmt.Println("mongo_request" + tableSuffix2)

	client, collection := MongoCollection(constants.MongoRequestTable + "_" + tableSuffix)
	defer client.Close()
	var ui []interface{}

	for _, value := range results {

		var cacheEntry interface{}
		json.Unmarshal([]byte(value), &cacheEntry)

		ui = append(ui, cacheEntry)
	}

	err := collection.Insert(ui...)

	fmt.Println(err)

}

func MongoResponseMove(tableSuffix2 string) {

	results := redisclient.LRange("mongo_response"+tableSuffix2, 20000)

	//~ fmt.Println(results)

	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMinGoal(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	client, collection := MongoCollection(constants.MongoResponseTable + "_" + tableSuffix)
	defer client.Close()
	var ui []interface{}

	for _, value := range results {

		var cacheEntry interface{}
		json.Unmarshal([]byte(value), &cacheEntry)

		ui = append(ui, cacheEntry)
	}

	err := collection.Insert(ui...)

	fmt.Println(err)

}

func MongoWinMove(tableSuffix2 string) {

	results := redisclient.LRange("mongo_win"+tableSuffix2, 20000)

	//~ fmt.Println(results)

	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := GetMinGoal(t.Minute())
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)

	client, collection := MongoCollection(constants.MongoWinNoticeTable + "_" + tableSuffix)
	defer client.Close()
	var ui []interface{}

	for _, value := range results {

		var cacheEntry interface{}
		json.Unmarshal([]byte(value), &cacheEntry)

		ui = append(ui, cacheEntry)
	}

	err := collection.Insert(ui...)

	fmt.Println(err)

}

// Save Response Function
func MongoSaveVastCount(zoneid int, exchangeid int, event string) (error, bool) {

	//~ return error

	defer func() {
		if err := recover(); err != nil {
			logger.Log.Println("Error occured : ", err, " Recovered from panic")
		}
	}()
	t := time.Now()
	y := t.Year()
	mon := int(t.Month())
	d := t.Day()
	h := t.Hour()
	min := 0
	tableSuffix := strconv.Itoa(y) + strconv.Itoa(mon) + strconv.Itoa(d) + strconv.Itoa(h) + strconv.Itoa(min)
	// Get a handle for your collection
	client, collection := MongoCollection(constants.MongoVastTable + "_" + tableSuffix)
	defer client.Close()
	// Insert document
	objid := bson.NewObjectId()
	err := collection.Insert(VastCount{Id: objid, Zoneid: zoneid, Exchangeid: exchangeid, Event: event, Datetime: time.Now().Format("2006-01-02 15:04:05")})
	if err != nil {
		return err, false
	}
	return nil, true
}

// Function for getting minutes
func GetMin(k int) (m int) {

	if k%5 > 0 {
		m = k - (k % 5)

	}

	//~ if k <= 15 && k >= 0 {
	//~ m = 0
	//~ } else if k <= 30 && k > 15 {
	//~ m = 15
	//~ } else if k <= 45 && k > 30 {
	//~ m = 30
	//~ } else if k <= 59 && k > 45 {
	//~ m = 45
	//~ }
	return
}
func GetMinGoal(k int) (m int) {

	//~ if k%5 > 0 {
	//~ m = k - (k%5)

	//~ }

	if k <= 15 && k >= 0 {
		m = 0
	} else if k <= 30 && k > 15 {
		m = 15
	} else if k <= 45 && k > 30 {
		m = 30
	} else if k <= 59 && k > 45 {
		m = 45
	}
	return
}

func get_details(data interface{}) interface{} {

	//~ datas := ReqResData{}

	//~ fmt.Println(data["device"])

	//~ datas.RrSite = RrSite{Site_domain : data.site.domain, Site_page_url : data.site.page  }
	//~ datas.RrDevice = RrDevice{Device_os : data.device.os, Device_ip : data.device.ip , Device_user_agent : data.device.ua , Device_language : data.device.language , Device_type : data.device.devicetype ,  Device_make : data.device.make , Device_model : data.device.model, RrGeo : RrGeo {Geo_country : data.device.country  }	 }

	return data

}

type ReqResData struct {
	RrSite   RrSite   `json:"site" bson:"site"`
	RrDevice RrDevice `json:"device" bson:"device"`
	RrUser   RrUser   `json:"user" bson:"user"`
}

type RrSite struct {
	Site_domain   string `json:"domain" bson:"domain"`
	Site_page_url string `json:"page_url" bson:"page_url"`
	Site_ref_url  string `json:"ref_url" bson:"ref_url"`
}

type RrGeo struct {
	Geo_country string `json:"country" bson:"country"`
}

type RrDevice struct {
	Device_os         string `json:"os" bson:"os"`
	Device_ip         string `json:"ip" bson:"ip"`
	Device_user_agent string `json:"ua" bson:"ua"`
	Device_language   string `json:"language" bson:"language"`
	Device_type       int32  `json:"device_type" bson:"device_type"`
	Device_make       string `json:"make" bson:"make"`
	Device_model      string `json:"model" bson:"model"`
	RrGeo             RrGeo  `json:"geo" bson:"geo"`
}

type RrUser struct {
	User_yob    int32  `json:"yob" bson:"yob"`
	User_gender string `json:"gender" bson:"gender"`
}
