package handlers

import (
	"context"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-sql-driver/mysql"
	"github.com/redis/go-redis/v9"
	gormDB "gorm.io/gorm"

	"mengyastore-backend/internal/config"
	"mengyastore-backend/internal/mq"
)

// SystemStatusHandler 向管理端暴露运维状态（仅供管理员）。
type SystemStatusHandler struct {
	cfg   *config.Config
	db    *gormDB.DB
	mq    *mq.Client
	start time.Time
}

func NewSystemStatusHandler(cfg *config.Config, db *gormDB.DB, mqClient *mq.Client, startedAt time.Time) *SystemStatusHandler {
	return &SystemStatusHandler{cfg: cfg, db: db, mq: mqClient, start: startedAt}
}

// GetSystemStatus 返回管理后台用 JSON，需通过管理员令牌。
// @Summary 系统运行状态
// @Tags 管理端-系统
// @Produce json
// @Security AdminToken
// @Success 200 {object} map[string]interface{}
// @Failure 401 {object} SwaggerErrorBody
// @Router /api/admin/system-status [get]
func (h *SystemStatusHandler) GetSystemStatus(c *gin.Context) {
	if !h.adminTokenOK(c) {
		return
	}
	ctx, cancel := context.WithTimeout(c.Request.Context(), 8*time.Second)
	defer cancel()

	c.JSON(http.StatusOK, gin.H{
		"data": gin.H{
			"backend":  h.backendInfo(c),
			"mysql":    h.mysqlInfo(ctx),
			"redis":    h.redisInfo(ctx),
			"rabbitmq": h.rabbitmqInfo(),
		},
	})
}

func (h *SystemStatusHandler) adminTokenOK(c *gin.Context) bool {
	token := c.GetHeader("X-Admin-Token")
	if token == "" {
		token = c.GetHeader("Authorization")
	}
	if token == "" {
		token = c.Query("token")
	}
	if token != "" && token == h.cfg.AdminToken {
		return true
	}
	c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
	return false
}

func (h *SystemStatusHandler) backendInfo(c *gin.Context) gin.H {
	proto := c.GetHeader("X-Forwarded-Proto")
	if proto == "" {
		if c.Request.TLS != nil {
			proto = "https"
		} else {
			proto = "http"
		}
	}
	host := c.Request.Host
	publicBase := strings.TrimSpace(h.cfg.PublicAPIBaseURL)
	if publicBase == "" && host != "" {
		publicBase = proto + "://" + host
	}

	out := gin.H{
		"status":            "ok",
		"appEnv":            h.cfg.AppEnv,
		"ginMode":           gin.Mode(),
		"requestHost":       host,
		"listenAddr":        h.cfg.HTTPListenAddr,
		"publicBaseUrl":     publicBase,
		"uptimeSeconds":     int(time.Since(h.start).Seconds()),
		"authApiConfigured": strings.TrimSpace(h.cfg.AuthAPIURL) != "",
		"rabbitmqEnabled":   h.cfg.RabbitMQEnabled,
		"redisEnabled":      h.cfg.RedisEnabled,
	}
	return out
}

func (h *SystemStatusHandler) mysqlInfo(ctx context.Context) gin.H {
	out := gin.H{}
	parseMysqlDSNForDisplay(h.cfg.DatabaseDSN, out)

	if h.db == nil {
		out["status"] = "error"
		out["message"] = "数据库未初始化"
		return out
	}
	sqlDB, err := h.db.DB()
	if err != nil {
		out["status"] = "error"
		out["message"] = err.Error()
		return out
	}
	if err := sqlDB.PingContext(ctx); err != nil {
		out["status"] = "error"
		out["message"] = err.Error()
		return out
	}

	var ver string
	if err := h.db.WithContext(ctx).Raw("SELECT VERSION()").Scan(&ver).Error; err != nil {
		out["status"] = "degraded"
		out["message"] = "连接正常但读取版本失败: " + err.Error()
		stats := sqlDB.Stats()
		out["openConnections"] = stats.OpenConnections
		out["inUse"] = stats.InUse
		out["idle"] = stats.Idle
		return out
	}

	stats := sqlDB.Stats()
	out["status"] = "ok"
	out["version"] = strings.TrimSpace(ver)
	out["openConnections"] = stats.OpenConnections
	out["inUse"] = stats.InUse
	out["idle"] = stats.Idle
	out["waitCount"] = stats.WaitCount
	return out
}

func parseMysqlDSNForDisplay(dsn string, out gin.H) {
	if dsn == "" {
		out["configured"] = false
		return
	}
	mc, err := mysql.ParseDSN(dsn)
	if err != nil {
		out["configured"] = false
		out["dsnParseError"] = err.Error()
		return
	}
	out["configured"] = true
	out["user"] = mc.User
	out["database"] = mc.DBName
	host, port, err := net.SplitHostPort(mc.Addr)
	if err != nil {
		out["host"] = mc.Addr
		out["port"] = ""
		if mc.Net == "unix" {
			out["socket"] = mc.Addr
		}
	} else {
		out["host"] = host
		out["port"] = port
	}
}

