package icshttp

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/big"
	"net/http"
	"strings"
	"sync"
	"time"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icspacketer"
	"gitlab.com/cinnamon/voiceagent/icspacketparser"
)

const HANDLE_NUM = 1024

const (
	TTS_FUNC1 = iota
	TTS_FUNC2
	TTS_FUNC3
	TTS_FUNC4
	BOT_FUNC
)

type Handler struct {
	r *Router
}

type handleInfo struct {
	id      int
	method  string
	pattern string
	h       http.HandlerFunc
}

type Request struct {
	Token          string          `json:"token"`
	OprMngCode     string          `json:"oprMngCode"`
	Method         string          `json:"method"`
	TalkText       string          `json:"talkText"`
	CallId         string          `json:"callId"`
	TrunkGroup     string          `json:"trunkGroup"`
	TelNo          string          `json:"telNo"`
	Dnis           string          `json:"dnis"`
	MentType       string          `json:"mentType"`
	RecordFilePath string          `json:"recordFilePath"`
	ServerID       string          `json:"serverId"`
	ServerIP       string          `json:"serverIp"`
	Data           json.RawMessage `json:"data"`
}

type Transrate struct {
	TargetDnis string `json:"target_dnis"`
}

type Response struct {
	ResultCode       int     `json:"resultCode"`
	Token            string  `json:"token"`
	Action           string  `json:"action"`
	AnounceMents     string  `json:"announceMents"`
	AnnounceFilePath string  `json:"announceFilePath"`
	Data             ResData `json:"DATA"`
}

type ResData struct {
	BargeIn      string          `json:"bargeIn"`
	RecodingFile string          `json:"recodingFile"`
	SttMaxTime   int             `json:"sttMaxTime"`
	MaxDigit     int             `json:"maxDigit"`
	MinDigit     int             `json:"minDigit"`
	DigitTerm    int             `json:"digitTerm"`
	TelNo        string          `json:"telNo"`
	VoiceName    int             `json:"voiceName"`
	Speed        int             `json:"speed"`
	Volume       int             `json:"volume"`
	Pitch        int             `json:"pitch"`
	EndCharacter []string        `json:"endCharacter"`
	MaxWaitTime  int             `json:"maxNoInputTime"`
	UUI          json.RawMessage `json:"uui"`
}

type ResStatus struct {
	Count         int
	Status        string
	NotUnderstand int
	PreEventNum   int
	PreEventNum2  int
	LoopCount     int
}

type ScenarioSession struct {
	session map[string]ResStatus
	m       *sync.Mutex
}

// var scenarioSession map[string]ResStatus

var handles []*handleInfo
var session []*ScenarioSession

func init() {
	handles = make([]*handleInfo, HANDLE_NUM)
	// session := make(map[string]ResStatus) // session init
	scenarioSession := new(ScenarioSession)
	scenarioSession.session = make(map[string]ResStatus, 200)
	scenarioSession.m = &sync.Mutex{}
	// session = make(map[string]ResStatus) // session init

	//TTS
	handles[TTS_FUNC1] = &handleInfo{method: "GET", pattern: "/tts/1", h: TTSFunc1}
	handles[TTS_FUNC2] = &handleInfo{method: "GET", pattern: "/tts/2", h: TTSFunc2}
	handles[TTS_FUNC3] = &handleInfo{method: "POST", pattern: "/tts/3", h: TTSFunc3}
	handles[TTS_FUNC4] = &handleInfo{method: "POST", pattern: "/tts/4", h: TTSFunc4}

	// bot sinario
	handles[BOT_FUNC] = &handleInfo{method: "POST", pattern: "/platform/api/call/process", h: scenarioSession.BOTPFunc}
}

func BuildHandler(r *Router) {
	for iter, handle := range handles {
		if handle != nil {
			//fmt.Println(handle)
			handle.id = iter
			r.HandleFunc(handle.method, handle.pattern, handle.h)
		} else {
			break
		}
	}
}

