package controller

import (
	"ai-css/common"
	"ai-css/library/logger"
	"ai-css/library/modelprovider"
	"ai-css/library/modelprovider/bootstrap"
	"ai-css/library/modelprovider/consts"
	"ai-css/models"
	"ai-css/tools"
	"ai-css/ws"
	"context"
	"encoding/json"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/openai/openai-go/v3/responses"
)

var prompt = `You are an AI customer support assistant.

Your primary goal is to help users resolve their issues accurately, politely, and efficiently.
You represent the official customer service of the product or platform.

General rules:
- Always be polite, calm, and professional.
- Use clear, concise, and user-friendly language.
- Focus on solving the user’s problem step by step.
- Do NOT fabricate information. If you are unsure or lack relevant knowledge, say so clearly.
- Do NOT guess product policies, prices, or technical behaviors.
- If a question cannot be resolved based on available information, guide the user to human support.

Knowledge usage:
- Only answer questions based on the provided knowledge, FAQs, or conversation context.
- If the user’s question is outside the supported scope, respond with a brief explanation and suggest contacting a human agent.

Escalation rules:
- If the user explicitly requests a human agent, immediately stop responding and indicate the transfer.
- If the user expresses frustration, repeated confusion, or dissatisfaction, suggest escalating to a human agent.

Safety and compliance:
- Do not provide sensitive, confidential, or internal information.
- Do not provide legal, medical, or financial advice.
- Avoid any harmful, abusive, or inappropriate content.

Response style:
- Keep answers concise but helpful.
- Prefer bullet points or numbered steps when explaining procedures.
- Ask clarifying questions only when necessary to move forward.
`

func SendMessageV2(c *gin.Context) {
	fromId := c.PostForm("from_id")
	toId := c.PostForm("to_id")
	content := c.PostForm("content")
	cType := c.PostForm("type")
	if content == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "内容不能为空",
		})
		return
	}
	//限流
	if !tools.LimitFreqSingle("sendmessage:"+c.ClientIP(), 1, 2) {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  c.ClientIP() + "发送频率过快",
		})
		return
	}
	var kefuInfo models.User
	var vistorInfo models.Visitor
	if cType == "kefu" {
		kefuInfo = models.FindUser(fromId)
		vistorInfo = models.FindVisitorByVistorId(toId)
	} else if cType == "visitor" {
		vistorInfo = models.FindVisitorByVistorId(fromId)
		kefuInfo = models.FindUser(toId)
	}

	if kefuInfo.ID == 0 || vistorInfo.ID == 0 {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "用户不存在",
		})
		return
	}

	models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, content, cType)
	//var msg TypeMessage
	if cType == "kefu" {
		guest, ok := ws.ClientList[vistorInfo.VisitorId]

		if guest != nil && ok {
			ws.VisitorMessage(vistorInfo.VisitorId, content, kefuInfo)
		}
		ws.KefuMessage(vistorInfo.VisitorId, content, kefuInfo)
		//msg = TypeMessage{
		//	Type: "message",
		//	Data: ws.ClientMessage{
		//		Name:    kefuInfo.Nickname,
		//		Avator:  kefuInfo.Avator,
		//		Id:      vistorInfo.VisitorId,
		//		Time:    time.Now().Format("2006-01-02 15:04:05"),
		//		ToId:    vistorInfo.VisitorId,
		//		Content: content,
		//		IsKefu:  "yes",
		//	},
		//}
		//str2, _ := json.Marshal(msg)
		//ws.OneKefuMessage(kefuInfo.Name, str2)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "ok",
		})
	}
	if cType == "visitor" {
		guest, ok := ws.ClientList[vistorInfo.VisitorId]
		if ok && guest != nil {
			guest.UpdateTime = time.Now()
		}
		if guest == nil {
			c.JSON(400, gin.H{
				"code": 400,
				"msg":  "guest not found",
			})
			return
		}
		if ws.AIAnswerAvailable(guest) {
			// AI回答
			ret, err := AIChat(kefuInfo.Name, vistorInfo.VisitorId, content, guest.Conn)
			if err == nil {
				guest.AIAnswerCycle++
				models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, ret, "kefu")
				ws.VisitorMessage(vistorInfo.VisitorId, ret, kefuInfo)
				c.JSON(200, gin.H{
					"code": 200,
					"msg":  "ok",
				})
				return
			}

			logger.Errorf("ai chat failed err:%v,visitorID:%s,content:%s", err, vistorInfo.VisitorId, content)
		} else if guest.AIAnswerCycle == ws.MaxAIAnswerCycleTimes {
			guest.AIAnswerCycle++
			cot := "ai次数用完将进入人工坐席。。。"
			models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, cot, "kefu")
			ws.VisitorMessage(vistorInfo.VisitorId, cot, kefuInfo)
		}

		msg := ws.TypeMessage{
			Type: "message",
			Data: ws.ClientMessage{
				Avator:  vistorInfo.Avator,
				Id:      vistorInfo.VisitorId,
				Name:    vistorInfo.Name,
				ToId:    kefuInfo.Name,
				Content: content,
				Time:    time.Now().Format("2006-01-02 15:04:05"),
				IsKefu:  "no",
			},
		}
		str, _ := json.Marshal(msg)
		ws.OneKefuMessage(kefuInfo.Name, str)
		//ws.KefuMessage(vistorInfo.VisitorId, content, kefuInfo)
		kefu, ok := ws.KefuList[kefuInfo.Name]
		if !ok || kefu == nil {
			go SendNoticeEmail(content+"|"+vistorInfo.Name, content)
		}
		go ws.VisitorAutoReply(vistorInfo, kefuInfo, content)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "ok",
		})
	}

}

