package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"path/filepath"

	"github.com/gorilla/mux"
	"github.com/jinzhu/gorm"
	"github.com/rs/cors"
)

var (
	db     *gorm.DB // Declare db globally
	config *Config
)

func main() {

	configFile := os.Getenv("BOXES_API_CONFIG")
	var err error
	config, err = LoadConfig(configFile)

	// get the static files directory
	staticPath := config.StaticFilesDir	 

		// Add this before setting up the handler
	if _, err := os.Stat(staticPath); os.IsNotExist(err) {
		log.Fatalf("Static directory does not exist: %s", staticPath)
	}

	// Get the allowed origins from the ALLOWED_ORIGINS environment variable
	// If empty, defaults to http://localhost:3000
	allowedOrigins := config.AllowedOrigins
	fmt.Println("Allowed origins: ", allowedOrigins)
	origins := []string{"http://localhost:3000"} // Default value

	if allowedOrigins != "" {
		// Split the comma-separated string into a slice of strings
		origins = strings.Split(allowedOrigins, ",")
		fmt.Println("Listening for connections from: ", origins)
	}

	// check for errors
	if err != nil || config == nil {
		log.Fatalf("Failed to load config: %v", err)
	}

	fmt.Println(config.DatabasePath)
	fmt.Println(config.ImageStorageDir)
	fmt.Println(config.JWTSecret)
	fmt.Println(config.LogFile)
	fmt.Println(config.ListeningPort)

	// Connect to the database
	db, err = ConnectDB(config.DatabasePath)
	if err != nil || db == nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer db.Close()

	// Modify your custom handler to include more detailed logging
	customHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Printf("Attempting to serve: %s from directory: %s", r.URL.Path, staticPath)
		fullPath := filepath.Join(staticPath, r.URL.Path)
		if _, err := os.Stat(fullPath); os.IsNotExist(err) {
			log.Printf("File not found: %s", fullPath)
			http.NotFound(w, r)
			return
		}
		http.FileServer(http.Dir(staticPath)).ServeHTTP(w, r)
	})

	fmt.Println("Default user 'boxuser' created successfully!")

	// Create the router
	baseRouter := mux.NewRouter()

	router := baseRouter.PathPrefix("/api/v1").Subrouter()
	staticRouter := baseRouter.PathPrefix("/").Subrouter()

	// Define your routes
	router.Handle("/login", http.HandlerFunc(LoginHandler)).Methods("POST", "OPTIONS")
	router.Handle("/boxes", AuthMiddleware(http.HandlerFunc(GetBoxesHandler))).Methods("GET", "OPTIONS")
	router.Handle("/boxes", AuthMiddleware(http.HandlerFunc(CreateBoxHandler))).Methods("POST", "OPTIONS")
	router.Handle("/boxes/{id}", AuthMiddleware(http.HandlerFunc(DeleteBoxHandler))).Methods("DELETE", "OPTIONS")
	router.Handle("/boxes/{id}", AuthMiddleware(http.HandlerFunc(GetBoxHandler))).Methods("GET", "OPTIONS")
	router.Handle("/items", AuthMiddleware(http.HandlerFunc(GetItemsHandler))).Methods("GET", "OPTIONS")
	router.Handle("/items", AuthMiddleware(http.HandlerFunc(CreateItemHandler))).Methods("POST", "OPTIONS")
	router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(GetItemHandler))).Methods("GET", "OPTIONS")
	router.Handle("/boxes/{id}/items", AuthMiddleware(http.HandlerFunc(GetItemsInBoxHandler))).Methods("GET", "OPTIONS")
	router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(UpdateItemHandler))).Methods("PUT", "OPTIONS")
	router.Handle("/items/{id}", AuthMiddleware(http.HandlerFunc(DeleteItemHandler))).Methods("DELETE", "OPTIONS")
	router.Handle("/items/{id}/image", AuthMiddleware(http.HandlerFunc(GetItemImageHandler))).Methods("GET", "OPTIONS")
	fmt.Println("Registering route for search items...")
	router.Handle("/search/items", AuthMiddleware(http.HandlerFunc(SearchItemsHandler))).Methods("GET", "OPTIONS")
	// Add a new route for uploading an image with AuthMiddleware
	router.HandleFunc("/items/{id}/upload", UploadItemImageHandler).
		Methods("POST").
		Handler(AuthMiddleware(http.HandlerFunc(UploadItemImageHandler)))

	managementRouter := router.PathPrefix("/admin").Subrouter()
	managementRouter.Use(AuthMiddleware)

	managementRouter.Handle("/user", http.HandlerFunc(GetUsersHandler)).Methods("GET", "OPTIONS")
	managementRouter.Handle("/user", http.HandlerFunc(CreateUserHandler)).Methods("POST", "OPTIONS")
	managementRouter.Handle("/user/{id}", http.HandlerFunc(GetUserHandler)).Methods("GET", "OPTIONS")
	managementRouter.Handle("/user/{id}", http.HandlerFunc(DeleteUserHandler)).Methods("DELETE", "OPTIONS")
	managementRouter.Handle("/db", http.HandlerFunc(BackupDatabaseHandler)).Methods("GET", "OPTIONS")
	managementRouter.Handle("/db", http.HandlerFunc(RestoreDatabaseHandler)).Methods("POST", "OPTIONS")

	// Define a route for serving static files
	fmt.Println("Serving static files from:", staticPath)
    //staticHandler := http.FileServer(http.Dir(staticPath))
	fmt.Println("Registering route for serving static files, no StripPrefix")
    //staticRouter.HandleFunc("/", customHandler).Methods("GET", "OPTIONS")
	// perplexity recommends:
	staticRouter.PathPrefix("/").Handler(http.StripPrefix("/", customHandler))

	
	// Apply CORS middleware
	c := cors.New(cors.Options{
		AllowedOrigins:   origins,
		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowedHeaders:   []string{"Authorization", "Content-Type"},
		ExposedHeaders:   []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma", "ETag"},
		AllowCredentials: true,
	})

	// Start the server with CORS middleware
	fmt.Printf("Server listening on port %d\n", config.ListeningPort)
	http.ListenAndServe(fmt.Sprintf(":%d", config.ListeningPort), c.Handler(baseRouter))
}
