package handlers import ( "encoding/json" "log" "net/http" "aggios-app/backend/internal/api/middleware" "aggios-app/backend/internal/service" "github.com/google/uuid" ) // TenantHandler handles tenant/agency listing endpoints type TenantHandler struct { tenantService *service.TenantService } // NewTenantHandler creates a new tenant handler func NewTenantHandler(tenantService *service.TenantService) *TenantHandler { return &TenantHandler{ tenantService: tenantService, } } // ListAll lists all agencies/tenants (SUPERADMIN only) func (h *TenantHandler) ListAll(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } tenants, err := h.tenantService.ListAllWithDetails() if err != nil { log.Printf("Error listing tenants with details: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } if tenants == nil { tenants = []map[string]interface{}{} } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(tenants) } // CheckExists returns 200 if tenant exists by subdomain, otherwise 404 func (h *TenantHandler) CheckExists(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } subdomain := r.URL.Query().Get("subdomain") if subdomain == "" { http.Error(w, "subdomain is required", http.StatusBadRequest) return } _, err := h.tenantService.GetBySubdomain(subdomain) if err != nil { if err == service.ErrTenantNotFound { http.NotFound(w, r) return } http.Error(w, "Internal server error", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) } // GetPublicConfig returns public branding info for a tenant by subdomain func (h *TenantHandler) GetPublicConfig(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } subdomain := r.URL.Query().Get("subdomain") if subdomain == "" { http.Error(w, "subdomain is required", http.StatusBadRequest) return } tenant, err := h.tenantService.GetBySubdomain(subdomain) if err != nil { if err == service.ErrTenantNotFound { http.NotFound(w, r) return } http.Error(w, "Internal server error", http.StatusInternalServerError) return } // Return only public info response := map[string]interface{}{ "id": tenant.ID.String(), "name": tenant.Name, "primary_color": tenant.PrimaryColor, "secondary_color": tenant.SecondaryColor, "logo_url": tenant.LogoURL, "logo_horizontal_url": tenant.LogoHorizontalURL, } log.Printf("📤 Returning tenant config for %s: logo_url=%s", subdomain, tenant.LogoURL) w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(response) } // GetBranding returns branding info for the current authenticated tenant func (h *TenantHandler) GetBranding(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // Get tenant from context (set by auth middleware) tenantID := r.Context().Value(middleware.TenantIDKey) if tenantID == nil { http.Error(w, "Tenant not found in context", http.StatusUnauthorized) return } // Parse tenant ID tid, err := uuid.Parse(tenantID.(string)) if err != nil { http.Error(w, "Invalid tenant ID", http.StatusBadRequest) return } // Get tenant from database tenant, err := h.tenantService.GetByID(tid) if err != nil { http.Error(w, "Error fetching branding", http.StatusInternalServerError) return } // Return branding info response := map[string]interface{}{ "id": tenant.ID.String(), "name": tenant.Name, "primary_color": tenant.PrimaryColor, "secondary_color": tenant.SecondaryColor, "logo_url": tenant.LogoURL, "logo_horizontal_url": tenant.LogoHorizontalURL, } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(response) } // GetProfile returns public tenant information by tenant ID func (h *TenantHandler) GetProfile(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // Extract tenant ID from URL path // URL format: /api/tenants/{id}/profile tenantIDStr := r.URL.Path[len("/api/tenants/"):] if idx := len(tenantIDStr) - len("/profile"); idx > 0 { tenantIDStr = tenantIDStr[:idx] } if tenantIDStr == "" { http.Error(w, "tenant_id is required", http.StatusBadRequest) return } // Para compatibilidade, aceitar tanto UUID quanto ID numérico // Primeiro tentar como UUID, se falhar buscar tenant diretamente tenant, err := h.tenantService.GetBySubdomain(tenantIDStr) if err != nil { log.Printf("Error getting tenant: %v", err) http.Error(w, "Tenant not found", http.StatusNotFound) return } // Return public info response := map[string]interface{}{ "tenant": map[string]string{ "company": tenant.Name, "primary_color": tenant.PrimaryColor, "secondary_color": tenant.SecondaryColor, "logo_url": tenant.LogoURL, "logo_horizontal_url": tenant.LogoHorizontalURL, }, } w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(response) }