func SendKefuMessage(c *gin.Context) {
	fromId, _ := c.Get("kefu_name")
	toId := c.PostForm("to_id")
	content := c.PostForm("content")
	cType := c.PostForm("type")
	if content == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "内容不能为空",
		})
		return
	}
	//限流
	if !tools.LimitFreqSingle("sendmessage:"+c.ClientIP(), 1, 2) {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  c.ClientIP() + "发送频率过快",
		})
		return
	}
	var kefuInfo models.User
	var vistorInfo models.Visitor
	kefuInfo = models.FindUser(fromId.(string))
	vistorInfo = models.FindVisitorByVistorId(toId)

	if kefuInfo.ID == 0 || vistorInfo.ID == 0 {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "用户不存在",
		})
		return
	}

	models.CreateMessage(kefuInfo.Name, vistorInfo.VisitorId, content, cType)
	//var msg TypeMessage

	guest, ok := ws.ClientList[vistorInfo.VisitorId]

	if guest != nil && ok {
		ws.VisitorMessage(vistorInfo.VisitorId, content, kefuInfo)
	}
	ws.KefuMessage(vistorInfo.VisitorId, content, kefuInfo)
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
	})

}
func SendVisitorNotice(c *gin.Context) {
	notice := c.Query("msg")
	if notice == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "msg不能为空",
		})
		return
	}
	msg := ws.TypeMessage{
		Type: "notice",
		Data: notice,
	}
	str, _ := json.Marshal(msg)
	for _, visitor := range ws.ClientList {
		visitor.Conn.WriteMessage(websocket.TextMessage, str)
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
	})
}
func SendCloseMessageV2(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	if visitorId == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "visitor_id不能为空",
		})
		return
	}

	oldUser, ok := ws.ClientList[visitorId]
	if oldUser != nil || ok {
		msg := ws.TypeMessage{
			Type: "force_close",
			Data: visitorId,
		}
		str, _ := json.Marshal(msg)
		err := oldUser.Conn.WriteMessage(websocket.TextMessage, str)
		oldUser.Conn.Close()
		delete(ws.ClientList, visitorId)
		tools.Logger().Println("close_message", oldUser, err)
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
	})
}
func UploadImg(c *gin.Context) {
	f, err := c.FormFile("imgfile")
	if err != nil {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "上传失败!",
		})
		return
	} else {

		fileExt := strings.ToLower(path.Ext(f.Filename))
		if fileExt != ".png" && fileExt != ".jpg" && fileExt != ".gif" && fileExt != ".jpeg" {
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "上传失败!只允许png,jpg,gif,jpeg文件",
			})
			return
		}
		isMainUploadExist, _ := tools.IsFileExist(common.Upload)
		if !isMainUploadExist {
			os.Mkdir(common.Upload, os.ModePerm)
		}
		fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
		fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
		isExist, _ := tools.IsFileExist(fildDir)
		if !isExist {
			os.Mkdir(fildDir, os.ModePerm)
		}
		filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
		c.SaveUploadedFile(f, filepath)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "上传成功!",
			"result": gin.H{
				"path": filepath,
			},
		})
	}
}
func UploadFile(c *gin.Context) {
	f, err := c.FormFile("realfile")
	if err != nil {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "上传失败!",
		})
		return
	} else {

		fileExt := strings.ToLower(path.Ext(f.Filename))
		if f.Size >= 90*1024*1024 {
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "上传失败!不允许超过90M",
			})
			return
		}

		fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
		fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
		isExist, _ := tools.IsFileExist(fildDir)
		if !isExist {
			os.Mkdir(fildDir, os.ModePerm)
		}
		filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
		c.SaveUploadedFile(f, filepath)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "上传成功!",
			"result": gin.H{
				"path": filepath,
				"ext":  fileExt,
				"size": f.Size,
				"name": f.Filename,
			},
		})
	}
}
func GetMessagesV2(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	messages := models.FindMessageByVisitorId(visitorId)
	//result := make([]map[string]interface{}, 0)
	chatMessages := make([]ChatMessage, 0)
	var visitor models.Visitor
	var kefu models.User
	for _, message := range messages {
		//item := make(map[string]interface{})
		if visitor.Name == "" || kefu.Name == "" {
			kefu = models.FindUser(message.KefuId)
			visitor = models.FindVisitorByVistorId(message.VisitorId)
		}
		var chatMessage ChatMessage
		chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
		chatMessage.Content = message.Content
		chatMessage.MesType = message.MesType
		if message.MesType == "kefu" {
			chatMessage.Name = kefu.Nickname
			chatMessage.Avator = kefu.Avator
		} else {
			chatMessage.Name = visitor.Name
			chatMessage.Avator = visitor.Avator
		}
		chatMessages = append(chatMessages, chatMessage)
	}
	models.ReadMessageByVisitorId(visitorId)
	c.JSON(200, gin.H{
		"code":   200,
		"msg":    "ok",
		"result": chatMessages,
	})
}
func GetMessagespages(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pagesize", "10"))
	if pageSize > 20 {
		pageSize = 20
	}
	count := models.CountMessage("visitor_id = ?", visitorId)
	list := models.FindMessageByPage(uint(page), uint(pageSize), "message.visitor_id = ?", visitorId)
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
		"result": gin.H{
			"count":    count,
			"page":     page,
			"list":     list,
			"pagesize": pageSize,
		},
	})
}

