package http

import (
	"runtime"
	"time"

	stdhttp "net/http"

	"qycw/go-server/internal/bootstrap"
	licenseclient "qycw/go-server/internal/license"
)

func adminSystemInfo(app *bootstrap.App, startedAt time.Time, req *stdhttp.Request) map[string]any {
	now := time.Now()
	license, update := licenseSystemInfo(app, req)
	info := map[string]any{
		"app": map[string]any{
			"name":           app.Config.AppName,
			"version":        app.Config.AppVersion,
			"backend_type":   "go",
			"started_at":     startedAt.Format(time.RFC3339),
			"current_time":   now.Format(time.RFC3339),
			"uptime_seconds": int64(now.Sub(startedAt).Seconds()),
		},
		"runtime": runtimeInfo(),
		"settings": map[string]any{
			"mode": app.Settings.Mode(),
		},
		"plugins": map[string]any{
			"enabled": app.Plugins != nil,
		},
		"database": databaseInfo(app, req),
		"redis":    redisInfo(app, req),
		"license":  license,
		"update":   update,
	}
	return info
}

func licenseInfo(app *bootstrap.App, req *stdhttp.Request) map[string]any {
	info := map[string]any{
		"required":   true,
		"configured": false,
	}
	if app == nil || app.LicenseManager == nil {
		return info
	}
	state, err := app.LicenseManager.State(req.Context())
	if err != nil {
		return info
	}
	info["configured"] = state.Configured()
	if app.LicenseEval != nil {
		status := app.LicenseEval.Status()
		info["status"] = status
		if status == "grace" {
			if graceUntil := app.LicenseEval.GraceUntil(); !graceUntil.IsZero() {
				info["grace_until"] = graceUntil.UTC().Format(time.RFC3339)
			}
		}
	}
	return info
}

func licenseSystemInfo(app *bootstrap.App, req *stdhttp.Request) (map[string]any, map[string]any) {
	license := map[string]any{
		"required":   true,
		"configured": false,
		"status":     "missing",
	}
	update := map[string]any{
		"status": "unavailable",
	}
	if app == nil || app.LicenseManager == nil {
		return license, update
	}
	state, err := app.LicenseManager.State(req.Context())
	if err != nil || !state.Configured() {
		return license, update
	}
	license["configured"] = true
	if app.LicenseEval != nil {
		license["status"] = app.LicenseEval.Status()
		if license["status"] == "grace" {
			if graceUntil := app.LicenseEval.GraceUntil(); !graceUntil.IsZero() {
				license["grace_until"] = graceUntil.UTC().Format(time.RFC3339)
			}
		}
	} else {
		license["status"] = "unavailable"
	}
	applyLocalLicenseInfo(license, state, app.Config.AppVersion)
	if app.License == nil {
		return license, update
	}

	result, _, _, err := app.License.QueryRaw(req.Context(), state.Code, state.Identity.InstanceID, state.InstanceToken, state.Identity.BackendURL)
	if err != nil {
		return license, update
	}
	if !result.Authorized {
		license["status"] = "invalid"
		return license, update
	}
	license["status"] = "active"
	license["license_no"] = result.LicenseNo
	license["purchase"] = result.Purchase
	license["expire"] = result.Expire
	license["service_purchase"] = result.ServicePurchase
	license["service_expire"] = result.ServiceExpire

	update["status"] = "ok"
	update["version"] = result.Version
	update["update_url"] = result.UpdateURL
	update["db_update_required"] = result.DBUpdate
	update["update_time"] = result.UpdateTime
	update["changelog"] = result.Changelog
	update["force_update_required"] = result.ForceUpdate
	return license, update
}

func applyLocalLicenseInfo(info map[string]any, state licenseclient.State, appVersion string) {
	info["type"] = state.Type
	info["version"] = state.Version
	info["verified_at"] = formatOptionalTime(state.VerifiedAt)
	info["instance_name"] = state.Identity.InstanceName
	info["system_name"] = state.Identity.SystemName
	info["system_arch"] = state.Identity.SystemArch
	info["backend_url"] = state.Identity.BackendURL
	info["last_online"] = formatOptionalTime(state.LastHeartbeatAt)
	info["running_version"] = appVersion
}

func formatOptionalTime(value time.Time) string {
	if value.IsZero() {
		return ""
	}
	return value.UTC().Format(time.RFC3339)
}

func runtimeInfo() map[string]any {
	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)
	return map[string]any{
		"go_version": runtime.Version(),
		"os":         runtime.GOOS,
		"arch":       runtime.GOARCH,
		"cpus":       runtime.NumCPU(),
		"goroutines": runtime.NumGoroutine(),
		"memory": map[string]any{
			"alloc_mb":      bytesToMB(mem.Alloc),
			"heap_alloc_mb": bytesToMB(mem.HeapAlloc),
			"sys_mb":        bytesToMB(mem.Sys),
			"num_gc":        mem.NumGC,
		},
	}
}

func databaseInfo(app *bootstrap.App, req *stdhttp.Request) map[string]any {
	info := map[string]any{
		"enabled": app.DB != nil,
		"status":  "disabled",
	}
	if app.DB == nil {
		return info
	}

	sqlDB, err := app.DB.DB()
	if err != nil {
		info["status"] = "error"
		info["error"] = err.Error()
		return info
	}

	started := time.Now()
	if err := sqlDB.PingContext(req.Context()); err != nil {
		info["status"] = "error"
		info["latency_ms"] = millisSince(started)
		info["error"] = err.Error()
		return info
	}

	stats := sqlDB.Stats()
	info["status"] = "ok"
	info["latency_ms"] = millisSince(started)
	info["open_connections"] = stats.OpenConnections
	info["in_use"] = stats.InUse
	info["idle"] = stats.Idle
	info["max_open_connections"] = stats.MaxOpenConnections
	info["wait_count"] = stats.WaitCount
	return info
}

func redisInfo(app *bootstrap.App, req *stdhttp.Request) map[string]any {
	info := map[string]any{
		"enabled": app.Redis != nil,
		"status":  "disabled",
	}
	if app.Redis == nil {
		return info
	}

	started := time.Now()
	if err := app.Redis.Ping(req.Context()).Err(); err != nil {
		info["status"] = "error"
		info["latency_ms"] = millisSince(started)
		info["error"] = err.Error()
		return info
	}
	info["status"] = "ok"
	info["latency_ms"] = millisSince(started)
	return info
}

func millisSince(started time.Time) int64 {
	return time.Since(started).Milliseconds()
}

func bytesToMB(value uint64) float64 {
	return float64(value) / 1024 / 1024
}
