package main

import (
	"context"
	"database/sql"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/anthropic/isdp/internal/api"
	"github.com/anthropic/isdp/internal/model"
	"github.com/anthropic/isdp/internal/repo"
	"github.com/anthropic/isdp/internal/reporter"
	"github.com/anthropic/isdp/internal/service/a2a"
	"github.com/anthropic/isdp/internal/service/agent"
	"github.com/anthropic/isdp/internal/service/command"
	"github.com/anthropic/isdp/internal/service/configgen"
	"github.com/anthropic/isdp/internal/service/humantask"
	"github.com/anthropic/isdp/internal/service/im"
	"github.com/anthropic/isdp/internal/service/knowledge"
	"github.com/anthropic/isdp/internal/service/local_repo"
	"github.com/anthropic/isdp/internal/service/market"
	"github.com/anthropic/isdp/internal/service/memory"
	"github.com/anthropic/isdp/internal/service/mention"
	"github.com/anthropic/isdp/internal/service/merge"
	"github.com/anthropic/isdp/internal/service/message"
	"github.com/anthropic/isdp/internal/service/project"
	"github.com/anthropic/isdp/internal/service/rule"
	"github.com/anthropic/isdp/internal/service/sandbox"
	"github.com/anthropic/isdp/internal/service/settings"
	"github.com/anthropic/isdp/internal/service/skill"
	"github.com/anthropic/isdp/internal/service/subagent"
	"github.com/anthropic/isdp/internal/service/teampackage"
	"github.com/anthropic/isdp/internal/service/teampackagesync"
	"github.com/anthropic/isdp/internal/service/thread"
	"github.com/anthropic/isdp/internal/service/workflow"
	"github.com/anthropic/isdp/internal/service/workspace"
	"github.com/anthropic/isdp/internal/ws"
	"github.com/anthropic/isdp/pkg/config"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"

	// 导入所有插件包（触发 init() 自动注册）
	_ "github.com/anthropic/isdp/internal/service/agent/plugins/all"
)

// 版本信息（构建时通过 -ldflags 注入）
var (
	Version   = "dev"
	GitCommit = "unknown"
	BuildTime = "unknown"
)

// extractBaseVersion 从完整版本号中提取基础版本号
// 例如: "v1.1.0-20260411-191622" -> "1.1.0"
// 例如: "dev" -> "dev"
func extractBaseVersion(fullVersion string) string {
	if fullVersion == "dev" {
		return "dev"
	}
	// 去掉 v 前缀
	if len(fullVersion) > 0 && fullVersion[0] == 'v' {
		fullVersion = fullVersion[1:]
	}
	// 找到第一个 - 的位置
	for i, c := range fullVersion {
		if c == '-' {
			return fullVersion[:i]
		}
	}
	return fullVersion
}

// findConfigPath 查找配置文件路径，按优先级查找
func findConfigPath() string {
	// 1. 命令行参数 -config
	for i, arg := range os.Args {
		if arg == "-config" && i+1 < len(os.Args) {
			return os.Args[i+1]
		}
	}

	// 2. 环境变量 ISDP_CONFIG
	if envPath := os.Getenv("ISDP_CONFIG"); envPath != "" {
		return envPath
	}

	// 3. 安装后的配置路径
	installConfig := "data/configs/config.yaml"
	if _, err := os.Stat(installConfig); err == nil {
		return installConfig
	}

	// 4. 开发环境配置路径
	return "configs/config.yaml"
}