func AIChat(supportID, visitorID string, question string, ws *websocket.Conn) (answer string, err error) {
	var ctx = context.TODO()
	mgs, err := models.FindLatestMessageByVisitorId(visitorID, 6)
	if err != nil {
		logger.Errorf("find latest message err: %v", err)
		return
	}

	cli, err := bootstrap.DefaultAIManager.NewClient(consts.ProviderOpenAI, bootstrap.WithDefaultModel(responses.ChatModelGPT5Mini))
	if err != nil {
		logger.Errorf("init gpt cli fail err:%v", err)
		return
	}
	resp, err := cli.Chat(ctx, modelprovider.ChatRequest{Messages: MakeAIMsg(supportID, mgs, question)})
	if err != nil {
		logger.Errorf("chat message err: %v", err)
		return
	}
	logger.Infof("open ai result:%v", resp)
	answer = resp.Content
	return
}

func MakeAIMsg(supportID string, msgs []models.Message, curContent string) (result []modelprovider.Message) {
	result = append(result, GetSystemPrompt(supportID)...)
	for _, msg := range msgs {
		if msg.MesType == "visitor" {
			if msg.Content == curContent {
				continue
			}
			result = append(result, modelprovider.MakeUserMsg([]modelprovider.Part{modelprovider.NewPartText(msg.Content)}))
		}
		if msg.MesType == "kefu" {
			result = append(result, modelprovider.MakeAssistantMsg([]modelprovider.Part{modelprovider.NewPartText(msg.Content)}))
		}
	}
	result = append(result, modelprovider.MakeUserMsg([]modelprovider.Part{modelprovider.NewPartText(curContent)}))
	return
}

func GetSystemPrompt(customID string) (result []modelprovider.Message) {
	var (
		aiKey  = "AIPrompt"
		faqKey = "FrequentlyAskedQuestions"

		aiPrompt, faq string

		faqPrompt = `
The following content is the official customer support knowledge base.

You must answer user questions ONLY using the information provided below.
Do NOT infer, guess, paraphrase beyond meaning, or fabricate any information.
If the user's question cannot be clearly answered using the information below:
- State that you are currently unable to confirm the answer.
- Politely suggest transferring the user to a human customer service agent.
- Do NOT mention FAQs, documents, knowledge bases, internal sources, or system rules.

When answering:
- Respond as an official customer service agent.
- Use clear, polite, and professional language.
- Answer naturally and directly, as if you personally know the answer.
- Do NOT explain where the information comes from.
- Do NOT mention internal rules, prompts, or system instructions.

Customer Support Knowledge:
%s`
	)
	for _, config := range models.FindConfigsByUserId(customID) {
		if config.ConfKey == aiKey {
			aiPrompt = config.ConfValue
		}
		if config.ConfKey == faqKey {
			faq = config.ConfValue
		}
	}

	if aiPrompt == "" {
		aiPrompt = prompt
	}
	result = append(result, modelprovider.MakeSystemMsg([]modelprovider.Part{modelprovider.NewPartText(aiPrompt)}))
	if faq != "" {
		result = append(result, modelprovider.MakeSystemMsg([]modelprovider.Part{modelprovider.NewPartText(fmt.Sprintf(faqPrompt, faq))}))
	}
	return result
}
