package proxy

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"

	"git.threefold.info/herocode/heroagent/pkg/jobsmanager"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/logger"
)

// Server represents the OpenAI proxy server
type Server struct {
	Factory *Factory
	App     *fiber.App
}

// NewServer creates a new proxy server with the given factory
func NewServer(factory *Factory) *Server {
	app := fiber.New(fiber.Config{
		ReadTimeout:  60 * time.Second,
		WriteTimeout: 60 * time.Second,
		BodyLimit:    10 * 1024 * 1024, // 10MB
	})

	// Add middleware
	app.Use(logger.New())

	server := &Server{
		Factory: factory,
		App:     app,
	}

	// Setup routes
	server.setupRoutes()

	return server
}

// setupRoutes configures all the API routes for the proxy server
func (s *Server) setupRoutes() {
	// API Routes
	api := s.App.Group("/ai")

	// Models endpoints
	api.Get("/models", s.handleModels)
	api.Get("/models/:model", s.handleGetModel)

	// Chat completions endpoint
	api.Post("/chat/completions", s.handleChatCompletions)

	// Completions endpoint
	api.Post("/completions", s.handleCompletions)

	// Embeddings endpoint
	api.Post("/embeddings", s.handleEmbeddings)

	// Images endpoints
	api.Post("/images/generations", s.handleImagesGenerations)
	api.Post("/images/edits", s.handleImagesEdits)
	api.Post("/images/variations", s.handleImagesVariations)

	// Files endpoints
	api.Get("/files", s.handleListFiles)
	api.Post("/files", s.handleUploadFile)
	api.Get("/files/:file_id", s.handleGetFile)
	api.Delete("/files/:file_id", s.handleDeleteFile)
}

// Start starts the proxy server on the configured port
func (s *Server) Start() error {
	return s.App.Listen(fmt.Sprintf(":%d", s.Factory.Config.Port))
}

// extractAPIKey extracts the API key from the Authorization header
func extractAPIKey(c *fiber.Ctx) string {
	auth := c.Get("Authorization")
	if auth == "" {
		return "" //TODO: give error, needs to be set
	}

	//TODO: why we have following???
	parts := strings.SplitN(auth, " ", 2)
	if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
		return ""
	}

	return parts[1]
}

// registerUserIfNeeded registers a new user if the API key is not already registered
func (s *Server) registerUserIfNeeded(apiKey string) {
	// Check if the user already exists
	_, err := s.Factory.GetUserConfig(apiKey)
	if err == nil {
		// User already exists, nothing to do
		return
	}

	// Create a new user configuration with default settings
	userConfig := UserConfig{
		Budget:      10000,           // Default budget
		ModelGroups: []string{"all"}, // Default access to all models
		OpenAIKey:   "",              // Empty OpenAI key means we'll use the server's default key
	}

	// Add the user to the factory
	s.Factory.AddUserConfig(apiKey, userConfig)
}

// createJob creates a new job for tracking the request
func createJob(c *fiber.Ctx, apiKey string, endpoint string, requestBody interface{}) (*jobsmanager.Job, error) {
	// Create a new job
	job := jobsmanager.NewJob()
	job.ParamsType = jobsmanager.ParamsTypeAI
	job.Topic = "openaiproxy-proxy"
	job.CircleID = "ai"

	// Serialize request body to JSON
	paramsBytes, err := json.Marshal(map[string]interface{}{
		"endpoint":   endpoint,
		"api_key":    apiKey,
		"request":    requestBody,
		"client_ip":  c.IP(),
		"user_agent": c.Get("User-Agent"),
	})
	if err != nil {
		return nil, fmt.Errorf("error serializing request: %w", err)
	}

	job.Params = string(paramsBytes)
	job.Status = jobsmanager.JobStatusActive
	job.TimeStart = time.Now().Unix()

	// Save the job to store it
	if err := job.Save(); err != nil {
		return nil, fmt.Errorf("error saving job: %w", err)
	}

	return job, nil
}