func main() {
	// 确定配置文件路径，按优先级查找
	configPath := findConfigPath()

	// 加载配置
	cfg, err := config.Load(configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load config from %s: %v\n", configPath, err)
		os.Exit(1)
	}
	fmt.Printf("Loaded config from: %s\n", configPath)

	// 初始化日志
	logger, err := initLogger(cfg.Logging.Level, cfg.Logging.Format, cfg.GetLogDir())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to init logger: %v\n", err)
		os.Exit(1)
	}

	// 设置会话日志记录器
	agent.SetSessionLogger(logger)

	// 设置 SessionRecorder（用于记录 A2A 失败/成功会话）
	agent.SetSessionRecorder(a2a.NewSessionRecorderImpl())

	// 连接数据库（数据库表结构由安装器初始化，服务启动时不执行 schema 创建）
	logger.Info("Connecting to database",
		zap.String("type", string(cfg.Database.Type)),
		zap.String("path", cfg.Database.Path))

	db, dialect, err := repo.NewDB(cfg.Database)
	if err != nil {
		logger.Fatal("Failed to connect to database", zap.Error(err))
	}
	defer db.Close()
	_ = dialect // 方言对象保留供后续使用

	logger.Info("Database connected successfully")

	// 检查数据库关键表是否存在（用于定位安装时迁移问题）
	checkDatabaseTables(db, logger)

	// 连接Redis（可选）
	var redisClient repo.RedisClient
	redisClient, err = repo.NewRedis(repo.RedisConfig{
		Addr:     cfg.Redis.Addr,
		Password: cfg.Redis.Password,
		DB:       cfg.Redis.DB,
	})
	if err != nil {
		logger.Warn("Redis not available, running without cache", zap.Error(err))
	} else {
		defer redisClient.Close()
	}

	// 初始化WebSocket Hub
	wsHub := ws.NewHub()
	go wsHub.Run()
	ws.SetWSLogger(logger) // 设置 WebSocket 日志记录器

	// 初始化调试线程管理器
	debugThreadMgr := agent.NewDebugThreadManager(wsHub)
	defer debugThreadMgr.Stop() // 优雅关闭调试线程管理器

	// 初始化Repositories
	dbType := cfg.Database.Type
	projectRepo := repo.NewProjectRepository(db, dbType)
	threadRepo := repo.NewThreadRepository(db, dbType)
	messageRepo := repo.NewMessageRepository(db, dbType)
	agentConfigRepo := repo.NewAgentConfigRepository(db, dbType)
	baseAgentRepo := repo.NewBaseAgentRepository(db, dbType)
	invocationRepo := repo.NewAgentInvocationRepository(db, dbType)
	artifactRepo := repo.NewArtifactRepository(db, dbType)
	sandboxRepo := repo.NewSandboxRepository(db, dbType)
	reviewRepo := repo.NewReviewRepository(artifactRepo)
	workflowRepo := repo.NewWorkflowTemplateRepository(db, dbType)
	teamPackageVersionRepo := repo.NewTeamPackageVersionRepository(db, dbType)
	skillRepo := repo.NewSkillRepository(db, dbType)
	agentSkillBindingRepo := repo.NewAgentSkillBindingRepository(db, dbType)
	registryRepo := repo.NewSkillRegistryRepository(db, dbType)
	knowledgeRepo := repo.NewKnowledgeBaseRepository(db, dbType)
	subagentRepo := repo.NewSubagentRepository(db, dbType)
	agentSubagentBindingRepo := repo.NewAgentSubagentBindingRepository(db, dbType)
	// Command 和 Rule 相关 Repositories
	commandRepo := repo.NewCommandRepository(db, dbType)
	ruleRepo := repo.NewRuleRepository(db, dbType)
	commandSkillBindingRepo := repo.NewCommandSkillBindingRepository(db, dbType)
	agentCommandBindingRepo := repo.NewAgentCommandBindingRepository(db, dbType)
	agentRuleBindingRepo := repo.NewAgentRuleBindingRepository(db, dbType)
	subagentSkillBindingRepo := repo.NewSubagentSkillBindingRepository(db, dbType)
	// Settings 相关 Repositories
	settingsRepo := repo.NewSettingsRepository(db, dbType)
	agentSettingsBindingRepo := repo.NewAgentSettingsBindingRepository(db, dbType)
	// 后台执行支持：内容块持久化
	contentBlockRepo := repo.NewContentBlockRepository(db, dbType)
	// HumanTask Repository
	humanTaskRepo := repo.NewHumanTaskRepository(db, dbType)
	// LocalRepo Repository
	localRepoRepo := repo.NewLocalRepoRepository(db, dbType)

	workspaceGuard, err := workspace.NewGuard(cfg.Deployment.WorkspacePath)
	if err != nil {
		logger.Fatal("Failed to initialize workspace guard", zap.Error(err))
	}

	// 初始化Services
	projectService := project.NewService(projectRepo, workflowRepo, workspaceGuard)
	localRepoService := local_repo.NewService(localRepoRepo, workspaceGuard, &cfg.GitURLConversion)
	threadService := thread.NewService(threadRepo, projectRepo, workflowRepo)
	messageService := message.NewService(messageRepo, wsHub)
	configService := agent.NewConfigService(agentConfigRepo, baseAgentRepo)
	baseAgentService := agent.NewBaseAgentService(baseAgentRepo)
	workflowEngine := agent.NewWorkflowEngine(threadRepo, messageRepo, configService)
	workflowService := workflow.NewService(workflowRepo)
	mcpAuthService := a2a.NewMCPAuthService(cfg.MCP.TokenTTL)
	invocationRegistry := a2a.NewInvocationRegistry() // 新增：调用注册表
	invocationQueue := a2a.NewInvocationQueue()       // 新增：请求队列

	// 初始化 Mention 模式注册表和解析器（支持动态 patterns 和博弈场景）
	mentionPatternRegistry := mention.NewPatternRegistry(agentConfigRepo)
	mentionParser := mention.NewParser(mentionPatternRegistry)

	// 刷新 mention patterns（从数据库加载）
	if err := mentionPatternRegistry.Refresh(context.Background()); err != nil {
		logger.Warn("Failed to refresh mention patterns", zap.Error(err))
	}

	skillService := skill.NewService(
		skillRepo, agentSkillBindingRepo, agentConfigRepo,
		subagentSkillBindingRepo, commandSkillBindingRepo,
		subagentRepo, commandRepo,
		cfg.GetSkillStoragePath(), logger,
	)
	skillScanner := skill.NewSkillScanner(registryRepo, skillRepo, agentSkillBindingRepo, agentConfigRepo, cfg.GetSkillStoragePath(), cfg.AgentConfig.DataDir, logger)
	registryService := skill.NewRegistryService(registryRepo, skillRepo, skillScanner)
	knowledgeService := knowledge.NewService(knowledgeRepo)
	configGenService := configgen.NewService(
		projectRepo, agentConfigRepo, skillRepo, agentSkillBindingRepo,
		subagentRepo, agentSubagentBindingRepo,
		commandRepo, ruleRepo,
		agentCommandBindingRepo, agentRuleBindingRepo,
		commandSkillBindingRepo, subagentSkillBindingRepo,
		settingsRepo, agentSettingsBindingRepo,
		cfg.GetSkillStoragePath(), cfg.GetSubagentStoragePath(),
		cfg.GetCommandStoragePath(), cfg.GetRuleStoragePath(),
		cfg.AgentConfig.DataDir,
		logger,
	)

	// 设置缓存失效回调：配置生成后刷新 ConfigService 缓存
	configGenService.SetCacheInvalidateCallback(func(agentRoleID uuid.UUID) {
		configService.InvalidateCache(agentRoleID)
	})

	// 创建 AutoGenerator（自动配置生成器）
	autoGenerator := configgen.NewAutoGenerator(
		configGenService,
		agentConfigRepo,
		baseAgentRepo,
		&configgen.BindingRepositories{
			SkillBindingRepo:    agentSkillBindingRepo,
			CommandBindingRepo:  agentCommandBindingRepo,
			SubagentBindingRepo: agentSubagentBindingRepo,
			RuleBindingRepo:     agentRuleBindingRepo,
			SettingsBindingRepo: agentSettingsBindingRepo,
		},
		logger,
	)

	// 创建 Subagent Service
	subagentSvc := subagent.NewService(
		subagentRepo, agentSubagentBindingRepo, subagentSkillBindingRepo,
		agentConfigRepo, skillRepo,
		cfg.GetSubagentStoragePath(),
		logger,
	)

	// 创建 Command Service
	commandSvc := command.NewService(
		commandRepo, commandSkillBindingRepo, agentCommandBindingRepo,
		agentConfigRepo, skillRepo,
		cfg.GetCommandStoragePath(),
		logger,
	)

	// 创建 Rule Service
	ruleSvc := rule.NewService(
		ruleRepo, agentRuleBindingRepo, agentConfigRepo,
		cfg.GetRuleStoragePath(),
		logger,
	)

	// 创建 Settings Service
	settingsSvc := settings.NewService(
		settingsRepo, agentSettingsBindingRepo, agentConfigRepo,
		cfg.GetSettingsStoragePath(),
		logger,
	)

	// 创建 TeamPackage Service
	teamPackageSvc := teampackage.NewService(
		workflowRepo, agentConfigRepo, baseAgentRepo,
		skillRepo, commandRepo, subagentRepo, ruleRepo, settingsRepo,
		agentSkillBindingRepo, agentCommandBindingRepo, agentSubagentBindingRepo,
		agentRuleBindingRepo, agentSettingsBindingRepo,
		commandSkillBindingRepo, subagentSkillBindingRepo,
		cfg.GetSkillStoragePath(), cfg.GetSubagentStoragePath(),
		cfg.GetCommandStoragePath(), cfg.GetRuleStoragePath(),
		cfg.GetSettingsStoragePath(),
		logger,
	)

	// 设置自动配置生成器（用于导入角色后自动生成配置）
	teamPackageSvc.SetAutoGenerator(autoGenerator)

	// 创建 HumanTask Service
	humanTaskSvc := humantask.NewService(humanTaskRepo, threadRepo, projectRepo, wsHub)

	// 初始化 MarketRepository
	marketRepo := repo.NewMarketRepository(db, dbType)

	// 初始化 MarketService
	marketSvc := market.NewService(marketRepo, teamPackageVersionRepo, cfg.Data.BasePath+"/temp", logger, &cfg.GitURLConversion)

	// 创建 TeamPackageSync Service（扩展：支持冲突检测）
	teamPackageSyncSvc := teampackagesync.NewSyncService(
		teamPackageVersionRepo, workflowRepo,
		agentConfigRepo, skillRepo, commandRepo, subagentRepo, ruleRepo, settingsRepo,
		teamPackageSvc, marketSvc,
		cfg.TeamPackageSync, cfg.Data.BasePath, logger,
		&cfg.GitURLConversion,
	)

	// 初始化 UseCountUpdater（技能使用次数统计）
	useCountUpdater := skill.NewUseCountUpdater(skillRepo, projectRepo, agentSkillBindingRepo)
	useCountUpdater.SetWorkflowService(workflowService)
	useCountUpdater.SetLogger(logger)

	// 启动技能使用次数统计定时任务
	updateInterval, err := time.ParseDuration(cfg.Skill.UseCountUpdateInterval)
	if err != nil {
		updateInterval = time.Hour // 默认 1 小时
	}
	useCountUpdater.Start(updateInterval)
	defer useCountUpdater.Stop()

	// 启动 Reporter（数据上报，如果配置启用）
	if cfg.Reporter.Enabled {
		reporterCfg := reporter.Config{
			Enabled:       cfg.Reporter.Enabled,
			Endpoint:      cfg.Reporter.Endpoint,
			Interval:      cfg.Reporter.GetInterval(),
			RetryTimes:    cfg.Reporter.RetryTimes,
			RetryInterval: cfg.Reporter.GetRetryInterval(),
		}
		usageReporter := reporter.NewReporter(db, reporterCfg, Version)
		usageReporter.SetLogger(logger)
		usageReporter.Start()
		defer usageReporter.Stop()
	}

	// 启动 MessageReporter（会话消息上报，如果配置启用）
	if cfg.MessageReporter.IsRunnable() {
		msgReporterCfg := reporter.MessageReporterConfig{
			Enabled:       cfg.MessageReporter.Enabled,
			Endpoint:      cfg.MessageReporter.Endpoint,
			Interval:      cfg.MessageReporter.GetInterval(),
			BatchSize:     cfg.MessageReporter.BatchSize,
			RetryTimes:    cfg.MessageReporter.RetryTimes,
			RetryInterval: cfg.MessageReporter.GetRetryInterval(),
		}
		msgReporter := reporter.NewMessageReporter(db, msgReporterCfg, dbType)
		msgReporter.SetLogger(logger)
		msgReporter.Start()
		defer msgReporter.Stop()
		logger.Info("MessageReporter 已启动",
			zap.String("endpoint", cfg.MessageReporter.Endpoint),
			zap.String("interval", cfg.MessageReporter.Interval))
	}

	// 启动 TeamPackageSync Checker（团队包同步检查，自动检查所有启用自动更新的市场）
	syncChecker := teampackagesync.NewSyncChecker(
		teamPackageSyncSvc,
		marketRepo,
		teamPackageVersionRepo,
		24*time.Hour, // 默认 24 小时检查间隔
		logger,
	)
	syncChecker.Start()
	defer syncChecker.Stop()

	// 初始化适配器
	// 默认适配器设为 nil，在执行时根据 AgentRoleConfig.BaseAgentID 动态创建适配器
	// 这样可以支持多种类型的 Agent（Claude、OpenCode 等）
	var defaultAdapter agent.AgentAdapter = nil
	_ = agent.NewContextBuilder(threadRepo, messageRepo, artifactRepo) // TODO: wire into orchestrator
	tracker := agent.NewInvocationTracker(invocationRepo)
	// 初始化记忆管理器（US-004 集成）
	memoryManager := memory.NewMemoryManager(agentConfigRepo)
	// 设置 API URL（用于 MCP server 回调）
	apiURL := fmt.Sprintf("http://localhost:%d", cfg.Server.Port)
	orchestrator := agent.NewOrchestrator(
		invocationRepo, threadRepo, messageRepo,
		configService, baseAgentService, baseAgentRepo, tracker, workflowEngine, workflowRepo, projectRepo, wsHub, defaultAdapter, mentionParser,
		contentBlockRepo,
		humanTaskSvc,
		cfg.HumanTask.Enabled,
		memoryManager,
	)

	// 在Orchestrator中设置调试管理器
	orchestrator.SetDebugThreadManager(debugThreadMgr)
	// 设置 API URL 到 executionService（用于 MCP server 回调）
	orchestrator.SetExecutionServiceAPIURL(apiURL)
	logger.Info("MemoryManager initialized and injected into Orchestrator", zap.String("apiURL", apiURL))

	// 初始化 SessionManager（统一管理 ACP 原生 session/resume）
	// 支持：
	// 1. Claude CLI: 使用原生 resume，持久化 session ID
	// 2. OpenCode/CodeAgent: 使用 ACP 原生 session/resume
	sessionRecordRepo := repo.NewSessionRecordRepository(db)
	sessionManager := agent.NewSessionManager(sessionRecordRepo, agent.SessionManagerConfig{
		ResumeExpiry:     168,  // 7 天
		CleanupInterval:  30,   // 30 分钟
	})
	// 将 SessionManager 注入到 ExecutionService
	orchestrator.SetSessionManager(sessionManager)
	logger.Info("SessionManager initialized and injected into Orchestrator")

	// 设置 MCP server 路径（用于 Agent 记忆工具调用）
	// 开发模式：bin/mcp-server.exe（相对于项目根目录）
	// 安装模式：packages/runtime/tools/mcp-server.exe（相对于安装目录）
	mcpServerPath := ""
	if os.Getenv("ISDP_MCP_SERVER_PATH") == "" {
		workDir, err := os.Getwd()
		if err == nil {
			// 优先检查安装模式路径
			installedPath := filepath.Join(workDir, "packages", "runtime", "tools", "mcp-server.exe")
			if _, err := os.Stat(installedPath); err == nil {
				mcpServerPath = installedPath
			} else {
				// 回退到开发模式路径
				devPath := filepath.Join(workDir, "bin", "mcp-server.exe")
				if _, err := os.Stat(devPath); err == nil {
					mcpServerPath = devPath
				}
			}
		}
		if mcpServerPath != "" {
			os.Setenv("ISDP_MCP_SERVER_PATH", mcpServerPath)
			logger.Info("MCP server path set", zap.String("path", mcpServerPath))
		} else {
			logger.Warn("MCP server not found, agents may fail to use memory tools")
		}
	}

	// 启动恢复：检测并标记孤儿 invocation（后台执行支持）
	startupReconciler := agent.NewStartupReconciler(invocationRepo, contentBlockRepo)
	startupReconciler.Reconcile(context.Background())

	// 连接Message服务和Agent编排器（用户消息触发Agent）
	messageService.SetAgentSpawner(orchestrator)

	// 创建队列处理器（在 orchestrator 创建之后）
	queueProcessor := a2a.NewQueueProcessor(a2a.QueueProcessorDeps{
		Queue:    invocationQueue,
		Registry: invocationRegistry,
		WSHub:    wsHub,
		SpawnAgent: func(ctx context.Context, threadID uuid.UUID, catID string, content string) error {
			// 通过 Orchestrator 触发 Agent
			req := &agent.SpawnRequest{
				ThreadID: threadID,
				Role:     getRoleFromCatID(catID),
				Input:    content,
			}
			_, err := orchestrator.SpawnAgent(ctx, req)
			return err
		},
	})
	_ = queueProcessor // TODO: wire into orchestrator completion hooks

	gatekeeper := merge.NewGatekeeper(reviewRepo, artifactRepo, threadRepo)

	// 初始化Docker客户端（可选）
	var sandboxService *sandbox.SandboxService
	dockerClient, err := sandbox.NewDockerClient()
	if err != nil {
		logger.Warn("Docker not available, sandbox features disabled", zap.Error(err))
	} else {
		sandboxService = sandbox.NewSandboxService(dockerClient, sandboxRepo)
		_ = sandboxService // TODO: wire into sandbox handler
	}

	// ========== IM Integration ==========
	// Merge im.platforms feishu config into legacy cfg.Feishu if present
	for _, p := range cfg.IM.Platforms {
		if p.Type == "feishu" && p.Enabled {
			cfg.Feishu.Enabled = true
			cfg.Feishu.AppID = p.AppID
			cfg.Feishu.AppSecret = p.AppSecret
			cfg.Feishu.VerificationToken = p.VerificationToken
			cfg.Feishu.EncryptKey = p.EncryptKey
			cfg.Feishu.LarkCLIPath = p.LarkCLIPath
			cfg.Feishu.DefaultProjectID = p.DefaultProjectID
			cfg.Feishu.EventMode = p.EventMode
			break
		}
	}

	var imBridgeSvc *im.IMBridgeService
	var eventListener *im.EventListener
	if cfg.Feishu.Enabled {
		imSessionRepo := repo.NewIMSessionRepository(db)
		larkClient := im.NewLarkCLIClient(cfg.Feishu.LarkCLIPath, logger)
		feishuAdapter := im.NewFeishuAdapter(larkClient, logger)
		if err := feishuAdapter.CheckHealth(context.Background()); err != nil {
			logger.Warn("Feishu adapter health check failed", zap.Error(err))
		}
		rateLimiter := im.NewRateLimiter(20, 60*time.Second)
		dedupCache := im.NewDedupCache(1000)
		feishuDelivery := im.NewDeliveryService(feishuAdapter, im.DefaultRetryConfig(), rateLimiter, dedupCache, logger)
		imBridgeSvc = im.NewIMBridgeService(imSessionRepo, threadRepo, projectRepo, orchestrator, wsHub, nil, logger)
		imBridgeSvc.RegisterAdapter(feishuAdapter, feishuDelivery)
		orchestrator.GetExecutionService().AddChunkListener(imBridgeSvc.OnAgentChunk)

		eventMode := cfg.Feishu.EventMode
		if eventMode == "" {
			eventMode = config.EventModeListener
		}

		switch eventMode {
		case config.EventModeListener:
			eventListener = im.NewEventListener(cfg.Feishu.LarkCLIPath, imBridgeSvc, logger)
			if err := eventListener.Start(context.Background()); err != nil {
				logger.Error("Failed to start IM event listener, falling back to webhook mode", zap.Error(err))
				eventListener = nil
			}
		case config.EventModeWebhook:
			logger.Info("IM event mode: webhook (requires public URL)")
		default:
			logger.Warn("Unknown event_mode, defaulting to listener", zap.String("event_mode", eventMode))
			eventListener = im.NewEventListener(cfg.Feishu.LarkCLIPath, imBridgeSvc, logger)
			if err := eventListener.Start(context.Background()); err != nil {
				logger.Error("Failed to start IM event listener", zap.Error(err))
				eventListener = nil
			}
		}
		logger.Info("IM integration enabled", zap.String("platform", "feishu"), zap.String("event_mode", eventMode))
	}

	// 设置Gin模式
	gin.SetMode(cfg.Server.Mode)

	// 创建路由
	router := gin.New()
	router.Use(gin.Recovery())
	router.Use(corsMiddleware())
	router.Use(requestLogger(logger))

	// 健康检查
	router.GET("/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status":    "ok",
			"version":   Version,
			"gitCommit": GitCommit,
			"buildTime": BuildTime,
			"time":      time.Now().Format(time.RFC3339),
		})
	})

	// 版本信息 API（供前端动态获取，避免浏览器缓存问题）
	router.GET("/api/v1/system/version", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"version":     Version,
			"baseVersion": extractBaseVersion(Version),
		})
	})

	router.GET("/ready", func(c *gin.Context) {
		if err := db.Ping(); err != nil {
			c.JSON(http.StatusServiceUnavailable, gin.H{"status": "not ready", "error": "database"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"status": "ready"})
	})

	// API路由组
	v1 := router.Group("/api/v1")

	// 注册Handlers
	projectHandler := api.NewProjectHandler(projectService)
	projectHandler.RegisterRoutes(v1)

	localRepoHandler := api.NewLocalRepoHandler(localRepoService)
	localRepoHandler.RegisterRoutes(v1)

	// Dashboard Handler（首页统计）
	dashboardHandler := api.NewDashboardHandler(db)
	dashboardHandler.RegisterRoutes(v1)

	// 先注册 invocationHandler（包含 /threads/:id/invocations）
	invocationHandler := api.NewInvocationHandler(orchestrator, mcpAuthService, projectRepo)
	invocationHandler.RegisterRoutes(v1)

	// Artifact Handler（包含 /threads/:id/artifacts）
	artifactHandler := api.NewArtifactHandler(artifactRepo)
	artifactHandler.RegisterRoutes(v1)

	// Merge Handler（包含 /threads/:id/merge/*）
	mergeHandler := api.NewMergeHandler(gatekeeper)
	mergeHandler.RegisterRoutes(v1)

	// 再注册 threadHandler（包含 /threads/:id）
	threadHandler := api.NewThreadHandler(threadService)
	threadHandler.RegisterRoutes(v1)

	messageHandler := api.NewMessageHandler(messageService)
	messageHandler.RegisterRoutes(v1)

	agentHandler := api.NewAgentHandler(configService, baseAgentService, orchestrator, threadRepo, debugThreadMgr, workflowRepo, configGenService, autoGenerator,
		agentSkillBindingRepo, agentSubagentBindingRepo, agentCommandBindingRepo, agentRuleBindingRepo, agentSettingsBindingRepo)
	// configGenHandler 必须在 agentHandler 前注册，否则 /agents/:id/config/* 路由会被 /agents/:id 捕获
	configGenHandler := api.NewConfigGenHandler(configGenService, autoGenerator, agentConfigRepo, baseAgentRepo)
	configGenHandler.RegisterRoutes(v1)
	agentHandler.RegisterRoutes(v1)

	// 基础Agent Handler
	baseAgentHandler := api.NewBaseAgentHandler(baseAgentService)
	baseAgentHandler.RegisterRoutes(v1)

	// 工作流模板 Handler
	workflowHandler := api.NewWorkflowHandler(workflowService)
	workflowHandler.RegisterRoutes(v1)

	// Skill Handler
	skillHandler := api.NewSkillHandler(skillService, skillScanner, cfg.GetSkillStoragePath(), cfg.Skill.GetUploadMaxSize(), autoGenerator, &cfg.GitURLConversion)
	skillHandler.RegisterRoutes(v1)

	// Registry Handler
	registryHandler := api.NewRegistryHandler(registryService)
	registryHandler.RegisterRoutes(v1)

	// Knowledge Handler
	knowledgeHandler := api.NewKnowledgeHandler(knowledgeService)
	knowledgeHandler.RegisterRoutes(v1)

	memoryHandler := api.NewMemoryHandler(memoryManager)
	memoryHandler.RegisterRoutes(v1)

	// Subagent Handler
	subagentHandler := api.NewSubagentHandler(subagentSvc, cfg.GetSubagentStoragePath(), cfg.Subagent.GetUploadMaxSize(), autoGenerator, agentConfigRepo)
	subagentHandler.RegisterRoutes(v1)

	// Command Handler
	commandHandler := api.NewCommandHandler(commandSvc, cfg.GetCommandStoragePath(), cfg.Command.GetUploadMaxSize(), autoGenerator, agentConfigRepo)
	commandHandler.RegisterRoutes(v1)

	// Rule Handler
	ruleHandler := api.NewRuleHandler(ruleSvc, cfg.GetRuleStoragePath(), cfg.Rule.GetUploadMaxSize(), autoGenerator, agentConfigRepo)
	ruleHandler.RegisterRoutes(v1)

	// Settings Handler
	settingsHandler := api.NewSettingsHandler(settingsSvc, cfg.GetSettingsStoragePath(), autoGenerator, agentConfigRepo)
	settingsHandler.RegisterRoutes(v1)

	// TeamPackage Handler
	teamPackageHandler := api.NewTeamPackageHandler(teamPackageSvc)
	teamPackageHandler.RegisterRoutes(v1)

	// TeamPackageSync Handler
	teamPackageSyncHandler := api.NewTeamPackageSyncHandler(teamPackageSyncSvc, logger)
	teamPackageSyncHandler.RegisterRoutes(v1)

	// Market Handler
	marketHandler := api.NewMarketHandler(marketSvc, cfg, logger)
	marketHandler.RegisterRoutes(v1)

	// Help Handler
	helpHandler := api.NewHelpHandler(
		cfg.Help.SupportGroup,
		cfg.Help.OfficialWebsite,
		cfg.Help.DocLink,
		cfg.Help.FeedbackAPI,
	)
	helpHandler.RegisterRoutes(v1)

	runtimeConfigHandler := api.NewRuntimeConfigHandler(cfg)
	runtimeConfigHandler.RegisterRoutes(v1)

	// MCP Callback Handler - 注册在 /api 下（不含 /v1），与 MCP client URL 一致
	callbackHandler := api.NewCallbackHandler(invocationRegistry, mcpAuthService, messageService, messageRepo, wsHub, orchestrator, baseAgentRepo, invocationQueue, queueProcessor, mentionParser, humanTaskSvc, agentConfigRepo, invocationRepo, projectRepo, threadRepo, workflowRepo, memoryManager)
	callbackHandler.RegisterRoutes(router.Group("/api"))

	// WebSocket
	wsHandler := ws.NewHandler(wsHub, orchestrator, orchestrator)
	wsHandler.SetCancelAgentFunc(orchestrator.CancelAgent)
	wsHandler.RegisterRoutes(v1)

	// 飞书 Webhook Handler (仅 webhook 模式)
	if imBridgeSvc != nil && eventListener == nil {
		feishuHandler := api.NewFeishuWebhookHandler(imBridgeSvc, cfg.Feishu.VerificationToken)
		feishuHandler.RegisterRoutes(v1)
	}

	// 沙箱 Handler (如果可用)
	if sandboxService != nil {
		sandboxHandler := api.NewSandboxHandler(sandboxService)
		sandboxHandler.RegisterRoutes(v1)
	}

	// HumanTask Handler
	humanTaskHandler := api.NewHumanTaskHandler(humanTaskSvc)
	humanTaskHandler.RegisterRoutes(v1)

	// 前端静态文件服务
	// 支持三种部署方式：
	// 1. 开发环境：./web/dist/ (项目根目录启动)
	// 2. 安装环境：./web/ (安装器复制到顶层)
	// 3. 桌面应用开发：./resources/web/ (packages/desktop 目录启动)
	webPaths := []string{
		"./web/dist",      // 开发环境（从项目根目录启动）
		"./web",           // 安装环境（安装器复制到顶层）
		"./resources/web", // 桌面应用开发（从 packages/desktop 启动）
	}

	var webDir string
	for _, path := range webPaths {
		if _, err := os.Stat(filepath.Join(path, "index.html")); err == nil {
			webDir = path
			logger.Info("Found web directory", zap.String("path", webDir))
			break
		}
	}

	if webDir == "" {
		logger.Warn("Web directory not found, using default")
		webDir = "./web/dist"
	}

	router.Static("/assets", filepath.Join(webDir, "assets"))
	router.StaticFile("/favicon.svg", filepath.Join(webDir, "favicon.svg"))
	router.StaticFile("/favicon.ico", filepath.Join(webDir, "favicon.ico"))

	// SPA fallback - 所有未匹配的路由返回 index.html
	router.NoRoute(func(c *gin.Context) {
		c.File(filepath.Join(webDir, "index.html"))
	})

	// 启动服务器
	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", cfg.Server.Port),
		Handler: router,
	}

	// 启动定期日志维护任务
	go func() {
		ticker := time.NewTicker(24 * time.Hour) // 每24小时检查一次
		defer ticker.Stop()

		// 立即执行一次日志维护
		performLogMaintenance(logger, cfg.GetLogDir())

		for {
			select {
			case <-ticker.C:
				// 定期执行日志维护
				performLogMaintenance(logger, cfg.GetLogDir())
			}
		}
	}()

	// 优雅关闭
	go func() {
		logger.Info("Starting server", zap.Int("port", cfg.Server.Port))
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatal("Failed to start server", zap.Error(err))
		}
	}()

	// 等待中断信号
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	logger.Info("Shutting down server...")

	// 优雅关闭 SessionManager（封存所有活跃 session）
	if sessionManager != nil {
		logger.Info("SessionManager: initiating graceful shutdown")
		if err := sessionManager.Shutdown(); err != nil {
			logger.Error("SessionManager: shutdown error", zap.Error(err))
		} else {
			logger.Info("SessionManager: shutdown completed")
		}
	}

	if eventListener != nil {
		eventListener.Stop()
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		logger.Fatal("Server forced to shutdown", zap.Error(err))
	}

	logger.Info("Server exited")
}

