package appconfig

import (
	"fmt"
	"strconv"
	"strings"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/integration/activityclient"
	"hyapp-admin-server/internal/integration/userclient"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/repository"
	"hyapp-admin-server/internal/response"

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

type Handler struct {
	service *AppConfigService
	audit   shared.OperationLogger
}

func New(store *repository.Store, audit shared.OperationLogger) *Handler {
	return &Handler{service: NewService(store), audit: audit}
}

func (h *Handler) BindActivityTemplateTarget(activity activityclient.Client, landing ActivityLandingURLBuilder) *Handler {
	if h != nil {
		h.service.BindActivityTemplateTarget(activity, landing)
	}
	return h
}

func (h *Handler) BindRoleScopePolicyClient(client userclient.Client) *Handler {
	if h != nil {
		h.service.BindRoleScopePolicyClient(client)
	}
	return h
}

func (h *Handler) ListH5Links(c *gin.Context) {
	appCode := appctx.FromContext(c.Request.Context())
	items, err := h.service.ListH5Links(appCode)
	if err != nil {
		response.ServerError(c, "获取 H5 配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) UpdateH5Links(c *gin.Context) {
	var request updateH5LinksRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}

	appCode := appctx.FromContext(c.Request.Context())
	items, err := h.service.UpdateH5Links(appCode, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-h5-links", "admin_app_configs", "success", fmt.Sprintf("app_code=%s %d h5 links", appCode, len(request.Items)))
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreateH5Link(c *gin.Context) {
	var request h5LinkPayload
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	appCode := appctx.FromContext(c.Request.Context())
	item, err := h.service.CreateH5Link(appCode, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-h5-link", "admin_app_configs", "success", fmt.Sprintf("app_code=%s h5_key=%s", appCode, item.Key))
	response.Created(c, item)
}

func (h *Handler) UpdateH5Link(c *gin.Context) {
	key := strings.TrimSpace(c.Param("key"))
	if key == "" {
		response.BadRequest(c, "h5 config key is invalid")
		return
	}
	var request h5LinkPayload
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	appCode := appctx.FromContext(c.Request.Context())
	item, err := h.service.UpdateH5Link(appCode, key, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-h5-link", "admin_app_configs", "success", fmt.Sprintf("app_code=%s h5_key=%s", appCode, item.Key))
	response.OK(c, item)
}

func (h *Handler) DeleteH5Link(c *gin.Context) {
	key := strings.TrimSpace(c.Param("key"))
	if key == "" {
		response.BadRequest(c, "h5 config key is invalid")
		return
	}
	appCode := appctx.FromContext(c.Request.Context())
	if err := h.service.DeleteH5Link(appCode, key); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-h5-link", "admin_app_configs", "success", fmt.Sprintf("app_code=%s h5_key=%s", appCode, key))
	response.OK(c, gin.H{"deleted": true})
}

func (h *Handler) ListBanners(c *gin.Context) {
	options := shared.ListOptions(c)
	regionID := parseOptionalInt64(c.Query("regionId"), c.Query("region_id"))
	country := firstQuery(c, "countryCode", "country_code", "country")
	if scope, external := appctx.ExternalScopeFromContext(c.Request.Context()); external {
		regionID = scope.RegionID
		// Region is server-owned for portal traffic. Country remains an optional,
		// region-validated narrowing filter handled by create/update and owner data.
		country = strings.TrimSpace(country)
	}
	items, err := h.service.ListBanners(appctx.FromContext(c.Request.Context()), repository.AppBannerListOptions{
		Keyword:      options.Keyword,
		Status:       options.Status,
		DisplayScope: firstQuery(c, "displayScope", "display_scope"),
		Platform:     strings.TrimSpace(c.Query("platform")),
		RegionID:     regionID,
		Country:      country,
	})
	if err != nil {
		response.ServerError(c, "获取 BANNER 配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreateBanner(c *gin.Context) {
	var request bannerRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.CreateBanner(c.Request.Context(), appctx.FromContext(c.Request.Context()), request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-banner", "admin_app_banners", "success", fmt.Sprintf("banner_id=%d", item.ID))
	response.Created(c, item)
}

func (h *Handler) UpdateBanner(c *gin.Context) {
	id, ok := bannerID(c)
	if !ok {
		return
	}
	var request bannerRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.UpdateBanner(c.Request.Context(), appctx.FromContext(c.Request.Context()), id, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-banner", "admin_app_banners", "success", fmt.Sprintf("banner_id=%d", item.ID))
	response.OK(c, item)
}

func (h *Handler) DeleteBanner(c *gin.Context) {
	id, ok := bannerID(c)
	if !ok {
		return
	}
	if err := h.service.DeleteBanner(c.Request.Context(), appctx.FromContext(c.Request.Context()), id); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-banner", "admin_app_banners", "success", fmt.Sprintf("banner_id=%d", id))
	response.OK(c, gin.H{"deleted": true})
}

func (h *Handler) ListSplashScreens(c *gin.Context) {
	options := shared.ListOptions(c)
	items, err := h.service.ListSplashScreens(appctx.FromContext(c.Request.Context()), repository.AppSplashScreenListOptions{
		Keyword:  options.Keyword,
		Status:   options.Status,
		Platform: strings.TrimSpace(c.Query("platform")),
		RegionID: parseOptionalInt64(c.Query("regionId"), c.Query("region_id")),
		Country:  firstQuery(c, "countryCode", "country_code", "country"),
	})
	if err != nil {
		response.ServerError(c, "获取开屏配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreateSplashScreen(c *gin.Context) {
	var request splashScreenRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.CreateSplashScreen(appctx.FromContext(c.Request.Context()), request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-splash-screen", "admin_app_splash_screens", "success", fmt.Sprintf("splash_id=%d", item.ID))
	response.Created(c, item)
}

func (h *Handler) UpdateSplashScreen(c *gin.Context) {
	id, ok := splashScreenID(c)
	if !ok {
		return
	}
	var request splashScreenRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.UpdateSplashScreen(appctx.FromContext(c.Request.Context()), id, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-splash-screen", "admin_app_splash_screens", "success", fmt.Sprintf("splash_id=%d", item.ID))
	response.OK(c, item)
}

func (h *Handler) DeleteSplashScreen(c *gin.Context) {
	id, ok := splashScreenID(c)
	if !ok {
		return
	}
	if err := h.service.DeleteSplashScreen(appctx.FromContext(c.Request.Context()), id); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-splash-screen", "admin_app_splash_screens", "success", fmt.Sprintf("splash_id=%d", id))
	response.OK(c, gin.H{"deleted": true})
}

func (h *Handler) ListPopups(c *gin.Context) {
	options := shared.ListOptions(c)
	items, err := h.service.ListPopups(appctx.FromContext(c.Request.Context()), repository.AppPopupListOptions{
		Keyword: options.Keyword,
		Status:  options.Status,
	})
	if err != nil {
		response.ServerError(c, "获取弹窗配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreatePopup(c *gin.Context) {
	var request popupRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.CreatePopup(appctx.FromContext(c.Request.Context()), request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-popup", "admin_app_popups", "success", fmt.Sprintf("popup_id=%d", item.ID))
	response.Created(c, item)
}

func (h *Handler) UpdatePopup(c *gin.Context) {
	id, ok := popupID(c)
	if !ok {
		return
	}
	var request popupRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.UpdatePopup(appctx.FromContext(c.Request.Context()), id, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-popup", "admin_app_popups", "success", fmt.Sprintf("popup_id=%d", item.ID))
	response.OK(c, item)
}

func (h *Handler) DeletePopup(c *gin.Context) {
	id, ok := popupID(c)
	if !ok {
		return
	}
	if err := h.service.DeletePopup(appctx.FromContext(c.Request.Context()), id); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-popup", "admin_app_popups", "success", fmt.Sprintf("popup_id=%d", id))
	response.OK(c, gin.H{"deleted": true})
}

func (h *Handler) ListAppVersions(c *gin.Context) {
	items, err := h.service.ListAppVersions(appctx.FromContext(c.Request.Context()), repository.AppVersionListOptions{
		Keyword:  strings.TrimSpace(c.Query("keyword")),
		Platform: strings.TrimSpace(c.Query("platform")),
	})
	if err != nil {
		response.ServerError(c, "获取版本配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreateAppVersion(c *gin.Context) {
	var request appVersionRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.CreateAppVersion(appctx.FromContext(c.Request.Context()), request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", item.ID))
	response.Created(c, item)
}

func (h *Handler) UpdateAppVersion(c *gin.Context) {
	id, ok := appVersionID(c)
	if !ok {
		return
	}
	var request appVersionRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.UpdateAppVersion(appctx.FromContext(c.Request.Context()), id, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", item.ID))
	response.OK(c, item)
}

func (h *Handler) DeleteAppVersion(c *gin.Context) {
	id, ok := appVersionID(c)
	if !ok {
		return
	}
	if err := h.service.DeleteAppVersion(appctx.FromContext(c.Request.Context()), id); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-version", "admin_app_versions", "success", fmt.Sprintf("version_id=%d", id))
	response.OK(c, gin.H{"deleted": true})
}

func (h *Handler) ListExploreTabs(c *gin.Context) {
	var enabled *bool
	switch strings.ToLower(strings.TrimSpace(c.Query("enabled"))) {
	case "true", "1", "enabled":
		value := true
		enabled = &value
	case "false", "0", "disabled":
		value := false
		enabled = &value
	}

	items, err := h.service.ListExploreTabs(appctx.FromContext(c.Request.Context()), repository.AppExploreTabListOptions{
		Keyword: strings.TrimSpace(c.Query("keyword")),
		Enabled: enabled,
	})
	if err != nil {
		response.ServerError(c, "获取 Explore 配置失败")
		return
	}
	response.OK(c, gin.H{"items": items, "total": len(items)})
}

func (h *Handler) CreateExploreTab(c *gin.Context) {
	var request exploreTabRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.CreateExploreTab(appctx.FromContext(c.Request.Context()), request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "create-app-explore-tab", "admin_app_explore_tabs", "success", fmt.Sprintf("explore_tab_id=%d", item.ID))
	response.Created(c, item)
}

func (h *Handler) UpdateExploreTab(c *gin.Context) {
	id, ok := exploreTabID(c)
	if !ok {
		return
	}
	var request exploreTabRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "参数不正确")
		return
	}
	item, err := h.service.UpdateExploreTab(appctx.FromContext(c.Request.Context()), id, request)
	if err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "update-app-explore-tab", "admin_app_explore_tabs", "success", fmt.Sprintf("explore_tab_id=%d", item.ID))
	response.OK(c, item)
}

func (h *Handler) DeleteExploreTab(c *gin.Context) {
	id, ok := exploreTabID(c)
	if !ok {
		return
	}
	if err := h.service.DeleteExploreTab(appctx.FromContext(c.Request.Context()), id); err != nil {
		response.BadRequest(c, err.Error())
		return
	}
	shared.OperationLog(c, h.audit, "delete-app-explore-tab", "admin_app_explore_tabs", "success", fmt.Sprintf("explore_tab_id=%d", id))
	response.OK(c, gin.H{"deleted": true})
}

func bannerID(c *gin.Context) (uint, bool) {
	value, err := strconv.ParseUint(c.Param("banner_id"), 10, 64)
	if err != nil || value == 0 {
		response.BadRequest(c, "banner id is invalid")
		return 0, false
	}
	return uint(value), true
}

func splashScreenID(c *gin.Context) (uint, bool) {
	value, err := strconv.ParseUint(c.Param("splash_id"), 10, 64)
	if err != nil || value == 0 {
		response.BadRequest(c, "splash screen id is invalid")
		return 0, false
	}
	return uint(value), true
}

func popupID(c *gin.Context) (uint, bool) {
	value, err := strconv.ParseUint(c.Param("popup_id"), 10, 64)
	if err != nil || value == 0 {
		response.BadRequest(c, "popup id is invalid")
		return 0, false
	}
	return uint(value), true
}

func appVersionID(c *gin.Context) (uint, bool) {
	value, err := strconv.ParseUint(c.Param("version_id"), 10, 64)
	if err != nil || value == 0 {
		response.BadRequest(c, "version id is invalid")
		return 0, false
	}
	return uint(value), true
}

func exploreTabID(c *gin.Context) (uint, bool) {
	value, err := strconv.ParseUint(c.Param("tab_id"), 10, 64)
	if err != nil || value == 0 {
		response.BadRequest(c, "explore tab id is invalid")
		return 0, false
	}
	return uint(value), true
}

func parseOptionalInt64(values ...string) int64 {
	for _, value := range values {
		value = strings.TrimSpace(value)
		if value == "" {
			continue
		}
		parsed, err := strconv.ParseInt(value, 10, 64)
		if err == nil && parsed > 0 {
			return parsed
		}
	}
	return 0
}

func firstQuery(c *gin.Context, keys ...string) string {
	for _, key := range keys {
		if value := c.Query(key); value != "" {
			return value
		}
	}
	return ""
}