// finishJob updates the job with the result or error
func finishJob(job *jobsmanager.Job, result interface{}, err error) {
	if err != nil {
		job.Finish(jobsmanager.JobStatusError, "", err)
		return
	}

	// Serialize the result to JSON
	resultBytes, jsonErr := json.Marshal(result)
	if jsonErr != nil {
		job.Finish(jobsmanager.JobStatusError, "", jsonErr)
		return
	}

	job.Finish(jobsmanager.JobStatusDone, string(resultBytes), nil)
}

// handleModels handles GET /v1/models
func (s *Server) handleModels(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Create a job to track this request
	job, err := createJob(c, apiKey, "models.list", nil)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/models"
	if url == "/v1/models" {
		url = "https://api.openaiproxy.com/v1/models"
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Authorization", "Bearer "+s.Factory.GetOpenAIKey(apiKey))

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Parse response
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	return c.Status(resp.StatusCode).JSON(result)
}

// handleGetModel handles GET /v1/models/:model
func (s *Server) handleGetModel(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	modelID := c.Params("model")

	// Create a job to track this request
	job, err := createJob(c, apiKey, "models.get", map[string]string{
		"model_id": modelID,
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/models/" + modelID
	if strings.HasPrefix(url, "/v1/models/") {
		url = "https://api.openaiproxy.com/v1/models/" + modelID
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Authorization", "Bearer "+s.Factory.GetOpenAIKey(apiKey))

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Parse response
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	return c.Status(resp.StatusCode).JSON(result)
}

// handleChatCompletions handles POST /v1/chat/completions
func (s *Server) handleChatCompletions(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Log the raw request body for debugging
	rawBody := c.Body()
	log.Printf("Received chat completions request with API key: %s", apiKey)
	log.Printf("Raw request body: %s", string(rawBody))

	// Parse the request body
	var requestBody map[string]interface{}
	if err := json.Unmarshal(rawBody, &requestBody); err != nil {
		log.Printf("Error parsing request body: %v", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"error": "invalid request body: " + err.Error(),
		})
	}

	// Extract model from request
	model, _ := requestBody["model"].(string)

	// Check user budget and model access
	if !s.Factory.CanAccessModel(apiKey, model) {
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "access to this model is not allowed for your API key",
		})
	}

	// Create a job to track this request
	job, err := createJob(c, apiKey, "chat.completions", requestBody)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/chat/completions"
	if url == "/v1/chat/completions" {
		url = "https://api.openaiproxy.com/v1/chat/completions"
	}

	// Convert the request body back to JSON
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to marshal request body: " + err.Error(),
		})
	}

	log.Printf("Forwarding request to OpenAI at URL: %s", url)
	log.Printf("Request body being sent to OpenAI: %s", string(jsonBody))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Content-Type", "application/json")
	openaiKey := s.Factory.GetOpenAIKey(apiKey)
	req.Header.Set("Authorization", "Bearer "+openaiKey)
	log.Printf("Using OpenAI key: %s (first 5 chars)", openaiKey[:5])

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error from OpenAI: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Read the response body
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error reading response body: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error reading OpenAI response: " + err.Error(),
		})
	}

	log.Printf("Response from OpenAI (status %d): %s", resp.StatusCode, string(respBody))

	// Parse response
	var result map[string]interface{}
	if err := json.Unmarshal(respBody, &result); err != nil {
		finishJob(job, nil, err)
		log.Printf("Error parsing OpenAI response: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	// Update user budget based on usage if available
	if usage, ok := result["usage"].(map[string]interface{}); ok {
		if totalTokens, ok := usage["total_tokens"].(float64); ok {
			// For simplicity, we're using 1 token = 1 budget unit
			_ = s.Factory.DecreaseBudget(apiKey, uint32(totalTokens))
		}
	}

	return c.Status(resp.StatusCode).JSON(result)
}

// handleCompletions handles POST /v1/completions
func (s *Server) handleCompletions(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Log the raw request body for debugging
	rawBody := c.Body()
	log.Printf("Received completions request with API key: %s", apiKey)
	log.Printf("Raw request body: %s", string(rawBody))

	// Parse the request body
	var requestBody map[string]interface{}
	if err := json.Unmarshal(rawBody, &requestBody); err != nil {
		log.Printf("Error parsing request body: %v", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"error": "invalid request body: " + err.Error(),
		})
	}

	// Extract model from request
	model, _ := requestBody["model"].(string)

	// Check user budget and model access
	if !s.Factory.CanAccessModel(apiKey, model) {
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "access to this model is not allowed for your API key",
		})
	}

	// Create a job to track this request
	job, err := createJob(c, apiKey, "completions", requestBody)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/completions"
	if url == "/v1/completions" {
		url = "https://api.openaiproxy.com/v1/completions"
	}

	// Convert the request body back to JSON
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to marshal request body: " + err.Error(),
		})
	}

	log.Printf("Forwarding completions request to OpenAI at URL: %s", url)
	log.Printf("Request body being sent to OpenAI: %s", string(jsonBody))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Content-Type", "application/json")
	openaiKey := s.Factory.GetOpenAIKey(apiKey)
	req.Header.Set("Authorization", "Bearer "+openaiKey)
	log.Printf("Using OpenAI key: %s (first 5 chars)", openaiKey[:5])

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error from OpenAI: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Read the response body
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error reading response body: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error reading OpenAI response: " + err.Error(),
		})
	}

	log.Printf("Response from OpenAI (status %d): %s", resp.StatusCode, string(respBody))

	// Parse response
	var result map[string]interface{}
	if err := json.Unmarshal(respBody, &result); err != nil {
		finishJob(job, nil, err)
		log.Printf("Error parsing OpenAI response: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	// Update user budget based on usage if available
	if usage, ok := result["usage"].(map[string]interface{}); ok {
		if totalTokens, ok := usage["total_tokens"].(float64); ok {
			// For simplicity, we're using 1 token = 1 budget unit
			_ = s.Factory.DecreaseBudget(apiKey, uint32(totalTokens))
		}
	}

	return c.Status(resp.StatusCode).JSON(result)
}

// handleEmbeddings handles POST /v1/embeddings
func (s *Server) handleEmbeddings(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Log the raw request body for debugging
	rawBody := c.Body()
	log.Printf("Received embeddings request with API key: %s", apiKey)
	log.Printf("Raw request body: %s", string(rawBody))

	// Parse the request body
	var requestBody map[string]interface{}
	if err := json.Unmarshal(rawBody, &requestBody); err != nil {
		log.Printf("Error parsing request body: %v", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"error": "invalid request body: " + err.Error(),
		})
	}

	// Extract model from request
	model, _ := requestBody["model"].(string)

	// Check user budget and model access
	if !s.Factory.CanAccessModel(apiKey, model) {
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "access to this model is not allowed for your API key",
		})
	}

	// Create a job to track this request
	job, err := createJob(c, apiKey, "embeddings", requestBody)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/embeddings"
	if url == "/v1/embeddings" {
		url = "https://api.openaiproxy.com/v1/embeddings"
	}

	// Convert the request body back to JSON
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to marshal request body: " + err.Error(),
		})
	}

	log.Printf("Forwarding embeddings request to OpenAI at URL: %s", url)
	log.Printf("Request body being sent to OpenAI: %s", string(jsonBody))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Content-Type", "application/json")
	openaiKey := s.Factory.GetOpenAIKey(apiKey)
	req.Header.Set("Authorization", "Bearer "+openaiKey)
	log.Printf("Using OpenAI key: %s (first 5 chars)", openaiKey[:5])

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error from OpenAI: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Read the response body
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error reading response body: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error reading OpenAI response: " + err.Error(),
		})
	}

	log.Printf("Response from OpenAI (status %d): %s", resp.StatusCode, string(respBody))

	// Parse response
	var result map[string]interface{}
	if err := json.Unmarshal(respBody, &result); err != nil {
		finishJob(job, nil, err)
		log.Printf("Error parsing OpenAI response: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	// Update user budget based on usage if available
	if usage, ok := result["usage"].(map[string]interface{}); ok {
		if totalTokens, ok := usage["total_tokens"].(float64); ok {
			// For simplicity, we're using 1 token = 1 budget unit
			_ = s.Factory.DecreaseBudget(apiKey, uint32(totalTokens))
		}
	}

	return c.Status(resp.StatusCode).JSON(result)
}

// handleImagesGenerations handles POST /v1/images/generations
func (s *Server) handleImagesGenerations(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Log the raw request body for debugging
	rawBody := c.Body()
	log.Printf("Received images generations request with API key: %s", apiKey)
	log.Printf("Raw request body: %s", string(rawBody))

	// Parse the request body
	var requestBody map[string]interface{}
	if err := json.Unmarshal(rawBody, &requestBody); err != nil {
		log.Printf("Error parsing request body: %v", err)
		return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"error": "invalid request body: " + err.Error(),
		})
	}

	// Create a job to track this request
	job, err := createJob(c, apiKey, "images.generations", requestBody)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Check budget for image generation
	// For image generation we use a standard cost based on size and quantity
	n := 1 // Default to 1 image
	if nValue, ok := requestBody["n"].(float64); ok {
		n = int(nValue)
	}

	costPerImage := uint32(1000) // Base cost - adjust as needed
	totalCost := costPerImage * uint32(n)

	userConfig, err := s.Factory.GetUserConfig(apiKey)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "invalid API key",
		})
	}

	if userConfig.Budget < totalCost {
		finishJob(job, nil, fmt.Errorf("insufficient budget"))
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "insufficient budget for this request",
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/images/generations"
	if url == "/v1/images/generations" {
		url = "https://api.openaiproxy.com/v1/images/generations"
	}

	// Convert the request body back to JSON
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to marshal request body: " + err.Error(),
		})
	}

	log.Printf("Forwarding images generations request to OpenAI at URL: %s", url)
	log.Printf("Request body being sent to OpenAI: %s", string(jsonBody))

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Content-Type", "application/json")
	openaiKey := s.Factory.GetOpenAIKey(apiKey)
	req.Header.Set("Authorization", "Bearer "+openaiKey)
	log.Printf("Using OpenAI key: %s (first 5 chars)", openaiKey[:5])

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error from OpenAI: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Read the response body
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		finishJob(job, nil, err)
		log.Printf("Error reading response body: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error reading OpenAI response: " + err.Error(),
		})
	}

	log.Printf("Response from OpenAI (status %d): %s", resp.StatusCode, string(respBody))

	// Parse response
	var result map[string]interface{}
	if err := json.Unmarshal(respBody, &result); err != nil {
		finishJob(job, nil, err)
		log.Printf("Error parsing OpenAI response: %v", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	// Deduct the cost if successful
	if resp.StatusCode >= 200 && resp.StatusCode < 300 {
		_ = s.Factory.DecreaseBudget(apiKey, totalCost)
	}

	return c.Status(resp.StatusCode).JSON(result)
}

// handleImagesEdits handles POST /v1/images/edits
func (s *Server) handleImagesEdits(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Create a job to track this request
	job, err := createJob(c, apiKey, "images.edits", map[string]string{
		"info": "multipart form data - see raw request",
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// For this example, we'll charge a fixed amount
	costPerEdit := uint32(2000) // Base cost - adjust as needed

	userConfig, err := s.Factory.GetUserConfig(apiKey)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "invalid API key",
		})
	}

	if userConfig.Budget < costPerEdit {
		finishJob(job, nil, fmt.Errorf("insufficient budget"))
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "insufficient budget for this request",
		})
	}

	// For multipart requests, we need to handle them differently
	// This is a simplified implementation
	finishJob(job, map[string]string{"status": "processed"}, nil)

	return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{
		"error": "image edits endpoint not fully implemented in this proxy",
	})
}