func initLogger(level, format, logDir string) (*zap.Logger, error) {
	// 确保日志目录存在
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return nil, fmt.Errorf("failed to create log directory: %w", err)
	}

	// 配置 lumberjack 用于日志轮转
	logFile := &lumberjack.Logger{
		Filename:   filepath.Join(logDir, "server.log"),
		MaxSize:    1,     // MB，单个文件最大大小
		MaxBackups: 10,    // 保留的旧日志文件数量
		MaxAge:     30,    // 天，保留天数
		Compress:   false, // 不压缩旧日志文件
	}

	// 解析日志级别
	var zapLevel zapcore.Level
	switch level {
	case "debug":
		zapLevel = zapcore.DebugLevel
	case "info":
		zapLevel = zapcore.InfoLevel
	case "warn":
		zapLevel = zapcore.WarnLevel
	case "error":
		zapLevel = zapcore.ErrorLevel
	default:
		zapLevel = zapcore.InfoLevel
	}

	// 配置编码器
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
	}
	encoderConfig.EncodeLevel = func(level zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
		// 输出 [INFO] [goroutineID]
		gid := getGoroutineID()
		enc.AppendString("[" + level.CapitalString() + "] [" + strconv.FormatUint(gid, 10) + "]")
	}
	encoderConfig.EncodeCaller = func(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) {
		enc.AppendString("[" + caller.TrimmedPath() + "]")
	}
	encoderConfig.ConsoleSeparator = " " // 1个空格分隔各部分

	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	// 创建多输出：同时输出到文件和控制台
	fileWriter := zapcore.AddSync(logFile)
	consoleWriter := zapcore.AddSync(os.Stdout)

	core := zapcore.NewTee(
		zapcore.NewCore(encoder, fileWriter, zapLevel),
		zapcore.NewCore(zapcore.NewConsoleEncoder(encoderConfig), consoleWriter, zapLevel),
	)

	logger := zap.New(core, zap.AddCaller())

	// 设置全局 logger，使得 zap.L() 能返回此 logger
	zap.ReplaceGlobals(logger)

	return logger, nil
}

