package main

import (
	"fmt"
	"knowledge/modules/configloader"

	"knowledge/controllers"
	"knowledge/middlewares"
	"knowledge/modules/database"
	"knowledge/recoders"

	"github.com/kataras/iris/v12"
	"github.com/spf13/viper"
)

var (
	officeController            = new(controllers.OfficeController)
	userController              = new(controllers.UserController)
	infoController              = new(controllers.InfoController)
	personalNotebookController  = new(controllers.PersonalNotebookController)
	orgNotebookController       = new(controllers.OrgNotebookController)
	KnowledgeController         = new(controllers.KnowledgeController)
	OrgKnowledgeController      = new(controllers.OrgKnowledgeController)
	industryKnowledgeController = new(controllers.IndustryKnowledgeController)
	orgController               = new(controllers.OrgController)
	industryController          = new(controllers.IndustryController)
	chatController              = new(controllers.ChatController)
	toolboxController           = new(controllers.ToolboxController)
	userActionsController       = new(controllers.UserActionsController)
	systemInfoController        = new(controllers.SystemInfoController)
	friendAgentController       = new(controllers.FriendAgentController)
	storageController           = new(controllers.StorageController)
	mountController             = new(controllers.MountController)
)

func main() {
	app := iris.New()
	app.Configure(iris.WithConfiguration(iris.Configuration{
		// WebDAV 客户端（如 macOS Finder）对 PROPFIND 的 301 跟随不稳定。
		// 关闭路径修正的"重定向"：带尾斜杠的请求仍被修正去斜杠，但直接执行 handler 而非 301。
		DisablePathCorrectionRedirection: true,
	}))
	app.Logger().Infof("[webdav] DisablePathCorrectionRedirection=%v", app.ConfigurationReadOnly().GetDisablePathCorrectionRedirection())

	// CORS configuration to allow all origins
	// app.AllowMethods(iris.MethodOptions)
	// crs := cors.New()
	// app.UseRouter(crs.Handler())

	viperConfig := viper.New()
	viperConfig.SetConfigName("config")
	viperConfig.SetConfigType("yaml")
	viperConfig.AddConfigPath("etc/")
	dbUtil := database.New()
	middlewares.Init(dbUtil)
	err := configloader.ReadInConfig(viperConfig)
	if err != nil {
		app.Logger().Fatalf("Error reading config file: %s", err)
		return
	}
	host := viperConfig.GetString("Server.Host")
	port := viperConfig.GetString("Server.Port")
	// Serve static files from frontend directory at root route
	app.HandleDir("/", "./frontend")

	app.Get("/ping", func(ctx iris.Context) {
		ctx.JSON(iris.Map{
			"message": "pong!",
		})
	})
	app.Post("/api/internal/wechat/event", controllers.WechatEventWebhook)

	Assets := app.Party("/assets")
	{
		Assets.HandleDir("/", "./assets")
	}

	Api := app.Party("/api")
	{
		Api.Use(middlewares.AccessTokenToHeader)
		Api.Use(middlewares.SignatureToHeader)
		Api.Use(recoders.ResignRedirectURL)
		Api.Post("/login", middlewares.JsonParserMiddleware, controllers.Login)
		Api.Post("/login/phone", middlewares.JsonParserMiddleware, controllers.LoginByPhone)
		Api.Post("/register", middlewares.JsonParserMiddleware, controllers.Register)
		Api.Post("/sms/send", middlewares.JsonParserMiddleware, controllers.SendSMSCode)
		Api.Get("/auth/settings", controllers.GetAuthSettings)
		Api.Post("/auth/wechat/qrcode", controllers.CreateWechatQRCode)
		Api.Post("/auth/wechat/oauth", controllers.CreateWechatOAuth)
		Api.Post("/auth/wechat/status", middlewares.JsonParserMiddleware, controllers.GetWechatLoginStatus)
		Api.Post("/auth/wechat/bind-phone", middlewares.JsonParserMiddleware, controllers.BindWechatPhone)
		OfficeApi := Api.Party("/office")
		{
			OfficeApi.Get("/doc_viewer", func(ctx iris.Context) {
				ctx.ServeFile("./assets/htmls/doc_viewer.html")
			})
			OfficeApi.Get("/collabration", func(ctx iris.Context) {
				ctx.ServeFile("./assets/htmls/collaboration_network.html")
			})
			OfficeApi.Get("/network", func(ctx iris.Context) {
				ctx.ServeFile("./assets/htmls/network_graph.html")
			})
			// 受保护的路由放到带鉴权的子分组下，确保鉴权优先执行
			OfficeAuth := OfficeApi.Party("/", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
			OfficeAuth.Post("/get_viewer_url", middlewares.JsonParserMiddleware, officeController.GetViewerUrl)
			OfficeAuth.Post("/get_download_url", middlewares.JsonParserMiddleware, officeController.GetDownloadUrl)
		}
		NotebookApi := Api.Party("/notebook")
		{
			NotebookApi.Use(middlewares.SignatureVerifier)
			NotebookApiAuth := NotebookApi.Party("/", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
			PersonalNotebookApi := NotebookApiAuth.Party("/personal")
			{
				PersonalNotebookApi.Get("/", personalNotebookController.GetNotebookList)
				PersonalNotebookApi.Get("/content", recoders.AppendCDNToken, personalNotebookController.GetNotebookContent)
				PersonalNotebookApi.Post("/upload", personalNotebookController.UploadPic)
				PersonalNotebookApi.Post("/create", middlewares.JsonParserMiddleware, personalNotebookController.CreateNotebook)
				PersonalNotebookApi.Post("/delete", middlewares.JsonParserMiddleware, personalNotebookController.DeleteNotebook)
				PersonalNotebookApi.Post("/rename", middlewares.JsonParserMiddleware, personalNotebookController.RenameNotebook)
				PersonalNotebookApi.Post("/update", middlewares.JsonParserMiddleware, personalNotebookController.Update)
			}
			OrgNotebookApi := NotebookApiAuth.Party("/org")
			{
				OrgNotebookApi.Post("/share", middlewares.JsonParserMiddleware, orgNotebookController.ShareNotebook)
				OrgNotebookApi.Get("/shared", orgNotebookController.GetSharedNotebookList)
				OrgNotebookApi.Get("/sharedContent", recoders.AppendCDNToken, orgNotebookController.GetSharedNotebookContent)
			}
		}
		KnowledgeApi := Api.Party("/knowledge", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			KnowledgeApi.Use(middlewares.SignatureVerifier)
			SearchKnowledgeBaseApi := KnowledgeApi.Party("/search")
			{
				SearchKnowledgeBaseApi.Post("/", middlewares.JsonParserMiddleware, KnowledgeController.SearchKnowledge)
				SearchKnowledgeBaseApi.Post("/deep", middlewares.JsonParserMiddleware, KnowledgeController.DeepSearch)
				// document-level search within a single doc
				SearchKnowledgeBaseApi.Post("/document", recoders.AppendCDNToken, middlewares.JsonParserMiddleware, KnowledgeController.SearchByDocument)
				SearchKnowledgeBaseApi.Post("/unified", recoders.AppendCDNToken, middlewares.JsonParserMiddleware, KnowledgeController.UnifiedSearch)
			}
		}
		IndustryApi := Api.Party("/industry", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			IndustryApi.Use(middlewares.SignatureVerifier)
			IndustryApi.Get("/", industryController.GetIndustryInfo)
			UserIndustryApi := IndustryApi.Party("/user")
			{
				UserIndustryApi.Get("/", industryController.GetUserIndustry)
			}
			IndustryKnowledgeBaseApi := IndustryApi.Party("/knowledge")
			{

				IndustryKnowledgeBaseApi.Get("/permission", industryKnowledgeController.GetIndustryPermission)
				IndustryKnowledgeBaseApi.Post("/filelist", middlewares.JsonParserMiddleware, industryKnowledgeController.GetFileList)
				IndustryKnowledgeBaseApi.Post("/renameDoc", middlewares.JsonParserMiddleware, industryKnowledgeController.RenameDoc)
				IndustryKnowledgeBaseApi.Post("/upload", industryKnowledgeController.UploadFile)
				IndustryKnowledgeBaseApi.Post("/createFolder", middlewares.JsonParserMiddleware, industryKnowledgeController.CreateFolder)
				IndustryKnowledgeBaseApi.Post("/createLink", industryKnowledgeController.CreateLink)
				IndustryKnowledgeBaseApi.Post("/deleteLink", middlewares.JsonParserMiddleware, industryKnowledgeController.DeleteLink)
				IndustryKnowledgeBaseApi.Post("/renameFolder", middlewares.JsonParserMiddleware, industryKnowledgeController.RenameFolder)
				IndustryKnowledgeBaseApi.Post("/moveFolder", middlewares.JsonParserMiddleware, industryKnowledgeController.MoveFolder)
				IndustryKnowledgeBaseApi.Post("/moveDocumentPosition", middlewares.JsonParserMiddleware, industryKnowledgeController.MoveDocumentPosition)
				IndustryKnowledgeBaseApi.Post("/moveFolderPosition", middlewares.JsonParserMiddleware, industryKnowledgeController.MoveFolderPosition)
				IndustryKnowledgeBaseApi.Post("/deleteFile", middlewares.JsonParserMiddleware, industryKnowledgeController.DeleteFile)
				IndustryKnowledgeBaseApi.Post("/deleteFolder", middlewares.JsonParserMiddleware, industryKnowledgeController.DeleteFolder)
				IndustryKnowledgeBaseApi.Post("/parseDoc", middlewares.JsonParserMiddleware, industryKnowledgeController.ReparseDoc)
				IndustryKnowledgeBaseApi.Get("/download", middlewares.RateLimit, recoders.ResignRedirectURL, func(ctx iris.Context) {
					// 检查 header 中是否存在 EO-Client-OS
					if ctx.GetHeader("EO-Client-OS") == "" {
						// 不存在则重定向到 /download_cdn，保持所有参数
						redirectURL := ctx.Request().URL.Path + "_cdn"
						if ctx.Request().URL.RawQuery != "" {
							redirectURL += "?" + ctx.Request().URL.RawQuery
						}
						ctx.Redirect(redirectURL, iris.StatusFound)
						return
					}
					// 存在则继续调用原处理函数
					industryKnowledgeController.DownloadFile(ctx)
				})
				IndustryKnowledgeBaseApi.Get("/download_cdn", middlewares.RateLimit, recoders.ResignRedirectURL, industryKnowledgeController.DownloadFileCDN)
				QingHuiAPI := IndustryKnowledgeBaseApi.Party("/qinghui")
				{
					QingHuiAPI.Post("/download", middlewares.JsonParserMiddleware, industryKnowledgeController.DownloadQingHuiFile)
				}
			}
		}
		OrganizationApi := Api.Party("/org", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			OrganizationApi.Use(middlewares.SignatureVerifier)
			OrganizationKnowledgeBaseApi := OrganizationApi.Party("/knowledge")
			{
				OrganizationKnowledgeBaseApi.Get("/permission", OrgKnowledgeController.GetOrgPermission)
				OrganizationKnowledgeBaseApi.Post("/filelist", middlewares.JsonParserMiddleware, OrgKnowledgeController.GetFileList)
				OrganizationKnowledgeBaseApi.Post("/renameDoc", middlewares.JsonParserMiddleware, OrgKnowledgeController.RenameDoc)
				OrganizationKnowledgeBaseApi.Post("/upload", OrgKnowledgeController.UploadFile)
				OrganizationKnowledgeBaseApi.Post("/deleteFile", middlewares.JsonParserMiddleware, OrgKnowledgeController.DeleteFile)
				OrganizationKnowledgeBaseApi.Post("/createFolder", middlewares.JsonParserMiddleware, OrgKnowledgeController.CreateFolder)
				OrganizationKnowledgeBaseApi.Post("/renameFolder", middlewares.JsonParserMiddleware, OrgKnowledgeController.RenameFolder)
				OrganizationKnowledgeBaseApi.Post("/deleteFolder", middlewares.JsonParserMiddleware, OrgKnowledgeController.DeleteFolder)
				OrganizationKnowledgeBaseApi.Post("/moveFolder", middlewares.JsonParserMiddleware, OrgKnowledgeController.MoveFolder)
				OrganizationKnowledgeBaseApi.Post("/moveDocumentPosition", middlewares.JsonParserMiddleware, OrgKnowledgeController.MoveDocumentPosition)
				OrganizationKnowledgeBaseApi.Post("/moveFolderPosition", middlewares.JsonParserMiddleware, OrgKnowledgeController.MoveFolderPosition)
				OrganizationKnowledgeBaseApi.Post("/parseDoc", middlewares.JsonParserMiddleware, OrgKnowledgeController.ReparseDoc)
				OrganizationKnowledgeBaseApi.Get("/download", func(ctx iris.Context) {
					// 检查 header 中是否存在 EO-Client-OS
					if ctx.GetHeader("EO-Client-OS") == "" {

						// 不存在则重定向到 /download_cdn，保持所有参数
						redirectURL := ctx.Request().URL.Path + "_cdn"
						if ctx.Request().URL.RawQuery != "" {
							redirectURL += "?" + ctx.Request().URL.RawQuery
						}
						ctx.Redirect(redirectURL, iris.StatusFound)
						return
					}
					// 存在则继续调用原处理函数
					OrgKnowledgeController.DownloadFile(ctx)
				})
				OrganizationKnowledgeBaseApi.Get("/download_cdn", recoders.ResignRedirectURL, OrgKnowledgeController.DownloadFileCDN)
			}
			OrganizationAdminApi := OrganizationApi.Party("/admin")
			{
				OrganizationAdminSubUserApi := OrganizationAdminApi.Party("/user")
				{
					OrganizationAdminSubUserApi.Get("/", orgController.GetSubUserList)
					OrganizationAdminSubUserApi.Get("/permission", orgController.GetSubUserPermission)
					OrganizationAdminSubUserApi.Post("/permission", middlewares.JsonParserMiddleware, orgController.SetSubUserPermission)
					OrganizationAdminSubUserApi.Get("/quota", orgController.GetSubUserQuota)
					OrganizationAdminSubUserApi.Post("/new", middlewares.JsonParserMiddleware, orgController.CreateSubUser)
					OrganizationAdminSubUserApi.Post("/setAdmin", middlewares.JsonParserMiddleware, orgController.SetSubUserAdmin)
					OrganizationAdminSubUserApi.Post("/update", middlewares.JsonParserMiddleware, orgController.UpdateSubUser)
					OrganizationAdminSubUserApi.Post("/delete", middlewares.JsonParserMiddleware, orgController.DeleteSubUser)
				}
			}
		}
		ChatApi := Api.Party("/chat", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			ChatApi.Use(middlewares.SignatureVerifier)
			ChatApi.Post("/onlineSearch", middlewares.JsonParserMiddleware, chatController.OnlineSearch)
			ChatApi.Post("/onlineSearchAgent", middlewares.JsonParserMiddleware, chatController.OnlineSearchAgent)
			ChatApi.Post("/online-search/start", middlewares.JsonParserMiddleware, chatController.StartOnlineSearch)
			ChatApi.Post("/online-search/editStart", middlewares.JsonParserMiddleware, chatController.EditOnlineSearch)
			ChatApi.Post("/online-search/stop", middlewares.JsonParserMiddleware, chatController.StopOnlineSearch)
			ChatApi.Get("/online-search/status", recoders.AppendCDNToken, chatController.OnlineSearchStatus)
			ChatApi.Get("/online-search/stream", chatController.OnlineSearchStream)
			ChatApi.Get("/historyList", chatController.GetChatHistoryList)
			ChatApi.Get("/conversation", recoders.AppendCDNToken, chatController.GetChatConversation)
			ChatApi.Post("/uploadAttachment", chatController.UploadAttachment)
			ChatApi.Get("/attachment/status", chatController.AttachmentStatus)
			ChatApi.Post("/send", middlewares.JsonParserMiddleware, chatController.NewMessage)
			ChatApi.Post("/editMessage", middlewares.JsonParserMiddleware, chatController.EditMessage)
			ChatApi.Post("/getDocx", middlewares.JsonParserMiddleware, chatController.GetDocx)
			ChatApi.Post("/deleteConversation", middlewares.JsonParserMiddleware, chatController.DeleteConversation)
			ChatApi.Post("/agentic/start", middlewares.JsonParserMiddleware, chatController.StartAgentic)
			ChatApi.Post("/agentic/stop", middlewares.JsonParserMiddleware, chatController.StopAgentic)
			ChatApi.Get("/agentic/status", recoders.AppendCDNToken, chatController.AgenticStatus)
			ChatApi.Get("/agentic/stream", chatController.AgenticStream)
		}
		UserApi := Api.Party("/user", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			UserApi.Use(middlewares.SignatureVerifier)
			UserApi.Get("/space", userController.GetUserSpace)
			PersonalKnowledgeBaseApi := UserApi.Party("/personal")
			{
				PersonalKnowledgeBaseApi.Post("/filelist", middlewares.JsonParserMiddleware, KnowledgeController.GetFileList)
				PersonalKnowledgeBaseApi.Post("/renameDoc", middlewares.JsonParserMiddleware, KnowledgeController.RenameDoc)
				PersonalKnowledgeBaseApi.Post("/upload", KnowledgeController.UploadFile)
				PersonalKnowledgeBaseApi.Post("/deleteFile", middlewares.JsonParserMiddleware, KnowledgeController.DeleteFile)
				PersonalKnowledgeBaseApi.Post("/createFolder", middlewares.JsonParserMiddleware, KnowledgeController.CreateFolder)
				PersonalKnowledgeBaseApi.Post("/renameFolder", middlewares.JsonParserMiddleware, KnowledgeController.RenameFolder)
				PersonalKnowledgeBaseApi.Post("/deleteFolder", middlewares.JsonParserMiddleware, KnowledgeController.DeleteFolder)
				PersonalKnowledgeBaseApi.Post("/moveFolder", middlewares.JsonParserMiddleware, KnowledgeController.MoveFolder)
				PersonalKnowledgeBaseApi.Post("/moveDocumentPosition", middlewares.JsonParserMiddleware, KnowledgeController.MoveDocumentPosition)
				PersonalKnowledgeBaseApi.Post("/moveFolderPosition", middlewares.JsonParserMiddleware, KnowledgeController.MoveFolderPosition)
				PersonalKnowledgeBaseApi.Post("/parseDoc", middlewares.JsonParserMiddleware, KnowledgeController.ReparseDoc)
				PersonalKnowledgeBaseApi.Get("/download", func(ctx iris.Context) {
					// 检查 header 中是否存在 EO-Client-OS
					if ctx.GetHeader("EO-Client-OS") == "" {
						fmt.Println("Redirecting to CDN download")
						// 不存在则重定向到 /download_cdn，保持所有参数
						redirectURL := ctx.Request().URL.Path + "_cdn"
						if ctx.Request().URL.RawQuery != "" {
							redirectURL += "?" + ctx.Request().URL.RawQuery
						}
						ctx.Redirect(redirectURL, iris.StatusFound)
						return
					}
					// 存在则继续调用原处理函数
					KnowledgeController.DownloadFile(ctx)
				})
				PersonalKnowledgeBaseApi.Get("/download_cdn", recoders.ResignRedirectURL, KnowledgeController.DownloadFileCDN)
			}
			UserSettingApi := UserApi.Party("/setting")
			{
				UserModelSettingApi := UserSettingApi.Party("/model")
				{
					UserModelProviderSettingApi := UserModelSettingApi.Party("/provider")
					{
						UserModelProviderSettingApi.Get("/", userController.GetUserModelProviderSetting)
						UserModelProviderSettingApi.Get("/presets", infoController.GetPresetModelProviders)
						UserModelProviderSettingApi.Post("/create", middlewares.JsonParserMiddleware, userController.CreateUserModelProvider)
						UserModelProviderSettingApi.Post("/delete", middlewares.JsonParserMiddleware, userController.DeleteUserModelProvider)
						UserModelProviderSettingApi.Post("/update", middlewares.JsonParserMiddleware, userController.UpdateUserModelProvider)
					}
					UserModelConfigSettingApi := UserModelSettingApi.Party("/config")
					{
						UserModelConfigSettingApi.Get("/", userController.GetUserModelConfigSetting)
						UserModelConfigSettingApi.Get("/models", userController.GetUserModels)
						UserModelConfigSettingApi.Post("/update", middlewares.JsonParserMiddleware, userController.UpdateUserModelConfigSetting)
					}
				}
				UserAccountSettingApi := UserSettingApi.Party("/account")
				{
					UserAccountSettingApi.Get("/info", userController.GetAccountInfo)
					UserAccountSettingApi.Post("/password", middlewares.JsonParserMiddleware, userController.ChangePassword)
					UserAccountSettingApi.Post("/nickname", middlewares.JsonParserMiddleware, userController.ChangeNickname)
					UserAccountSettingApi.Post("/phone/bind", middlewares.JsonParserMiddleware, userController.BindPhone)
				}
				UserParseSettingApi := UserSettingApi.Party("/parse")
				{
					UserParseSettingApi.Get("/", mountController.GetParseSetting)
					UserParseSettingApi.Post("/update", middlewares.JsonParserMiddleware, mountController.UpdateParseSetting)
				}
			}

			MountApi := UserApi.Party("/mount")
			{
				MountApi.Post("/list", middlewares.JsonParserMiddleware, mountController.ListMounts)
				MountApi.Post("/create", middlewares.JsonParserMiddleware, mountController.CreateMount)
				MountApi.Post("/delete", middlewares.JsonParserMiddleware, mountController.DeleteMount)
				MountApi.Post("/reset_password", middlewares.JsonParserMiddleware, mountController.ResetMountPassword)
			}

			// Friend Agent: 云端实例一键初始化 / 状态 / 启停 / 删除
			FriendAgentApi := UserApi.Party("/friend-agent")
			{
				FriendAgentApi.Post("/initialize", middlewares.JsonParserMiddleware, friendAgentController.PostInitialize)
				FriendAgentApi.Get("/status", friendAgentController.GetStatus)
				FriendAgentApi.Post("/enable", middlewares.JsonParserMiddleware, friendAgentController.PostEnable)
				FriendAgentApi.Post("/delete", middlewares.JsonParserMiddleware, friendAgentController.PostDelete)
				FriendAgentApi.Get("/ws", friendAgentController.GetWS)
			}

			// User Actions: Favorites and Color Tags
			FavoritesApi := UserApi.Party("/favorites")
			{
				FavoritesApi.Post("/", middlewares.JsonParserMiddleware, userActionsController.SetFavorDoc)
				FavoritesApi.Get("/", userActionsController.GetFavorDocs) // Folder favorites
				FavoritesApi.Post("/folder", middlewares.JsonParserMiddleware, userActionsController.SetFavorFolder)
				FavoritesApi.Get("/folder", userActionsController.GetFavorFolders)
			}

			TagsApi := UserApi.Party("/tags")
			{
				// Document color tags
				TagsApi.Post("/", middlewares.JsonParserMiddleware, userActionsController.SetColorTag)
				TagsApi.Get("/", userActionsController.GetDocsByColor)
				// Folder color tags
				TagsApi.Post("/folder", middlewares.JsonParserMiddleware, userActionsController.SetFolderColorTag)
				TagsApi.Get("/folder", userActionsController.GetFoldersByColor)
			}
		}
		ToolboxApi := Api.Party("/toolbox", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			ToolboxApi.Get("/links", toolboxController.GetLinks)
			ToolboxApi.Post("/authorize", toolboxController.HandleToolsAuthorize)
			ToolboxApi.Post("/authorize_generic", toolboxController.HandleToolsAuthorizeGeneric)
		}
		// Toolbox integration route without JWT middleware (uses access_token from URL)
		Api.Get("/toolbox/tools", toolboxController.HandleToolsPage)
		Api.Get("/toolbox/tools_generic", toolboxController.HandleToolsPageGeneric)
		SystemInfoApi := Api.Party("/systemInfo", middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)
		{
			SystemInfoApi.Get("/colors", systemInfoController.GetColors)
			SystemInfoApi.Get("/version", systemInfoController.GetVersion)
			SystemInfoApi.Get("/ops-monitor", systemInfoController.GetOpsMonitor)
		}
		// StorageApi := Api.Party("/storage")
		// {
		// 	StorageApi.Post("/upload", storageController.UploadFile)
		// }
	}
	app.Post("/api/admin/files/upload", storageController.UploadFile)

	storage := app.Party("/storage")
	{
		storage.Get("/{p:path}", func(ctx iris.Context) {
			// 检查 header 中是否存在 EO-Client-OS
			if ctx.GetHeader("EO-Client-OS") == "" {
				// 不存在则重定向到 /storage_cdn，保持所有参数
				path := ctx.Params().Get("p")
				redirectURL := "/storage_cdn/" + path
				// 保留查询参数
				if ctx.Request().URL.RawQuery != "" {
					redirectURL += "?" + ctx.Request().URL.RawQuery
				}
				ctx.Redirect(redirectURL, iris.StatusFound)
				return
			}
			// 存在则继续调用原处理函数
			storageController.GetFile(ctx)
		})
	}

	storageCDN := app.Party("/storage_cdn")
	{
		storageCDN.Get("/{p:path}", storageController.GetFileCDN)
	}

	// 示例：使用签名验证的开放API
	// 注意：需要在配置文件中设置 Signature.Enabled = true 来启用签名验证
	// WebDAV 远程挂载：独立顶级路由，绕过签名/JSON 中间件；Basic Auth 在 handler 内完成。
	// WebDAV 用到 PROPFIND/MKCOL/COPY/MOVE/LOCK/UNLOCK/PROPPATCH 等方法，需逐个注册。
	davHandler := controllers.NewWebDAVHandler()
	webdavMethods := []string{"GET", "HEAD", "PUT", "DELETE", "POST", "OPTIONS", "PROPFIND", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", "PROPPATCH"}
	// 注册 WebDAV 非标准方法，确保 Iris 路由器识别（AllMethods 默认只含标准方法）
	iris.RegisterMethods(webdavMethods...)
	for _, m := range webdavMethods {
		app.Handle(m, "/dav", func(ctx iris.Context) {
			davHandler.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
		})
		app.Handle(m, "/dav/", func(ctx iris.Context) {
			davHandler.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
		})
		app.Handle(m, "/dav/{p:path}", func(ctx iris.Context) {
			davHandler.ServeHTTP(ctx.ResponseWriter(), ctx.Request())
		})
	}

	OpenApi := app.Party("/openapi")
	{
		// 仅使用签名验证的路由（不需要JWT）
		OpenApi.Use(middlewares.SignatureVerifier)

		// 这些路由只需要签名验证，适合对外开放的API
		// OpenApi.Post("/data", middlewares.JsonParserMiddleware, yourController.YourMethod)
		// OpenApi.Get("/status", yourController.GetStatus)

		// 测试路由
		OpenApi.Get("/test", controllers.TestSignatureAPI)
		OpenApi.Post("/data", middlewares.JsonParserMiddleware, controllers.TestSignatureDataAPI)
	}

	// 示例：同时使用JWT和签名验证的高安全性API
	SecureApi := app.Party("/secure")
	{
		// 先验证签名，再验证JWT
		SecureApi.Use(middlewares.SignatureVerifier)
		SecureApi.Use(middlewares.JWTVerifier, middlewares.JWTSessionMiddleware)

		// 这些路由需要双重验证，适合高安全性要求的接口
		// SecureApi.Post("/sensitive", middlewares.JsonParserMiddleware, yourController.SensitiveOperation)
	}

	// Friend connector 回连入口（P4）：不走 JWT/签名中间件，
	// 鉴权靠 X-Host-Token（FriendToken）在 HandleConnectorWS 内完成
	ConnectorApi := app.Party("/connector")
	{
		ConnectorApi.Get("/ws", func(ctx iris.Context) {
			token := ctx.GetHeader("X-Host-Token")
			friendAgentController.Bridge().HandleConnectorWS(ctx.ResponseWriter(), ctx.Request(), token)
		})
	}

	app.Run(iris.Addr(host+":"+port), iris.WithCharset("UTF-8"), iris.WithoutServerError(iris.ErrServerClosed))
	app.Logger().Infof("Server started at %s:%s", host, port)
}
