package history_admin

import (
	"fmt"
	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository"
	codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword"
)

type Deps struct {
	MiddleWare     *http.MiddleWare
	HistoryRepo    *repository.HistoryRepository
	AccountRepo    *repository.AccountRepository
	VerifyClient   *client.VerificationClient
	AuthClient     *client.AuthClient
	TemplateClient *client.TemplateClient
	CodewordClient *client.CodewordClient
	Logger         *zap.Logger
}

type HistoryController struct {
	middleWare     *http.MiddleWare
	historyRepo    *repository.HistoryRepository
	accountRepo    *repository.AccountRepository
	verifyClient   *client.VerificationClient
	authClient     *client.AuthClient
	templateClient *client.TemplateClient
	codewordClient *client.CodewordClient
	logger         *zap.Logger
}

func NewHistoryController(deps Deps) *HistoryController {
	return &HistoryController{
		middleWare:     deps.MiddleWare,
		historyRepo:    deps.HistoryRepo,
		authClient:     deps.AuthClient,
		accountRepo:    deps.AccountRepo,
		verifyClient:   deps.VerifyClient,
		templateClient: deps.TemplateClient,
		codewordClient: deps.CodewordClient,
		logger:         deps.Logger,
	}
}

func (receiver *HistoryController) CalculateLTV(ctx *fiber.Ctx) error {
	var req struct {
		From int64 `json:"from"`
		To   int64 `json:"to"`
	}

	if err := ctx.BodyParser(&req); err != nil {
		receiver.logger.Error("failed to bind request", zap.Error(err))
		return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
	}

	if req.From > req.To && req.To != 0 {
		receiver.logger.Error("From timestamp must be less than To timestamp unless To is 0")
		return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0")
	}

	ltv, err := receiver.historyRepo.CalculateCustomerLTV(ctx.Context(), req.From, req.To)
	if err != nil {
		receiver.logger.Error("failed to calculate LTV", zap.Error(err))
		return receiver.middleWare.ErrorOld(ctx, err)
	}

	response := struct {
		LTV int64 `json:"LTV"`
	}{
		LTV: ltv,
	}

	return ctx.Status(fiber.StatusOK).JSON(response)
}

func (receiver *HistoryController) QuizLogoStat(ctx *fiber.Ctx) error {
	var req struct {
		From  *int `json:"from,omitempty"`
		Limit *int `json:"limit,omitempty"`
		Page  *int `json:"page,omitempty"`
		To    *int `json:"to,omitempty"`
	}

	if err := ctx.BodyParser(&req); err != nil {
		receiver.logger.Error("failed to bind request", zap.Error(err))
		return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
	}

	result, err := receiver.accountRepo.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{
		Page:  req.Page,
		Limit: req.Limit,
		From:  req.From,
		To:    req.To,
	})
	if err != nil {
		return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error()))
	}

	return ctx.Status(fiber.StatusOK).JSON(result)
}

func (receiver *HistoryController) PromocodeLTV(ctx *fiber.Ctx) error {
	var req struct {
		From int `json:"from"`
		To   int `json:"to"`
	}

	if err := ctx.BodyParser(&req); err != nil {
		receiver.logger.Error("failed to bind request", zap.Error(err))
		return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request")
	}

	// получаем мапу вида [promoID] = []{userid,timeActivate}
	// отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним
	// если в запросе время различается с временем активации - если меньше, то учитывается только после применения
	// если больше, то учитывается только с начала переданного from
	codewordData, err := receiver.codewordClient.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{
		To:   int64(req.To),
		From: int64(req.From),
	})

	if err != nil {
		return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error()))
	}

	userSumMap, er := receiver.historyRepo.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To))
	if er != nil {
		return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error()))
	}

	resp := make(map[string]struct {
		Regs  int
		Money int64
	})

	for promoID, data := range codewordData {
		fmt.Println("PROTOMOTO", promoID, data)
		for _, value := range data {

			paids, ok := userSumMap[value.UserID]
			if !ok {
				paids = 0
			}
			fmt.Println("PROTOMOTO1", paids, value)

			if value.Time >= int64(req.From) && value.Time <= int64(req.To) {
				if _, ok := resp[promoID]; !ok {
					resp[promoID] = struct {
						Regs  int
						Money int64
					}{Regs: 1, Money: paids}
					continue
				}
				current := resp[promoID]
				current.Regs += 1
				current.Money += paids
				resp[promoID] = current
			}
		}
	}

	return ctx.Status(fiber.StatusOK).JSON(resp)
}
