package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"yh_web/server/config"
	"yh_web/server/handlers"
	"yh_web/server/middleware"
	"yh_web/server/models"
	"yh_web/server/pkg/logger"
	"yh_web/server/pkg/schema"

	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
)

// loadEnv 启动时自动加载 .env（在 server 目录或项目根/server 下），不覆盖已存在的环境变量
func loadEnv() {
	wd, _ := os.Getwd()
	serverDir := wd
	if !strings.HasSuffix(filepath.Clean(wd), "server") {
		serverDir = filepath.Join(wd, "server")
	}
	envPath := filepath.Clean(filepath.Join(serverDir, ".env"))
	if _, err := os.Stat(envPath); err == nil {
		if err := godotenv.Load(envPath); err == nil {
			log.Printf("已加载配置: %s", envPath)
		}
	}
}

func main() {
	loadEnv()

	// 初始化根目录 logs/server（支持从项目根或 server 目录启动）
	wd, _ := os.Getwd()
	baseDir := filepath.Join(wd, "logs", "server")
	if strings.HasSuffix(filepath.Clean(wd), "server") {
		baseDir = filepath.Join(wd, "..", "logs", "server")
	}
	logger.Init(filepath.Clean(baseDir))

	// 连接 MongoDB；URI 从环境变量 MONGODB_URI 读取，默认 mongodb://localhost:27017；SKIP_MONGODB=1 时可跳过
	if os.Getenv("SKIP_MONGODB") != "1" {
		mongoURI := os.Getenv("MONGODB_URI")
		if mongoURI == "" {
			mongoURI = "mongodb://localhost:27017"
		}
		if dbName := os.Getenv("MONGODB_DB"); dbName != "" {
			config.DBName = dbName
		}
		if err := config.ConnectMongoDB(mongoURI); err != nil {
			logger.Err("main", "MongoDB 连接失败: %v（若仅需健康检查可设置环境变量 SKIP_MONGODB=1 后启动）", err)
			log.Fatalf("MongoDB 连接失败: %v（若仅需健康检查可设置环境变量 SKIP_MONGODB=1 后启动）", err)
		}
		defer config.CloseMongoDB()

		// 启动时获取线上表结构并生成 sql；缺失的集合在线上创建并生成 created_*.sql
		projectRoot := wd
		if strings.HasSuffix(filepath.Clean(wd), "server") {
			projectRoot = filepath.Join(wd, "..")
		}
		projectRoot = filepath.Clean(projectRoot)
		ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
		if err := schema.Sync(ctx, projectRoot); err != nil {
			logger.Err("main", "启动时同步表结构失败: %v", err)
			log.Printf("警告: 启动时同步表结构失败: %v", err)
		}
		cancel()
	} else {
		logger.Log("main", "已跳过 MongoDB 连接（SKIP_MONGODB=1），仅 /api/health 等不依赖数据库的接口可用")
		log.Println("已跳过 MongoDB 连接（SKIP_MONGODB=1），仅 /api/health 等不依赖数据库的接口可用")
	}

	r := gin.Default()
	r.MaxMultipartMemory = 200 << 20 // 200MB，与 Nginx client_max_body_size 一致，避免上传 413
	r.Use(middleware.ErrorLogger())

	// CORS（ALLOWED_ORIGINS 为空则允许所有来源；否则仅允许配置的域名）
	allowedOriginsEnv := os.Getenv("ALLOWED_ORIGINS")
	r.Use(func(c *gin.Context) {
		origin := c.GetHeader("Origin")
		if allowedOriginsEnv != "" {
			for _, o := range strings.Split(allowedOriginsEnv, ",") {
				if strings.TrimSpace(o) == origin {
					c.Header("Access-Control-Allow-Origin", origin)
					break
				}
			}
		} else {
			c.Header("Access-Control-Allow-Origin", "*")
		}
		c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}
		c.Next()
	})

	// 未连接 MongoDB 时，/api/admin 下所有接口返回 503（健康检查不受影响）
	r.Use(func(c *gin.Context) {
		if strings.HasPrefix(c.Request.URL.Path, "/api/admin") && config.MongoClient == nil {
			c.JSON(http.StatusServiceUnavailable, gin.H{"error": "服务暂不可用，数据库未连接"})
			c.Abort()
			return
		}
		c.Next()
	})

	// 健康检查
	r.GET("/api/health", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"status": "ok"})
	})

	// 登录、注册（无需鉴权）
	r.POST("/api/admin/login", handlers.Login)
	r.POST("/api/admin/send-code", handlers.SendCode)
	r.POST("/api/admin/register", handlers.Register)
	r.POST("/api/admin/reset-password", handlers.ResetPassword)

	// 后台 API 路由组（需鉴权）
	admin := r.Group("/api/admin")
	admin.Use(handlers.AuthRequired())
	{
		admin.GET("/info", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"message": "admin api"})
		})
		admin.GET("/my-permissions", handlers.GetMyPermissions)
		admin.GET("/db-structure", func(c *gin.Context) {
			structure, err := config.GetDBStructure()
			if err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
				return
			}
			c.JSON(http.StatusOK, structure)
		})
		admin.GET("/stats", handlers.GetStats)

		// 用户管理
		admin.GET("/users", handlers.RequirePermission(models.PermUserManage), handlers.GetUsers)
		admin.GET("/users/:id", handlers.RequirePermission(models.PermUserManage), handlers.GetUserByID)
		admin.POST("/users", handlers.RequirePermission(models.PermUserManage), handlers.CreateUser)
		admin.PUT("/users/:id", handlers.RequirePermission(models.PermUserManage), handlers.UpdateUser)
		admin.DELETE("/users/:id", handlers.RequirePermission(models.PermUserManage), handlers.DeleteUser)

		// 工作空间
		admin.GET("/workspaces", handlers.RequirePermission(models.PermWorkspaceManage), handlers.GetWorkspaces)

		// 对话
		admin.GET("/conversations", handlers.RequirePermission(models.PermConversationManage), handlers.GetConversations)

		// 站点管理（带子路径的路由放前面；与 :site_id 统一，避免 Gin 路由冲突）
		admin.GET("/sites/:site_id/homepage/download", handlers.RequirePermission(models.PermHomepageEdit), handlers.DownloadHomepage)
		admin.GET("/sites/:site_id/homepage", handlers.RequirePermission(models.PermHomepageEdit), handlers.GetHomepage)
		admin.PUT("/sites/:site_id/homepage", handlers.RequirePermission(models.PermHomepageEdit), handlers.UpdateHomepage)
		admin.GET("/sites/:site_id/assets/downloadable", handlers.RequirePermission(models.PermHomepageEdit), handlers.ListDownloadableAssets)
		admin.GET("/sites/:site_id/assets", handlers.RequirePermission(models.PermSiteManage), handlers.ListSiteAssets)
		admin.POST("/sites/:site_id/assets", handlers.RequirePermission(models.PermModuleUpload), handlers.UploadSiteAsset)
		admin.POST("/sites/:site_id/folders", handlers.RequirePermission(models.PermModuleUpload), handlers.CreateSiteFolder)
		admin.DELETE("/sites/:site_id/assets/:asset_id", handlers.RequirePermission(models.PermSiteManage), handlers.DeleteSiteAsset)
		admin.GET("/sites", handlers.RequirePermission(models.PermSiteManage), handlers.GetSites)
		admin.GET("/sites/:site_id", handlers.RequirePermission(models.PermSiteManage), handlers.GetSiteByID)
		admin.POST("/sites", handlers.RequirePermission(models.PermSiteManage), handlers.CreateSite)
		admin.PUT("/sites/:site_id", handlers.RequirePermission(models.PermSiteManage), handlers.UpdateSite)
		admin.DELETE("/sites/:site_id", handlers.RequirePermission(models.PermSiteManage), handlers.DeleteSite)
		admin.GET("/system/official-site", handlers.RequirePermission(models.PermSiteManage), handlers.GetOfficialSite)
		admin.PUT("/system/official-site", handlers.RequirePermission(models.PermSiteManage), handlers.SetOfficialSite)

		// 角色权限管理
		admin.GET("/role-permissions", handlers.RequirePermission(models.PermRolePermission), handlers.GetRolePermissionsList)
		admin.POST("/role-permissions", handlers.RequirePermission(models.PermRolePermission), handlers.CreateRole)
		admin.PUT("/role-permissions/:role_id", handlers.RequirePermission(models.PermRolePermission), handlers.UpdateRolePermissions)
		admin.DELETE("/role-permissions/:role_id", handlers.RequirePermission(models.PermRolePermission), handlers.DeleteRole)

		// 网页管理（按站点）
		admin.GET("/pages", handlers.RequirePermission(models.PermPageManage), handlers.GetPages)
		admin.GET("/pages/:id", handlers.RequirePermission(models.PermPageManage), handlers.GetPageByID)
		admin.POST("/pages", handlers.RequirePermission(models.PermPageManage), handlers.CreatePage)
		admin.PUT("/pages/:id", handlers.RequirePermission(models.PermPageManage), handlers.UpdatePage)
		admin.DELETE("/pages/:id", handlers.RequirePermission(models.PermPageManage), handlers.DeletePage)

		// 短信平台配置
		smsConfig := admin.Group("/sms-config")
		smsConfig.Use(handlers.RequirePermission(models.PermSMSConfig))
		{
			smsConfig.GET("", handlers.GetSMSConfig)
			smsConfig.PUT("", handlers.UpdateSMSConfig)
		}

		// 支付配置（微信、支付宝）
		paymentConfig := admin.Group("/payment-config")
		paymentConfig.Use(handlers.RequirePermission(models.PermPaymentConfig))
		{
			paymentConfig.GET("", handlers.GetPaymentConfig)
			paymentConfig.PUT("", handlers.UpdatePaymentConfig)
		}
	}

	// 官网站点首页（前台，无需鉴权）
	r.GET("/api/web/homepage", handlers.GetWebHomepage)

	// 前台 API 路由组
	web := r.Group("/api/web")
	{
		web.GET("/info", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"message": "web api"})
		})
		// 可下载资源公开下载（首页等链接指向此路径）
		web.GET("/sites/:site_id/assets/:asset_id/download", handlers.DownloadSiteAsset)
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	r.Run(":" + port)
}