func (h *SystemStatusHandler) redisInfo(ctx context.Context) gin.H {
	out := gin.H{
		"enabled": h.cfg.RedisEnabled,
		"env":     h.cfg.RedisEnv,
	}
	if h.cfg.RedisAddr != "" {
		host, port, err := net.SplitHostPort(h.cfg.RedisAddr)
		if err != nil {
			out["host"] = h.cfg.RedisAddr
			out["port"] = "6379"
		} else {
			out["host"] = host
			if port == "" {
				port = "6379"
			}
			out["port"] = port
		}
	}
	out["dbIndex"] = h.cfg.RedisDB

	if !h.cfg.RedisEnabled {
		out["status"] = "disabled"
		return out
	}
	if h.cfg.RedisAddr == "" {
		out["status"] = "misconfigured"
		out["message"] = "已启用但未配置 REDIS_ADDR"
		return out
	}

	rdb := redis.NewClient(&redis.Options{
		Addr:     h.cfg.RedisAddr,
		Password: h.cfg.RedisPassword,
		DB:       h.cfg.RedisDB,
	})
	defer rdb.Close()

	if err := rdb.Ping(ctx).Err(); err != nil {
		out["status"] = "error"
		out["message"] = err.Error()
		return out
	}

	info, err := rdb.Info(ctx, "server", "memory").Result()
	if err != nil {
		out["status"] = "degraded"
		out["message"] = "PING 成功但无法读取 INFO: " + err.Error()
		return out
	}
	dbsize, _ := rdb.DBSize(ctx).Result()

	out["status"] = "ok"
	out["redisVersion"] = parseRedisInfoField(info, "redis_version:")
	out["usedMemoryHuman"] = parseRedisInfoField(info, "used_memory_human:")
	out["keysApprox"] = dbsize
	return out
}

func parseRedisInfoField(block, key string) string {
	for _, line := range strings.Split(block, "\r\n") {
		if strings.HasPrefix(line, key) {
			return strings.TrimSpace(strings.TrimPrefix(line, key))
		}
	}
	return ""
}

func (h *SystemStatusHandler) rabbitmqInfo() gin.H {
	out := gin.H{
		"enabled":    h.cfg.RabbitMQEnabled,
		"env":        h.cfg.RabbitMQEnv,
		"exchange":   mq.ExchangeName(h.cfg.RabbitMQEnv),
		"queue":      mq.QueueName(h.cfg.RabbitMQEnv),
		"routingKey": mq.OrderEmailRoutingKey(),
	}
	host, port, vhost, user := parseAMQPBroker(h.cfg.RabbitMQURL)
	out["brokerHost"] = host
	out["brokerPort"] = port
	out["vhost"] = vhost
	out["brokerUser"] = user

	if !h.cfg.RabbitMQEnabled {
		out["status"] = "disabled"
		return out
	}

	if h.cfg.RabbitMQURL == "" {
		out["status"] = "misconfigured"
		out["message"] = "已启用但未配置 RABBITMQ_URL 或 RABBITMQ_PASSWORD"
		return out
	}

	if h.mq == nil {
		out["status"] = "error"
		out["message"] = "连接未建立，请检查 Broker 与 vhost 权限"
		return out
	}

	if err := h.mq.Ping(); err != nil {
		out["status"] = "error"
		out["message"] = err.Error()
		return out
	}

	msgs, cons, err := h.mq.QueueInspectInfo()
	if err != nil {
		out["status"] = "degraded"
		out["message"] = "通道可用但无法读取队列统计: " + err.Error()
		return out
	}

	out["status"] = "ok"
	out["messagesReady"] = msgs
	out["consumers"] = cons
	return out
}

// parseAMQPBroker 从 amqp URL 解析主机、端口、vhost、用户名（不含口令，仅展示用）。
func parseAMQPBroker(raw string) (host, port, vhost, user string) {
	if raw == "" {
		return "", "", "", ""
	}
	u, err := url.Parse(raw)
	if err != nil {
		return "", "", "", ""
	}
	host = u.Hostname()
	port = u.Port()
	if port == "" {
		port = "5672"
	}
	if u.User != nil {
		user = u.User.Username()
	}
	vpath := strings.TrimPrefix(u.Path, "/")
	if vpath != "" {
		if dec, err := url.PathUnescape(vpath); err == nil {
			vhost = dec
		} else {
			vhost = vpath
		}
	}
	if vhost == "" {
		vhost = "/"
	}
	return host, port, vhost, user
}
