package router

import (
	errorcode "ai_scheduler/internal/data/error"
	errors "ai_scheduler/internal/data/error"
	"ai_scheduler/internal/gateway"
	"ai_scheduler/internal/services"
	"ai_scheduler/internal/services/advice"
	"encoding/json"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/websocket/v2"
)

// SetupRoutes 设置路由
func SetupRoutes(app *fiber.App, ChatService *services.ChatService, sessionService *services.SessionService, task *services.TaskService,
	gateway *gateway.Gateway, callbackService *services.CallbackService, chatHist *services.HistoryService,
	capabilityService *services.CapabilityService, adviceFile *advice.FileService, adviceData *advice.AdvicerService,
	adviceChat *advice.ChatService, adviceProject *advice.ProjectService, adviceTalkSkill *advice.TalkSkillService, adviceClient *advice.ClientService,
) {
	app.Use(func(c *fiber.Ctx) error {
		// 设置 CORS 头
		c.Set("Access-Control-Allow-Origin", "*")
		c.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

		// AI能力调用路由，设置不同的 CORS 头
		if strings.HasPrefix(c.Path(), "/api/v1/capability") {
			c.Set("Access-Control-Allow-Headers", "Content-Type, X-Source-Key, X-Timestamp")
		}

		// 如果是预检请求（OPTIONS），直接返回 204
		if c.Method() == "OPTIONS" {
			return c.SendStatus(fiber.StatusNoContent) // 204
		}

		// 继续处理后续中间件或路由
		return c.Next()
	})
	//socket
	routerSocket(app, ChatService)

	r := app.Group("api/v1/")
	registerResponse(r)
	r.Get("/health", func(c *fiber.Ctx) error {
		c.Response().SetBody([]byte("1"))
		return nil
	})
	r.Post("/session/new", sessionService.NewSession)
	r.Post("/session/init", sessionService.SessionInit) // 会话初始化,不存在则创建,存在则返回会话ID和默认条数会话历史
	r.Post("/session/list", sessionService.SessionList)
	r.Post("/session/delete", sessionService.DeleteSession) // 删除会话
	r.Post("/session/rename", sessionService.RenameSession) // 会话重命名

	r.Post("/sys/tasks", task.Tasks)
	// 评价
	r.Post("/chat/useful/list", ChatService.UsefulList)
	r.Post("/chat/useful", ChatService.Useful)
	// 回调
	r.Post("/callback", callbackService.Callback)
	// 钉钉机器人回调
	r.Post("/callback/dingtalk-robot", callbackService.CallbackDingtalkRobot)
	// 钉钉卡片回调
	r.Post("/callback/dingtalk-card", callbackService.CallbackDingtalkCard)
	// 企业微信回调
	r.Get("/qywx/callback", callbackService.QywxCallback)
	//广播
	r.Get("/broadcast", func(ctx *fiber.Ctx) error {
		action := ctx.Query("action")
		uid := ctx.Query("uid")
		msg := ctx.Query("msg")

		switch action {
		case "sendToAll":
			gateway.SendToAll([]byte(msg))
			return ctx.SendString("sent to all")
		case "sendToUid":
			if uid == "" {
				return ctx.Status(400).SendString("missing uid")
			}
			gateway.SendToUid(uid, []byte(msg))
			return ctx.SendString(fmt.Sprintf("sent to uid %s", uid))
		default:
			return ctx.Status(400).SendString("unknown action")
		}
	})

	// 会话历史
	r.Post("/chat/history/list", chatHist.List)
	r.Post("/chat/history/update/content", chatHist.UpdateContent)

	// 能力
	r.Post("/capability/product/ingest", capabilityService.ProductIngest)                           // 商品数据提取
	r.Post("/capability/product/ingest/:thread_id/confirm", capabilityService.ProductIngestConfirm) // 商品数据提取确认

	advicer := r.Group("advice/")
	advicer.Post("file/word/ana", adviceFile.WordAna)
	//顾问
	advicer.Post("advicer/add", adviceData.AdvicerUpdate)
	advicer.Post("advicer/update", adviceData.AdvicerUpdate)
	advicer.Post("advicer/list", adviceData.AdvicerList)
	advicer.Post("advicer/version/add", adviceData.AdvicerVersionAdd)
	advicer.Post("advicer/version/update", adviceData.AdvicerVersionUpdate)
	advicer.Post("advicer/version/del", adviceData.AdvicerVersionDel)
	advicer.Post("advicer/version/list", adviceData.AdvicerVersionList)
	//聊天技巧
	advicer.Post("skill/list", adviceTalkSkill.TalkSkillList)
	advicer.Post("skill/add", adviceTalkSkill.TalkSkillAdd)
	advicer.Post("skill/update", adviceTalkSkill.TalkSkillUpdate)
	advicer.Post("skill/del", adviceTalkSkill.TalkSkillDel)

	//项目
	advicer.Post("project/base/init", adviceProject.BaseInit)
	advicer.Post("project/base/update", adviceProject.BaseUpdate)
	advicer.Post("project/info/add", adviceProject.Add)
	advicer.Post("project/info/update", adviceProject.Update)
	advicer.Post("project/info", adviceProject.Info)

	//客户
	advicer.Post("client/add", adviceClient.Add)
	advicer.Post("client/update", adviceClient.Update)
	advicer.Post("client/list", adviceClient.List)
	advicer.Post("client/del", adviceClient.Del)

	//会话
	advicer.Post("chat/regis", adviceChat.Regis)
	advicer.Post("chat/chat", adviceChat.Chat)

}