// getGoroutineID 获取当前 goroutine ID
func getGoroutineID() uint64 {
	var buf [64]byte
	n := runtime.Stack(buf[:], false)
	// 解析 goroutine ID，格式: "goroutine X [running]:"
	idField := strings.Fields(string(buf[:n]))[1]
	id, _ := strconv.ParseUint(idField, 10, 64)
	return id
}

func corsMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	}
}

// requestLogger 请求日志中间件
func requestLogger(logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery

		c.Next()

		latency := time.Since(start)
		status := c.Writer.Status()

		if status >= 400 {
			logger.Error("HTTP Request",
				zap.String("method", c.Request.Method),
				zap.String("path", path),
				zap.String("query", query),
				zap.Int("status", status),
				zap.Duration("latency", latency),
				zap.String("client_ip", c.ClientIP()),
			)
		} else {
			logger.Info("HTTP Request",
				zap.String("method", c.Request.Method),
				zap.String("path", path),
				zap.String("query", query),
				zap.Int("status", status),
				zap.Duration("latency", latency),
				zap.String("client_ip", c.ClientIP()),
			)
		}
	}
}

// performLogMaintenance 执行日志维护任务
func performLogMaintenance(logger *zap.Logger, logDir string) {
	// 检查日志目录是否存在
	if _, err := os.Stat(logDir); os.IsNotExist(err) {
		return
	}

	// 获取日志目录中的所有文件
	files, err := os.ReadDir(logDir)
	if err != nil {
		logger.Error("Failed to read log directory", zap.Error(err))
		return
	}

	cleanedCount := 0
	totalSize := int64(0)

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		info, err := file.Info()
		if err != nil {
			continue
		}

		// 计算文件大小
		totalSize += info.Size()

		// 删除超过30天的日志文件
		if time.Since(info.ModTime()).Hours() > 720 { // 30天 = 30 * 24小时
			filePath := filepath.Join(logDir, file.Name())
			if err := os.Remove(filePath); err == nil {
				logger.Info("Deleted old log file", zap.String("file", filePath))
				cleanedCount++
			}
		}
	}

	logger.Info("Log maintenance completed",
		zap.Int("files_cleaned", cleanedCount),
		zap.Int64("total_size_bytes", totalSize))
}

