package history

import (
	"fmt"
	"log"
	"net/http"

	"github.com/labstack/echo/v4"
	"go.uber.org/zap"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
	"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
)

type Deps struct {
	Logger         *zap.Logger
	HistoryService *history.Service
}

type Controller struct {
	logger         *zap.Logger
	historyService *history.Service
}

func New(deps Deps) *Controller {
	if deps.Logger == nil {
		log.Panicln("logger is nil on <New (history controller)>")
	}

	if deps.HistoryService == nil {
		log.Panicln("HistoryService is nil on <New (history controller)>")
	}

	return &Controller{
		logger:         deps.Logger,
		historyService: deps.HistoryService,
	}
}

func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetHistoryParams) error {
	var userID string

	if params.AccountID != nil && *params.AccountID != "" {
		userID = *params.AccountID
	} else {
		userID, _ = ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
	}

	histories, err := receiver.historyService.GetHistoryList(ctx.Request().Context(), &history.GetHistories{
		Type:   params.Type,
		UserID: userID,
		Pagination: &models.Pagination{
			Page:  int64(*params.Page),
			Limit: int64(*params.Limit),
		},
	})
	if err != nil {
		receiver.logger.Error("failed to get histories on <GetHistoryList> of <HistoryController>", zap.Error(err))
		return errors.HTTP(ctx, err)
	}

	return ctx.JSON(http.StatusOK, histories)
}

// TODO:tests.
func (receiver *Controller) GetRecentTariffs(ctx echo.Context) error {
	userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
	if !ok {
		receiver.logger.Error("failed to convert jwt payload to string on <GetRecentTariffs> of <HistoryController>")
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to convert jwt payload to string: %s", userID),
			errors.ErrInvalidArgs,
		))
	}

	tariffs, err := receiver.historyService.GetRecentTariffs(ctx.Request().Context(), userID)
	if err != nil {
		receiver.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <HistoryController>",
			zap.String("userId", userID),
			zap.Error(err),
		)
		return errors.HTTP(ctx, err)
	}

	return ctx.JSON(http.StatusOK, tariffs)
}

// TODO:tests.
func (receiver *Controller) SendReport(ctx echo.Context) error {
	historyID := ctx.Param("id")

	err := receiver.historyService.GetHistoryByID(ctx.Request().Context(), historyID)
	if err != nil {
		receiver.logger.Error("failed to send report on <SendReport> of <HistoryController>", zap.Error(err))
		return errors.HTTP(ctx, err)
	}

	return ctx.NoContent(http.StatusOK)
}

// TODO:tests.
func (receiver *Controller) CalculateLTV(ctx echo.Context) error {
	var req swagger.CalculateLTVJSONBody

	if err := ctx.Bind(&req); err != nil {
		receiver.logger.Error("failed to bind request", zap.Error(err))
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("failed to bind request: %s", err),
			errors.ErrInvalidArgs,
		))
	}

	if req.From > req.To && req.To != 0 {
		receiver.logger.Error("From timestamp must be less than To timestamp unless To is 0")
		return errors.HTTP(ctx, errors.New(
			fmt.Errorf("From timestamp must be less than To timestamp unless To is 0"),
			errors.ErrInvalidArgs,
		))
	}

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

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

	return ctx.JSON(http.StatusOK, response)
}