func routerSocket(app *fiber.App, chatService *services.ChatService) {
	ws := app.Group("ws/v1/")
	// WebSocket 路由配置
	ws.Get("/chat", websocket.New(chatService.Chat, websocket.Config{
		// 可选配置：跨域检查、最大负载大小等
		HandshakeTimeout: 10 * time.Second,
		//Subprotocols: []string{"json", "msgpack"},
		//Origins: []string{"http://localhost:3000", "https://yourdomain.com"} //验证 Origin 头，防止跨站请求伪造（CSRF）。如果为空，则允许所有来源。
		ReadBufferSize:  8192,
		WriteBufferSize: 8192,
		WriteBufferPool: bufferPool, // 使用缓冲池
	}))
}

var bufferPool = &sync.Pool{
	New: func() interface{} {
		return make([]byte, 4096) // 4KB 缓冲区
	},
}

func registerResponse(router fiber.Router) {
	// 自定义返回
	router.Use(func(c *fiber.Ctx) error {
		err := c.Next()
		return registerCommon(c, err)
	})

}

func registerCommon(c *fiber.Ctx, err error) error {
	// 调用下一个中间件或路由处理函数
	if c.Path() == "/api/v1/qywx/callback" {
		return nil
	}

	// 如果有错误发生
	if err != nil {
		bsErr, ok := err.(*errors.BusinessErr)
		if !ok {
			bsErr = errorcode.SysErr(err.Error())
		}
		// 返回自定义错误响应
		return c.JSON(fiber.Map{
			"message": bsErr.Error(),
			"code":    bsErr.Code(),
			"data":    nil,
		})
	}
	contentType := strings.ToLower(string(c.Response().Header.Peek("Content-Type")))
	if strings.Contains(strings.ToLower(contentType), "text/event-stream") {
		// 是 SSE 请求
		return c.SendString("这是 SSE 请求")
	}

	body := c.Response().Body()
	if c.Locals("skip_response_wrap") == true {
		return c.JSON(string(body))
	}
	var rawData json.RawMessage
	if len(body) > 0 {
		if err := json.Unmarshal(body, &rawData); err != nil {
			// 解析失败，作为字符串包装成JSON
			rawData = json.RawMessage(`"` + strings.ReplaceAll(string(body), `"`, `\"`) + `"`)
		}
	}

	// 检查是否需要跳过响应包装
	if c.Locals("skip_response_wrap") == true {
		return c.JSON(rawData)
	}

	return c.JSON(fiber.Map{
		"data":    rawData,
		"message": errors.Success.Error(),
		"code":    errors.Success.Code(),
	})
}