// handleImagesVariations handles POST /v1/images/variations
func (s *Server) handleImagesVariations(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Create a job to track this request
	job, err := createJob(c, apiKey, "images.variations", map[string]string{
		"info": "multipart form data - see raw request",
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// For this example, we'll charge a fixed amount
	costPerVariation := uint32(1500) // Base cost - adjust as needed

	userConfig, err := s.Factory.GetUserConfig(apiKey)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "invalid API key",
		})
	}

	if userConfig.Budget < costPerVariation {
		finishJob(job, nil, fmt.Errorf("insufficient budget"))
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error": "insufficient budget for this request",
		})
	}

	// For multipart requests, we need to handle them differently
	// This is a simplified implementation
	finishJob(job, map[string]string{"status": "processed"}, nil)

	return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{
		"error": "image variations endpoint not fully implemented in this proxy",
	})
}

// handleListFiles handles GET /v1/files
func (s *Server) handleListFiles(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Create a job to track this request
	job, err := createJob(c, apiKey, "files.list", nil)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/files"
	if url == "/v1/files" {
		url = "https://api.openaiproxy.com/v1/files"
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Authorization", "Bearer "+s.Factory.GetOpenAIKey(apiKey))

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Parse response
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	return c.Status(resp.StatusCode).JSON(result)
}

// handleUploadFile handles POST /v1/files
func (s *Server) handleUploadFile(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	// Create a job to track this request
	job, err := createJob(c, apiKey, "files.upload", map[string]string{
		"info": "multipart form data - see raw request",
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// For multipart requests, we need to handle them differently
	// This is a simplified implementation
	finishJob(job, map[string]string{"status": "processed"}, nil)

	return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{
		"error": "file upload endpoint not fully implemented in this proxy",
	})
}

// handleGetFile handles GET /v1/files/:file_id
func (s *Server) handleGetFile(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	fileID := c.Params("file_id")

	// Create a job to track this request
	job, err := createJob(c, apiKey, "files.get", map[string]string{
		"file_id": fileID,
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/files/" + fileID
	if strings.HasPrefix(url, "/v1/files/") {
		url = "https://api.openaiproxy.com/v1/files/" + fileID
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Authorization", "Bearer "+s.Factory.GetOpenAIKey(apiKey))

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Parse response
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	return c.Status(resp.StatusCode).JSON(result)
}

// handleDeleteFile handles DELETE /v1/files/:file_id
func (s *Server) handleDeleteFile(c *fiber.Ctx) error {
	apiKey := extractAPIKey(c)
	if apiKey == "" {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error": "missing API key",
		})
	}

	// Register the user if they don't exist yet
	s.registerUserIfNeeded(apiKey)

	fileID := c.Params("file_id")

	// Create a job to track this request
	job, err := createJob(c, apiKey, "files.delete", map[string]string{
		"file_id": fileID,
	})
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error creating job: " + err.Error(),
		})
	}

	// Forward request to OpenAI
	url := s.Factory.Config.OpenAIBaseURL + "/v1/files/" + fileID
	if strings.HasPrefix(url, "/v1/files/") {
		url = "https://api.openaiproxy.com/v1/files/" + fileID
	}

	req, err := http.NewRequest("DELETE", url, nil)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "failed to create request: " + err.Error(),
		})
	}

	// Set headers from original request
	req.Header.Set("Authorization", "Bearer "+s.Factory.GetOpenAIKey(apiKey))

	// Perform the request
	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error from OpenAI: " + err.Error(),
		})
	}
	defer resp.Body.Close()

	// Parse response
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		finishJob(job, nil, err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": "error parsing OpenAI response: " + err.Error(),
		})
	}

	// Finish the job with the result
	finishJob(job, result, nil)

	return c.Status(resp.StatusCode).JSON(result)
}
