package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/gorilla/mux"
	"golang.org/x/crypto/bcrypt"
)

// GetUsersHandler handles GET requests to /admin/user
func GetUsersHandler(w http.ResponseWriter, r *http.Request) {
	var users []User
	db.Find(&users)
	json.NewEncoder(w).Encode(users)
}

// CreateUserHandler handles POST requests to /admin/user
func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
	var user User
	err := json.NewDecoder(r.Body).Decode(&user)
	if err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	// Hash the password before storing
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
	if err != nil {
		http.Error(w, "Failed to hash password", http.StatusInternalServerError)
		return
	}
	user.Password = string(hashedPassword)

	db.Create(&user)
	json.NewEncoder(w).Encode(user)
}

// GetUserHandler handles GET requests to /admin/user/{id}
func GetUserHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["id"]
	var user User
	db.First(&user, id)
	if user.ID == 0 {
		http.Error(w, "User not found", http.StatusNotFound)
		return
	}
	json.NewEncoder(w).Encode(user)
}

// DeleteUserHandler handles DELETE requests to /admin/user/{id}
func DeleteUserHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id := vars["id"]
	var user User
	db.First(&user, id)
	if user.ID == 0 {
		http.Error(w, "User not found", http.StatusNotFound)
		return
	}
	db.Delete(&user)
	w.WriteHeader(http.StatusNoContent)
}

// BackupDatabaseHandler handles GET requests to /admin/db
func BackupDatabaseHandler(w http.ResponseWriter, r *http.Request) {
	// ...
	fmt.Println("BackupDatabaseHandler called")
	// Open the database file using the path from the config
	file, err := os.Open(config.DatabasePath)
	if err != nil {
		http.Error(w, "Failed to open database file", http.StatusInternalServerError)
		return
	}
	defer file.Close()

	// Copy the file to the response writer
	_, err = io.Copy(w, file)
	if err != nil {
		http.Error(w, "Failed to send database file", http.StatusInternalServerError)
		return
	}
}

// RestoreDatabaseHandler handles POST requests to /admin/db
func RestoreDatabaseHandler(w http.ResponseWriter, r *http.Request) {
	// Create a backup of the existing database
	err := createDatabaseBackup()
	if err != nil {
		http.Error(w, "Failed to create database backup", http.StatusInternalServerError)
		return
	}

	// Save the new database
	err = saveNewDatabase(r)
	if err != nil {
		http.Error(w, "Failed to save new database", http.StatusInternalServerError)
		return
	}

	// Validate the new database is properly initialized
	err = validateNewDatabase()
	if err != nil {
		http.Error(w, "New database is not properly initialized", http.StatusInternalServerError)
		return
	}

	// Switch to the new database app-wide
	err = switchToNewDatabase()
	if err != nil {
		http.Error(w, "Failed to switch to new database", http.StatusInternalServerError)
		return
	}
	fmt.Println("Database restored successfully")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"message": "Database restored successfully"})
}

func createDatabaseBackup() error {
	// Create a backup of the existing database
	src, err := os.Open(config.DatabasePath)
	if err != nil {
		return err
	}
	defer src.Close()

	dst, err := os.Create(config.DatabasePath + ".bak")
	if err != nil {
		return err
	}
	defer dst.Close()

	_, err = io.Copy(dst, src)
	return err
}

func saveNewDatabase(r *http.Request) error {
	// Save the new database
	file, _, err := r.FormFile("database")
	if err != nil {
		return err
	}
	defer file.Close()

	dst, err := os.Create(config.DatabasePath)
	if err != nil {
		return err
	}
	defer dst.Close()

	_, err = io.Copy(dst, file)
	return err
}

func validateNewDatabase() error {
	// Validate the new database is properly initialized
	db, err := ConnectDB(config.DatabasePath)
	if err != nil {
		return err
	}
	defer db.Close()

	// Check if required tables exist
	tables := []string{"users", "boxes", "items"}
	for _, table := range tables {
		var count int
		db.Debug().Raw("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=?;", table).Row().Scan(&count)
		if count == 0 {
			return fmt.Errorf("table %s does not exist", table)
		}
	}

	return nil
}

func switchToNewDatabase() error {
	// Switch to the new database app-wide
	db, err := ConnectDB(config.DatabasePath)
	if err != nil {
		return err
	}
	// Update the db variable with the new database connection
	db = db
	return nil
}
