package handlers import ( "aggios-app/backend/internal/domain" "aggios-app/backend/internal/repository" "aggios-app/backend/internal/api/middleware" "encoding/json" "log" "net/http" "github.com/google/uuid" "github.com/gorilla/mux" ) type CRMHandler struct { repo *repository.CRMRepository } func NewCRMHandler(repo *repository.CRMRepository) *CRMHandler { return &CRMHandler{repo: repo} } // ==================== CUSTOMERS ==================== func (h *CRMHandler) CreateCustomer(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) userID, _ := r.Context().Value(middleware.UserIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } var customer domain.CRMCustomer if err := json.NewDecoder(r.Body).Decode(&customer); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Invalid request body", "message": err.Error(), }) return } customer.ID = uuid.New().String() customer.TenantID = tenantID customer.CreatedBy = userID customer.IsActive = true if err := h.repo.CreateCustomer(&customer); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to create customer", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(map[string]interface{}{ "customer": customer, }) } func (h *CRMHandler) GetCustomers(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } customers, err := h.repo.GetCustomersByTenant(tenantID) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to fetch customers", "message": err.Error(), }) return } if customers == nil { customers = []domain.CRMCustomer{} } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "customers": customers, }) } func (h *CRMHandler) GetCustomer(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) customerID := vars["id"] customer, err := h.repo.GetCustomerByID(customerID, tenantID) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(map[string]string{ "error": "Customer not found", "message": err.Error(), }) return } // Buscar listas do cliente lists, _ := h.repo.GetCustomerLists(customerID) if lists == nil { lists = []domain.CRMList{} } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "customer": customer, "lists": lists, }) } func (h *CRMHandler) UpdateCustomer(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) customerID := vars["id"] var customer domain.CRMCustomer if err := json.NewDecoder(r.Body).Decode(&customer); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Invalid request body", "message": err.Error(), }) return } customer.ID = customerID customer.TenantID = tenantID if err := h.repo.UpdateCustomer(&customer); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to update customer", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "Customer updated successfully", }) } func (h *CRMHandler) DeleteCustomer(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) customerID := vars["id"] if err := h.repo.DeleteCustomer(customerID, tenantID); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to delete customer", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "Customer deleted successfully", }) } // ==================== LISTS ==================== func (h *CRMHandler) CreateList(w http.ResponseWriter, r *http.Request) { tenantIDVal := r.Context().Value(middleware.TenantIDKey) userIDVal := r.Context().Value(middleware.UserIDKey) log.Printf("🔍 CreateList DEBUG: tenantID type=%T value=%v | userID type=%T value=%v", tenantIDVal, tenantIDVal, userIDVal, userIDVal) tenantID, ok := tenantIDVal.(string) if !ok || tenantID == "" { log.Printf("❌ CreateList: Missing or invalid tenant_id") w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } userID, _ := userIDVal.(string) var list domain.CRMList if err := json.NewDecoder(r.Body).Decode(&list); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Invalid request body", "message": err.Error(), }) return } list.ID = uuid.New().String() list.TenantID = tenantID list.CreatedBy = userID if list.Color == "" { list.Color = "#3b82f6" } if err := h.repo.CreateList(&list); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to create list", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(map[string]interface{}{ "list": list, }) } func (h *CRMHandler) GetLists(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } lists, err := h.repo.GetListsByTenant(tenantID) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to fetch lists", "message": err.Error(), }) return } if lists == nil { lists = []domain.CRMListWithCustomers{} } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "lists": lists, }) } func (h *CRMHandler) GetList(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) listID := vars["id"] list, err := h.repo.GetListByID(listID, tenantID) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(map[string]string{ "error": "List not found", "message": err.Error(), }) return } // Buscar clientes da lista customers, _ := h.repo.GetListCustomers(listID, tenantID) if customers == nil { customers = []domain.CRMCustomer{} } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "list": list, "customers": customers, }) } func (h *CRMHandler) UpdateList(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) listID := vars["id"] var list domain.CRMList if err := json.NewDecoder(r.Body).Decode(&list); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Invalid request body", "message": err.Error(), }) return } list.ID = listID list.TenantID = tenantID if err := h.repo.UpdateList(&list); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to update list", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "List updated successfully", }) } func (h *CRMHandler) DeleteList(w http.ResponseWriter, r *http.Request) { tenantID, _ := r.Context().Value(middleware.TenantIDKey).(string) if tenantID == "" { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]string{ "error": "Missing tenant_id", }) return } vars := mux.Vars(r) listID := vars["id"] if err := h.repo.DeleteList(listID, tenantID); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to delete list", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "List deleted successfully", }) } // ==================== CUSTOMER <-> LIST ==================== func (h *CRMHandler) AddCustomerToList(w http.ResponseWriter, r *http.Request) { userID, _ := r.Context().Value(middleware.UserIDKey).(string) vars := mux.Vars(r) customerID := vars["customer_id"] listID := vars["list_id"] if err := h.repo.AddCustomerToList(customerID, listID, userID); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to add customer to list", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "Customer added to list successfully", }) } func (h *CRMHandler) RemoveCustomerFromList(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) customerID := vars["customer_id"] listID := vars["list_id"] if err := h.repo.RemoveCustomerFromList(customerID, listID); err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(map[string]string{ "error": "Failed to remove customer from list", "message": err.Error(), }) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]string{ "message": "Customer removed from list successfully", }) }