// getRoleFromCatID 从 catID 获取 AgentRole
// catID 就是 role（如 "backend_developer"），直接返回
func getRoleFromCatID(catID string) model.AgentRole {
	return model.AgentRole(catID)
}

// checkDatabaseTables 检查数据库关键表是否存在
// 用于定位安装时迁移问题，打印详细日志以便后续排查
func checkDatabaseTables(db *sql.DB, logger *zap.Logger) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 定义关键表列表（按版本分组）
	// 这些表应该在安装时由 migrate.exe 创建
	requiredTables := map[string][]string{
		"v1.1.0": {"projects", "threads", "messages", "agent_configs", "base_agents", "agent_invocations", "artifacts", "sandboxes", "workflow_templates"},
		"v1.2.0": {"skills", "commands", "subagents", "rules", "settings"},
		"v1.2.2": {"markets", "team_package_versions"},
	}

	// 查询现有表
	var existingTables []string
	rows, err := db.QueryContext(ctx, "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
	if err != nil {
		logger.Error("Failed to query database tables", zap.Error(err))
		return
	}
	defer rows.Close()

	for rows.Next() {
		var name string
		if err := rows.Scan(&name); err != nil {
			logger.Warn("Failed to scan table name", zap.Error(err))
			continue
		}
		existingTables = append(existingTables, name)
	}
	logger.Info("Database tables detected", zap.Strings("tables", existingTables))

	// 检查缺失的表
	var missingTables []string
	for version, tables := range requiredTables {
		for _, table := range tables {
			found := false
			for _, existing := range existingTables {
				if existing == table {
					found = true
					break
				}
			}
			if !found {
				missingTables = append(missingTables, fmt.Sprintf("%s (from %s)", table, version))
			}
		}
	}

	if len(missingTables) > 0 {
		logger.Warn("Missing database tables detected",
			zap.Strings("missing", missingTables),
			zap.String("hint", "Please check if migrate.exe ran correctly during installation"))
	} else {
		logger.Info("All required database tables exist")
	}

	// 检查 goose_db_version 表（迁移版本记录）
	var gooseVersion int64
	row := db.QueryRowContext(ctx, "SELECT MAX(version_id) FROM goose_db_version")
	if err := row.Scan(&gooseVersion); err != nil {
		if err == sql.ErrNoRows {
			logger.Warn("goose_db_version table is empty or missing", zap.Error(err))
		} else {
			logger.Warn("Failed to query goose_db_version", zap.Error(err))
		}
	} else {
		logger.Info("Database migration version", zap.Int64("goose_version", gooseVersion))
	}

	// 检查数据库文件信息（SQLite）
	var dbSize int64
	var pageCount int64
	row = db.QueryRowContext(ctx, "PRAGMA page_count")
	if err := row.Scan(&pageCount); err == nil {
		row = db.QueryRowContext(ctx, "PRAGMA page_size")
		var pageSize int64
		if err := row.Scan(&pageSize); err == nil {
			dbSize = pageCount * pageSize
			logger.Info("Database file info",
				zap.Int64("page_count", pageCount),
				zap.Int64("page_size", pageSize),
				zap.Int64("size_bytes", dbSize),
				zap.String("size_mb", fmt.Sprintf("%.2f", float64(dbSize)/1024/1024)))
		}
	}
}
