package service

import (
	"net/http"

	gin2 "github.com/UpmeshLTD/urus-aio/infrastructure/server/transport/http/gin"
	mdmpb "github.com/UpmeshLTD/urus-aio/shipment/external/mdm/pb"

	"github.com/UpmeshLTD/urus-aio/infrastructure/db/entities"
	"github.com/UpmeshLTD/urus-aio/infrastructure/server/transport/http/gin/middleware"
	"github.com/UpmeshLTD/urus-aio/shipment/server/http/dto"
	"github.com/UpmeshLTD/urus-aio/shipment/service/transform"
	"github.com/gin-gonic/gin"
)

type iPickupPoint interface {
	GetListOfPickupPoints(ctx *gin.Context)
	GetPickupPoint(ctx *gin.Context)
	CreatePickupPoint(ctx *gin.Context)
	UpdatePickupPoint(ctx *gin.Context)
	DeletePickupPoint(ctx *gin.Context)
}

// GetListOfPickupPoints godoc
// @Summary Get list of all pickup points.
// @Description Get list of all pickup points.
// @Tags PickupPoint
// @Accept */*
// @Produce json
// @Param userworkspace header string true "User workspace")
// @Param GetPickupPointsRequest query dto.GetPickupPointsRequest true "GetPickupPointsRequest"
// @Success 200 {object} dto.GetPickupPointsResponse
// @Security BearerToken
// @Router /pickup-points [GET]
func (s *serviceImpl) GetListOfPickupPoints(c *gin.Context) {
	req := &dto.GetPickupPointsRequest{}
	if err := gin2.BindData(c, req, gin2.BindType_Query); err != nil {
		gin2.ResponseBadRequest(c, err)
		return
	}

	result, total, err := s.pickupPointDomain.GetListOfPickupPoints(c, middleware.GetWorkspaceId(c), req)
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}

	gin2.ResponseSuccess(c, &dto.GetPickupPointsResponse{
		Data:  transform.ToPickupPointDTOs(result),
		Total: total,
	})
}

// GetPickupPoint godoc
// @Summary Get a pickup point.
// @Description Get a pickup point.
// @Tags PickupPoint
// @Accept */*
// @Produce json
// @Param userworkspace header string true "User workspace")
// @Param id path int true "Pickup point id"
// @Success 200 {object} dto.PickupPoint
// @Security BearerToken
// @Router /pickup-points/{id} [GET]
func (s *serviceImpl) GetPickupPoint(c *gin.Context) {
	req := &dto.GetPickupPointRequest{}
	if err := gin2.BindData(c, req, gin2.BindType_URI); err != nil {
		gin2.ResponseBadRequest(c, err)
		return
	}

	result, err := s.pickupPointDomain.GetPickupPointByID(c, middleware.GetWorkspaceId(c), entities.IDFromInt64(req.ID))
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}

	gin2.ResponseSuccess(c, transform.ToPickupPointDTO(result))
}

// CreatePickupPoint godoc
// @Summary CreatePickupPoint
// @Description Add a pickup point
// @Tags PickupPoint
// @Accept */*
// @Produce json
// @Param userworkspace header string true "User workspace")
// @Param request body dto.CreatePickupPointRequest true "CreatePickupPointRequest"
// @Success 200 {object} dto.PickupPoint
// @Security BearerToken
// @Router /pickup-points [POST]
func (s *serviceImpl) CreatePickupPoint(c *gin.Context) {
	req := &dto.CreatePickupPointRequest{}

	if err := gin2.BindData(c, &req, gin2.BindType_JSON); err != nil {
		gin2.ResponseErrorWithCode(c, http.StatusBadRequest, err)
		return
	}

	// Get country over gPRC mdm
	country, err := s.mdmClient.GetCountryByCode(c, &mdmpb.GetCountryByCodeRequest{Code: req.Address.CountryCode})
	if err != nil {
		gin2.ResponseErrorWithCode(c, http.StatusBadRequest, err)
		return
	}

	entity, err := s.pickupPointDomain.CreatePickupPoint(c, transform.CreatePickupPointRequestDTOToEntity(
		req,
		middleware.GetWorkspaceId(c),
		transform.CreateAddressRequestDTOToEntity(req.Address, country.CountryId),
	))
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}

	gin2.ResponseSuccess(c, transform.ToPickupPointDTO(entity))
}

// UpdatePickupPoint godoc
// @Summary UpdatePickupPoint
// @Description Update a pickup point
// @Tags PickupPoint
// @Accept */*
// @Produce json
// @Param userworkspace header string true "User workspace")
// @Param id path int true "Pickup point id"
// @Param request body dto.UpdatePickupPointRequest true "UpdatePickupPointRequest"
// @Success 204
// @Security BearerToken
// @Router /pickup-points/{id} [PUT]
func (s *serviceImpl) UpdatePickupPoint(c *gin.Context) {
	req := &dto.UpdatePickupPointRequest{}

	if err := gin2.BindData(c, &req, gin2.BindType_JSON, gin2.BindType_URI); err != nil {
		gin2.ResponseErrorWithCode(c, http.StatusBadRequest, err)
		return
	}

	err := s.pickupPointDomain.UpdatePickupPoint(c, middleware.GetWorkspaceId(c), entities.IDFromInt64(req.ID), transform.UpdatePickupPointRequestDTOToEntity(req))
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}

	gin2.ResponseNoContent(c)
}

// DeletePickupPoint godoc
// @Summary DeletePickupPoint
// @Description Delete a pickup point
// @Tags PickupPoint
// @Accept */*
// @Produce json
// @Param id path int true "Pickup point id"
// @Success 204
// @Security BearerToken
// @Router /pickup-points/{id} [DELETE]
func (s *serviceImpl) DeletePickupPoint(c *gin.Context) {
	req := &dto.DeletePickupPointRequest{}
	if err := gin2.BindData(c, req, gin2.BindType_URI); err != nil {
		gin2.ResponseBadRequest(c, err)
		return
	}

	err := s.pickupPointDomain.DeletePickupPoint(getCtx(c), middleware.GetWorkspaceId(c), entities.IDFromInt64(req.ID))
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}
	gin2.ResponseNoContent(c)
}
