package handlers import ( "errors" "fmt" "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" "go.uber.org/zap" ) // CreateCompany godoc // @Summary Create a company // @Description Creates a company // @Tags company // @Accept json // @Produce json // @Param createCompany body domain.CreateCompanyReq true "Creates company" // @Success 200 {object} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/company [post] func (h *Handler) CreateCompany(c *fiber.Ctx) error { var req domain.CreateCompanyReq if err := c.BodyParser(&req); err != nil { h.mongoLoggerSvc.Info("CreateCompanyReq failed", zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.mongoLoggerSvc.Info("Failed to validate create company", zap.String("errMsg", errMsg), zap.Int("status_code", fiber.StatusBadRequest), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } user, err := h.userSvc.GetUserByID(c.Context(), req.AdminID) if err != nil { h.mongoLoggerSvc.Error("Error fetching user", zap.Int("admin_id", int(req.AdminID)), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } // Create Company Wallet newWallet, err := h.walletSvc.CreateWallet(c.Context(), domain.CreateWallet{ IsWithdraw: false, IsBettable: true, IsTransferable: true, UserID: req.AdminID, Type: domain.CompanyWalletType, }) if err != nil { h.mongoLoggerSvc.Error("Create Company Wallet failed", zap.Int64("admin", req.AdminID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } company, err := h.companySvc.CreateCompany(c.Context(), domain.CreateCompany{ Name: req.Name, AdminID: user.ID, WalletID: newWallet.ID, DeductedPercentage: req.DeductedPercentage, Slug: req.Slug, IsActive: req.IsActive, }) if err != nil { if errors.Is(err, domain.ErrWalletIDDuplicate) { h.mongoLoggerSvc.Error("CreateCompanyReq failed to create company", zap.Int64("userID", user.ID), zap.String("name", req.Name), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "this admin already has a company assigned to him") } h.mongoLoggerSvc.Error("CreateCompanyReq failed to create company", zap.Int64("userID", user.ID), zap.String("name", req.Name), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } err = h.userSvc.UpdateUserCompany(c.Context(), user.ID, company.ID) if err != nil { h.mongoLoggerSvc.Error("Failed to update user company", zap.Int64("userID", user.ID), zap.Int64("companyID", company.ID), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertCompany(company) return response.WriteJSON(c, fiber.StatusCreated, "Company Created", res, nil) } // GetAllCompanies godoc // @Summary Gets all companies // @Description Gets all companies // @Tags company // @Accept json // @Produce json // @Success 200 {array} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/company [get] func (h *Handler) GetAllCompanies(c *fiber.Ctx) error { searchQuery := c.Query("query") searchString := domain.ValidString{ Value: searchQuery, Valid: searchQuery != "", } createdBeforeQuery := c.Query("created_before") var createdBefore domain.ValidTime if createdBeforeQuery != "" { createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery) if err != nil { h.mongoLoggerSvc.Info("invalid created_before format", zap.String("createdBeforeQuery", createdBeforeQuery), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format") } createdBefore = domain.ValidTime{ Value: createdBeforeParsed, Valid: true, } } createdAfterQuery := c.Query("created_after") var createdAfter domain.ValidTime if createdAfterQuery != "" { createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery) if err != nil { h.mongoLoggerSvc.Info("invalid created_after format", zap.String("created_after", createdAfterQuery), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format") } createdAfter = domain.ValidTime{ Value: createdAfterParsed, Valid: true, } } companies, err := h.companySvc.GetAllCompanies(c.Context(), domain.CompanyFilter{ Query: searchString, CreatedBefore: createdBefore, CreatedAfter: createdAfter, }) if err != nil { h.mongoLoggerSvc.Error("Failed to get companies", zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var result []domain.GetCompanyRes = make([]domain.GetCompanyRes, 0, len(companies)) for _, company := range companies { result = append(result, domain.ConvertGetCompany(company)) } return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil) } // GetCompanyByID godoc // @Summary Gets company by id // @Description Gets a single company by id // @Tags company // @Accept json // @Produce json // @Param id path int true "Company ID" // @Success 200 {object} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/company/{id} [get] func (h *Handler) GetCompanyByID(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { h.mongoLoggerSvc.Info("Invalid company ID", zap.String("companyID", companyID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID") } company, err := h.companySvc.GetCompanyByID(c.Context(), id) if err != nil { h.mongoLoggerSvc.Error("Failed to get company by ID", zap.Int64("companyID", id), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertGetCompany(company) return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil) } // GetCompanyForAdmin godoc // @Summary Gets company by id // @Description Gets a single company by id // @Tags company // @Accept json // @Produce json // @Success 200 {object} domain.GetCompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/admin-company [get] func (h *Handler) GetCompanyForAdmin(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.mongoLoggerSvc.Error("Invalid company ID", zap.Int("status_code", fiber.StatusInternalServerError), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Invalid company ID") } company, err := h.companySvc.GetCompanyByID(c.Context(), companyID.Value) if err != nil { h.mongoLoggerSvc.Error("Failed to get company by ID", zap.Int64("companyID", companyID.Value), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } res := domain.ConvertGetCompany(company) return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil) } // GetAllCompanies godoc // @Summary Gets all companies // @Description Gets all companies // @Tags company // @Accept json // @Produce json // @Success 200 {array} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/search/company [get] func (h *Handler) SearchCompany(c *fiber.Ctx) error { searchQuery := c.Query("q") if searchQuery == "" { h.mongoLoggerSvc.Info("Search query is required", zap.Int("status_code", fiber.StatusBadRequest), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Search query is required") } companies, err := h.companySvc.SearchCompanyByName(c.Context(), searchQuery) if err != nil { h.mongoLoggerSvc.Info("Failed to get companies", zap.String("search query", searchQuery), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } var result []domain.GetCompanyRes = make([]domain.GetCompanyRes, 0, len(companies)) for _, company := range companies { result = append(result, domain.ConvertGetCompany(company)) } return response.WriteJSON(c, fiber.StatusOK, "All Companies retrieved", result, nil) } // UpdateCompany godoc // @Summary Updates a company // @Description Updates a company // @Tags company // @Accept json // @Produce json // @Param id path int true "Company ID" // @Param updateCompany body domain.UpdateCompanyReq true "Update Company" // @Success 200 {object} domain.CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/company/{id} [put] func (h *Handler) UpdateCompany(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { h.mongoLoggerSvc.Info("Invalid company ID", zap.String("companyID", companyID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID") } var req domain.UpdateCompanyReq if err := c.BodyParser(&req); err != nil { h.mongoLoggerSvc.Info("UpdateCompanyReq failed", zap.String("companyID", companyID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid request") } valErrs, ok := h.validator.Validate(c, req) if !ok { var errMsg string for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } h.mongoLoggerSvc.Info("UpdateCompanyReq failed to validate", zap.String("companyID", companyID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, errMsg) } err = h.companySvc.UpdateCompany(c.Context(), domain.ConvertUpdateCompanyReq(req, id)) if err != nil { h.mongoLoggerSvc.Error("Failed to update company", zap.Int64("companyID", id), zap.Any("req", req), zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Company Updated", nil, nil) } // DeleteCompany godoc // @Summary Delete the company // @Description Delete the company // @Tags company // @Accept json // @Produce json // @Param id path int true "Company ID"" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/company/{id} [delete] func (h *Handler) DeleteCompany(c *fiber.Ctx) error { companyID := c.Params("id") id, err := strconv.ParseInt(companyID, 10, 64) if err != nil { h.mongoLoggerSvc.Info("Invalid Company ID", zap.String("companyID", companyID), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusBadRequest, "Invalid Company ID") } err = h.companySvc.DeleteCompany(c.Context(), id) if err != nil { h.mongoLoggerSvc.Info("Failed to delete by ID", zap.Int64("Company ID", id), zap.Int("status_code", fiber.StatusBadRequest), zap.Error(err), zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } return response.WriteJSON(c, fiber.StatusOK, "Company removed successfully", nil, nil) }