/////////////////////////////////////////////
//TTS

func TTSFunc1(w http.ResponseWriter, r *http.Request) {
	h := icspacketparser.NewHTTP()
	err := icspacketer.PutPacket(r, &h)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Fprintln(w, "TTS func 1", r)
}

func TTSFunc2(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "TTS func 2", r)
}

// post
func TTSFunc3(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "TTS func 3", r)
	body := make([]byte, r.ContentLength)
	r.Body.Read(body)
	fmt.Println("TTS func 3", r.Method, r.URL)
	for iter, v := range r.Header {
		fmt.Println(iter, v)
	}
	fmt.Println(string(body))
}

// post
func TTSFunc4(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "TTS func 4", r)
}

// ///////////////////////////////////////////
// BOT
func (s *ScenarioSession) BOTPFunc(w http.ResponseWriter, r *http.Request) {
	// get scenario config
	l := icslog.GetIcsLog()
	conf := icsconf.GetIcsConfig()
	scnarioConf := conf.ScenarioConfig
	// Request json parsing
	request := Request{}
	resBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Println(err)
	}
	defer r.Body.Close()

	err = json.Unmarshal(resBody, &request)
	fmt.Printf("%+v\n", request)
	if err != nil {
		l.Printf(icslog.LOG_LEVEL_INFO, -1, "response unmarshal error!!!!! ")
	}

	agent := strings.SplitN(request.CallId, "@", 2)
	l.Printf(icslog.LOG_LEVEL_INFO, -1, ">>>>>> DATA INFO - method [%s], agent [%s], token [%s] talk[%s]", request.Method, agent, request.Token, request.TalkText)

	response := new(Response)
	dnis := request.Dnis

	if request.Method == "HANGUP" {
		response.ResultCode = 200
		response.Token = request.Token
		response.Action = ""
		response.AnounceMents = ""
		response.Data.BargeIn = ""
		response.Data.RecodingFile = ""
		response.Data.SttMaxTime = 10
	} else if request.Method != "INIT" && request.TalkText != "" {
		l.Printf(icslog.LOG_LEVEL_INFO, -1, "dnis: %s", dnis)
		response.ResultCode = 200
		response.Token = request.Token
		response.Action = scnarioConf[dnis][s.session[request.Token].Count].Action
		// response.AnounceMents = scnarioConf[dnis][s.session[request.Token].Count].AnounceMents
		response.AnounceMents = request.TalkText
		response.Data.Speed = scnarioConf[dnis][s.session[request.Token].Count].Speed
		response.Data.VoiceName = scnarioConf[dnis][s.session[request.Token].Count].VoiceName
		response.Data.Volume = scnarioConf[dnis][s.session[request.Token].Count].Volume
		response.Data.Pitch = scnarioConf[dnis][s.session[request.Token].Count].Pitch
		response.Data.MaxWaitTime = scnarioConf[dnis][s.session[request.Token].Count].MaxWaitTime
		response.Data.BargeIn = scnarioConf[dnis][s.session[request.Token].Count].BargeIn
		response.Data.SttMaxTime = scnarioConf[dnis][s.session[request.Token].Count].SttMaxTime
		response.Data.MaxDigit = scnarioConf[dnis][s.session[request.Token].Count].MaxDigit
		response.Data.EndCharacter = []string{scnarioConf[dnis][s.session[request.Token].Count].EndCharacter}
		response.Data.DigitTerm = scnarioConf[dnis][s.session[request.Token].Count].DigitTerm
		response.Data.RecodingFile = "Y"

		s.session[request.Token] = ResStatus{Count: s.session[request.Token].Count, Status: scnarioConf[dnis][s.session[request.Token].Count].Action}
		l.Printf(icslog.LOG_LEVEL_INFO, -1, "response: %+v", response)

	} else {
		switch request.Method {
		case "INIT":
			l.Printf(icslog.LOG_LEVEL_INFO, -1, "INIT..scnarioConf[dnis][1].AnounceMents: %s", scnarioConf[dnis][1].AnounceMents)
			token := createToken(request.CallId)
			response.ResultCode = 200
			response.Token = token
			response.Action = scnarioConf[dnis][1].Action
			response.AnounceMents = scnarioConf[dnis][1].AnounceMents
			response.Data.Speed = scnarioConf[dnis][1].Speed
			response.Data.VoiceName = scnarioConf[dnis][1].VoiceName
			response.Data.Volume = scnarioConf[dnis][1].Volume
			response.Data.Pitch = scnarioConf[dnis][1].Pitch
			response.Data.MaxWaitTime = scnarioConf[dnis][1].MaxWaitTime
			response.Data.BargeIn = scnarioConf[dnis][1].BargeIn
			response.Data.SttMaxTime = scnarioConf[dnis][1].SttMaxTime
			response.Data.MaxDigit = scnarioConf[dnis][1].MaxDigit
			response.Data.EndCharacter = []string{scnarioConf[dnis][1].EndCharacter}
			response.Data.DigitTerm = scnarioConf[dnis][1].DigitTerm
			response.AnnounceFilePath = scnarioConf[dnis][1].AudioFilePath
			response.Data.RecodingFile = "Y"
			s.session[token] = ResStatus{Count: 1, Status: scnarioConf[dnis][1].Action, NotUnderstand: 0, PreEventNum: 1}
		}
	}
	response.Data.UUI = json.RawMessage{}
	uuiMap := map[string]interface{}{
		"test1": "testdata1231",
		"test2": 123,
		"test3": 0.1,
	}

	// 맵을 JSON으로 마샬링
	uuiJSON, err := json.Marshal(uuiMap)
	if err != nil {
		l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Error marshaling UUI: %v", err)

		return
	}

	// 마샬링된 JSON을 json.RawMessage로 변환
	response.Data.UUI = json.RawMessage(uuiJSON)
	response.Data.TelNo = request.TelNo
	// s.m.Unlock()
	// response marshal

	resMarshal, jerr := json.Marshal(response)
	if jerr != nil {
		l.Printf(icslog.LOG_LEVEL_ERROR, -1, "Json Marshal error %v", jerr)
	}
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "%+v", response)
	l.Printf(icslog.LOG_LEVEL_INFO, -1, "Send Message\n %s", string(resMarshal))

	// if s.session[request.Token].Count < len(scnarioConf[dnis]) && scnarioConf[dnis][s.session[request.Token].Count].TimeValue {
	// 	l.Printf(icslog.LOG_LEVEL_INFO, -1, "Time Sleep %d \r\n", scnarioConf[dnis][s.session[request.Token].Count].TimeSleep)
	// 	time.Sleep(time.Second * time.Duration(time.Duration(scnarioConf[dnis][s.session[request.Token].Count].TimeSleep)))
	// } else {

	// }
	time.Sleep(time.Second * 1)
	// send response
	fmt.Fprintln(w, string(resMarshal))

}

func createToken(callId string) string {
	token := ""
	times := fmt.Sprintf("%d", time.Now().UnixNano()/1000000)
	tokens := strings.Split(callId, "@")[0] + times
	token = tokens[0:8] + "-" + tokens[8:10] + "-" + tokens[10:23]
	return token
}

func cryptoRandSecure(max int64) int64 {
	nBig, err := rand.Int(rand.Reader, big.NewInt(max))
	if err != nil {
		fmt.Println(err)
	}
	return nBig.Int64()
}

func (s *ScenarioSession) ByeCheck(method string, token string) {
	l := icslog.GetIcsLog()
	// fmt.Printf(">>>>>> SESSION BYE INFO - token [%s]\n", token)
	l.Printf(icslog.LOG_LEVEL_INFO, -1, ">>>>>> SESSION BYE INFO - token [%s] ", token)
	s.m.Lock()
	delete(s.session, token)
	s.m.Unlock()
}
