package handler

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/service"
	"apskel-pos-be/internal/transformer"
	"apskel-pos-be/internal/util"

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

type AnalyticsHandler struct {
	analyticsService service.AnalyticsService
	transformer      transformer.Transformer
}

func NewAnalyticsHandler(
	analyticsService service.AnalyticsService,
	transformer transformer.Transformer,
) *AnalyticsHandler {
	return &AnalyticsHandler{
		analyticsService: analyticsService,
		transformer:      transformer,
	}
}

func (h *AnalyticsHandler) GetPaymentMethodAnalytics(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.PaymentMethodAnalyticsRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetPaymentMethodAnalytics", err.Error())}), "AnalyticsHandler::GetPaymentMethodAnalytics")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	req.OutletID = &contextInfo.OutletID
	modelReq := transformer.PaymentMethodAnalyticsContractToModel(&req)

	response, err := h.analyticsService.GetPaymentMethodAnalytics(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetPaymentMethodAnalytics", err.Error())}), "AnalyticsHandler::GetPaymentMethodAnalytics")
		return
	}

	contractResp := transformer.PaymentMethodAnalyticsModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetPaymentMethodAnalytics")
}

func (h *AnalyticsHandler) GetSalesAnalytics(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.SalesAnalyticsRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetSalesAnalytics", err.Error())}), "AnalyticsHandler::GetSalesAnalytics")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	req.OutletID = &contextInfo.OutletID
	modelReq := transformer.SalesAnalyticsContractToModel(&req)

	response, err := h.analyticsService.GetSalesAnalytics(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetSalesAnalytics", err.Error())}), "AnalyticsHandler::GetSalesAnalytics")
		return
	}

	contractResp := transformer.SalesAnalyticsModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetSalesAnalytics")
}

func (h *AnalyticsHandler) GetProductAnalytics(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.ProductAnalyticsRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProductAnalytics", err.Error())}), "AnalyticsHandler::GetProductAnalytics")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	req.OutletID = &contextInfo.OutletID
	modelReq := transformer.ProductAnalyticsContractToModel(&req)

	response, err := h.analyticsService.GetProductAnalytics(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProductAnalytics", err.Error())}), "AnalyticsHandler::GetProductAnalytics")
		return
	}

	contractResp := transformer.ProductAnalyticsModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalytics")
}

func (h *AnalyticsHandler) GetProductAnalyticsPerCategory(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.ProductAnalyticsPerCategoryRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	req.OutletID = &contextInfo.OutletID
	modelReq := transformer.ProductAnalyticsPerCategoryContractToModel(&req)

	response, err := h.analyticsService.GetProductAnalyticsPerCategory(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProductAnalyticsPerCategory", err.Error())}), "AnalyticsHandler::GetProductAnalyticsPerCategory")
		return
	}

	contractResp := transformer.ProductAnalyticsPerCategoryModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalyticsPerCategory")
}

func (h *AnalyticsHandler) GetDashboardAnalytics(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.DashboardAnalyticsRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetDashboardAnalytics", err.Error())}), "AnalyticsHandler::GetDashboardAnalytics")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	req.OutletID = &contextInfo.OutletID
	modelReq := transformer.DashboardAnalyticsContractToModel(&req)

	response, err := h.analyticsService.GetDashboardAnalytics(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetDashboardAnalytics", err.Error())}), "AnalyticsHandler::GetDashboardAnalytics")
		return
	}

	contractResp := transformer.DashboardAnalyticsModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetDashboardAnalytics")
}

func (h *AnalyticsHandler) GetProfitLossAnalytics(c *gin.Context) {
	ctx := c.Request.Context()
	contextInfo := appcontext.FromGinContext(ctx)

	var req contract.ProfitLossAnalyticsRequest
	if err := c.ShouldBindQuery(&req); err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
		return
	}

	req.OrganizationID = contextInfo.OrganizationID
	modelReq, err := transformer.ProfitLossAnalyticsContractToModel(&req)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
		return
	}

	// Call service
	response, err := h.analyticsService.GetProfitLossAnalytics(ctx, modelReq)
	if err != nil {
		util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
		return
	}

	// Transform model to contract
	contractResp := transformer.ProfitLossAnalyticsModelToContract(response)
	util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProfitLossAnalytics")
}
