package bootstrap

import (
	"log/slog"
	"net/http"
	"strings"
	"time"

	"cs-agent/internal/ai/mcps"
	_ "cs-agent/internal/ai/runtime"
	"cs-agent/internal/controllers/api"
	"cs-agent/internal/controllers/dashboard"
	"cs-agent/internal/controllers/third"
	"cs-agent/internal/middleware"
	"cs-agent/internal/pkg/config"
	"cs-agent/internal/services"

	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/middleware/cors"
	"github.com/kataras/iris/v12/middleware/recover"
	"github.com/kataras/iris/v12/mvc"

	_ "cs-agent/internal/services/wx_callback_handlers"
)

func NewServer() (*iris.Application, error) {
	cfg := config.Current()
	app := iris.New()
	corsHandler := cors.New().
		AllowOrigin("*").
		AllowHeaders("Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With", "X-Guest-Id", "X-Channel-Id", "X-External-Id", "X-External-Name", "X-Customer-Session-Token", "X-Customer-Session-Expires-At").
		MaxAge(600).
		ExposeHeaders("Content-Length", "Content-Type", "Authorization", "X-Guest-Id", "X-Channel-Id", "X-External-Id", "X-External-Name", "X-Customer-Session-Token", "X-Customer-Session-Expires-At").
		Handler()
	app.UseRouter(func(ctx iris.Context) {
		// WebSocket upgrade is validated by the upgrader's origin policy.
		if isWebsocketUpgrade(ctx) {
			ctx.Next()
			return
		}
		corsHandler(ctx)
	})
	app.UseRouter(recover.New())
	app.UseRouter(func(ctx iris.Context) {
		start := time.Now()
		path := ctx.Path()
		method := ctx.Method()
		ctx.Next()

		slog.Info("http request",
			"method", method,
			"path", path,
			"status", ctx.GetStatusCode(),
			"elapsed", time.Since(start).Milliseconds(),
			"clientIp", ctx.RemoteAddr(),
		)
	})
	app.UseRouter(func(ctx iris.Context) {
		ctx.SetMaxRequestBodySize(cfg.Storage.MaxRequestBodySizeBytes())
		ctx.Next()
	})

	// 注册路由
	addRouter(app)

	// 注册本地存储静态资源服务
	app.HandleDir(cfg.Storage.Local.BaseURL, iris.Dir(cfg.Storage.Local.Root), iris.DirOptions{
		ShowList: false,
	})

	// 注册dashboard静态资源服务
	app.HandleDir("/", iris.Dir("web/out"), iris.DirOptions{
		IndexName: "index.html",
		Compress:  true,
		ShowList:  false,
	})

	return app, nil
}

func isWebsocketUpgrade(ctx iris.Context) bool {
	if !strings.EqualFold(ctx.GetHeader("Upgrade"), "websocket") {
		return false
	}
	return strings.Contains(strings.ToLower(ctx.GetHeader("Connection")), "upgrade")
}

func addRouter(app *iris.Application) {
	mcpHandler := mcps.NewHTTPHandler()

	app.Any("/api/mcp", iris.FromStd(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		mcpHandler.ServeHTTP(w, r)
	})))

	mvc.Configure(app.Party("/api"), func(m *mvc.Application) {
		m.Party("/auth").Handle(new(api.AuthController))
		m.Party("/channel").Handle(new(api.ChannelController))
		m.Party("/customer").Handle(new(api.CustomerController))
		m.Party("/conversation", middleware.ExternalUserMiddleware).Handle(new(api.ConversationController))
		m.Party("/message", middleware.ExternalUserMiddleware).Handle(new(api.MessageController))
	})

	mvc.Configure(app.Party("/api/ws"), func(m *mvc.Application) {
		m.Router.Get("/dashboard", middleware.AuthMiddleware, services.WsService.HandleDashboardWS)
		m.Router.Get("/dashboard/notification", middleware.AuthMiddleware, services.WsService.HandleDashboardNotificationWS)
		m.Router.Get("/open", services.WsService.HandleOpenWS)
	})

	mvc.Configure(app.Party("/api/dashboard", middleware.AuthMiddleware), func(m *mvc.Application) {
		m.Party("/dashboard").Handle(new(dashboard.DashboardController))
		m.Party("/user").Handle(new(dashboard.UserController))
		m.Party("/company").Handle(new(dashboard.CompanyController))
		m.Party("/customer").Handle(new(dashboard.CustomerController))
		m.Party("/customer-contact").Handle(new(dashboard.CustomerContactController))
		m.Party("/role").Handle(new(dashboard.RoleController))
		m.Party("/permission").Handle(new(dashboard.PermissionController))
		m.Party("/session").Handle(new(dashboard.SessionController))
		m.Party("/tag").Handle(new(dashboard.TagController))
		m.Party("/conversation").Handle(new(dashboard.ConversationController))
		m.Party("/ticket").Handle(new(dashboard.TicketController))
		m.Party("/notification").Handle(new(dashboard.NotificationController))
		m.Party("/quick-reply").Handle(new(dashboard.QuickReplyController))
		m.Party("/channel").Handle(new(dashboard.ChannelController))
		m.Party("/agent").Handle(new(dashboard.AgentController))
		m.Party("/agent-team").Handle(new(dashboard.AgentTeamController))
		m.Party("/agent-team-schedule").Handle(new(dashboard.AgentTeamScheduleController))
		m.Party("/ai-agent").Handle(new(dashboard.AIAgentController))
		m.Party("/ai-config").Handle(new(dashboard.AIConfigController))
		m.Party("/asset").Handle(new(dashboard.AssetController))
		m.Party("/knowledge-base").Handle(new(dashboard.KnowledgeBaseController))
		m.Party("/knowledge-document").Handle(new(dashboard.KnowledgeDocumentController))
		m.Party("/knowledge-faq").Handle(new(dashboard.KnowledgeFAQController))
		m.Party("/knowledge-retrieve").Handle(new(dashboard.KnowledgeRetrieveController))
		m.Party("/knowledge-retrieve-log").Handle(new(dashboard.KnowledgeRetrieveLogController))
		m.Party("/agent-run-log").Handle(new(dashboard.AgentRunLogController))
		m.Party("/skill-definition").Handle(new(dashboard.SkillDefinitionController))
		m.Party("/mcp").Handle(new(dashboard.MCPController))
	})

	mvc.Configure(app.Party("/api/third"), func(m *mvc.Application) {
		m.Party("/wechat").Handle(new(third.WechatController))
	})
}
