package databi

import (
	"strconv"
	"strings"

	"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 *Service
	store   *repository.Store
	audit   shared.OperationLogger
}

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

func (h *Handler) Master(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	master, err := h.service.Master(c.Request.Context(), access, shared.ActorFromContext(c).UserID, access.All)
	if err != nil {
		response.ServerError(c, "获取 BI 主数据失败")
		return
	}
	response.OK(c, master)
}

func (h *Handler) Overview(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	result, err := h.service.Overview(c.Request.Context(), access, OverviewQuery{
		StatTZ:    c.Query("stat_tz"),
		StartMS:   queryInt64(c, "start_ms"),
		EndMS:     queryInt64(c, "end_ms"),
		AppCodes:  splitCSV(c.Query("app_codes")),
		RegionID:  queryInt64(c, "region_id"),
		RegionIDs: queryInt64CSV(c.Query("region_ids")),
	})
	if err != nil {
		response.ServerError(c, "获取 BI 统计数据失败")
		return
	}
	response.OK(c, result)
}

func (h *Handler) Funnel(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	result, err := h.service.Funnel(c.Request.Context(), access, FunnelQuery{
		StatTZ:   c.Query("stat_tz"),
		StartMS:  queryInt64(c, "start_ms"),
		EndMS:    queryInt64(c, "end_ms"),
		AppCodes: splitCSV(c.Query("app_codes")),
		RegionID: queryInt64(c, "region_id"),
	})
	if err != nil {
		response.ServerError(c, "获取埋点漏斗数据失败")
		return
	}
	response.OK(c, result)
}

func (h *Handler) Requirements(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	result, err := h.service.Requirements(c.Request.Context(), access, RequirementsQuery{
		StatTZ:      c.Query("stat_tz"),
		StartMS:     queryInt64(c, "start_ms"),
		EndMS:       queryInt64(c, "end_ms"),
		AppCodes:    splitCSV(c.Query("app_codes")),
		RegionID:    queryInt64(c, "region_id"),
		RegionIDs:   queryInt64CSV(c.Query("region_ids")),
		Section:     c.Query("section"),
		UserRole:    c.Query("user_role"),
		PayerType:   c.Query("payer_type"),
		NewUserType: c.Query("new_user_type"),
	})
	if err != nil {
		response.ServerError(c, "获取数据需求指标失败")
		return
	}
	response.OK(c, result)
}

func (h *Handler) Kpi(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	result, err := h.service.Kpi(c.Request.Context(), access, KpiQuery{
		StatTZ:         c.Query("stat_tz"),
		StartMS:        queryInt64(c, "start_ms"),
		EndMS:          queryInt64(c, "end_ms"),
		PeriodMonth:    c.Query("period_month"),
		AppCodes:       splitCSV(c.Query("app_codes")),
		OperatorUserID: queryUint(c, "operator_user_id"),
		ActorUserID:    shared.ActorFromContext(c).UserID,
		ViewAll:        access.All,
	})
	if err != nil {
		if strings.Contains(err.Error(), "period_month") {
			response.BadRequest(c, "运营充值月份格式不正确")
			return
		}
		response.ServerError(c, "获取运营充值数据失败")
		return
	}
	response.OK(c, result)
}

func (h *Handler) moneyAccess(c *gin.Context) (repository.MoneyAccess, bool) {
	if h.store == nil {
		return repository.MoneyAccess{All: true}, true
	}
	access, err := h.store.MoneyAccessForUser(shared.ActorFromContext(c).UserID)
	if err != nil {
		response.ServerError(c, "获取数据范围失败")
		return repository.MoneyAccess{}, false
	}
	return access, true
}

func queryInt64(c *gin.Context, key string) int64 {
	parsed, _ := strconv.ParseInt(strings.TrimSpace(c.Query(key)), 10, 64)
	return parsed
}

func queryUint(c *gin.Context, key string) uint {
	parsed, _ := strconv.ParseUint(strings.TrimSpace(c.Query(key)), 10, 64)
	return uint(parsed)
}

func splitCSV(value string) []string {
	parts := strings.Split(value, ",")
	out := make([]string, 0, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part != "" {
			out = append(out, part)
		}
	}
	return out
}

func queryInt64CSV(value string) []int64 {
	parts := strings.Split(value, ",")
	out := make([]int64, 0, len(parts))
	for _, part := range parts {
		parsed, err := strconv.ParseInt(strings.TrimSpace(part), 10, 64)
		if err == nil && parsed > 0 {
			out = append(out, parsed)
		}
	}
	return out
}
