package handlers

import (
	"net/http"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"

	"gobsidian/internal/utils"
)

func (h *Handlers) SettingsPageHandler(c *gin.Context) {
	notesTree, err := utils.BuildTreeStructure(h.config.NotesDir, h.config.NotesDirHideSidepane, h.config)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error", gin.H{
			"error":           "Failed to build tree structure",
			"app_name":        h.config.AppName,
			"message":         err.Error(),
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	c.HTML(http.StatusOK, "settings", gin.H{
		"app_name":        h.config.AppName,
		"notes_tree":      notesTree,
		"active_path":     []string{},
		"current_note":    nil,
		"breadcrumbs":     utils.GenerateBreadcrumbs(""),
		"Authenticated":   isAuthenticated(c),
		"IsAdmin":         isAdmin(c),
		"ContentTemplate": "settings_content",
		"ScriptsTemplate": "settings_scripts",
		"Page":            "settings",
	})
}

func (h *Handlers) GetImageStorageSettingsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"mode":      h.config.ImageStorageMode,
		"path":      h.config.ImageStoragePath,
		"subfolder": h.config.ImageSubfolderName,
	})
}

func (h *Handlers) PostImageStorageSettingsHandler(c *gin.Context) {
	modeStr := c.PostForm("storage_mode")
	path := strings.TrimSpace(c.PostForm("storage_path"))
	subfolder := strings.TrimSpace(c.PostForm("subfolder_name"))

	mode, err := strconv.Atoi(modeStr)
	if err != nil || mode < 1 || mode > 4 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid storage mode"})
		return
	}

	// Validate path for mode 2
	if mode == 2 && path == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Storage path is required for mode 2"})
		return
	}

	// Validate subfolder name for mode 4
	if mode == 4 && subfolder == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Subfolder name is required for mode 4"})
		return
	}

	// Save settings
	if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_STORAGE_MODE", modeStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save storage mode"})
		return
	}

	if mode == 2 {
		if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_STORAGE_PATH", path); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save storage path"})
			return
		}
	}

	if mode == 4 {
		if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGE_SUBFOLDER_NAME", subfolder); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save subfolder name"})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"success":         true,
		"message":         "Image storage settings updated successfully",
		"reload_required": true,
	})
}

func (h *Handlers) GetNotesDirSettingsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"notes_dir": h.config.NotesDir,
	})
}

func (h *Handlers) PostNotesDirSettingsHandler(c *gin.Context) {
	newDir := strings.TrimSpace(c.PostForm("notes_dir"))
	if newDir == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Notes directory is required"})
		return
	}

	// Convert to absolute path
	if !filepath.IsAbs(newDir) {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Please provide an absolute path"})
		return
	}

	// Ensure directory exists
	if err := utils.EnsureDir(newDir); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create directory: " + err.Error()})
		return
	}

	// Save setting
	if err := h.config.SaveSetting("MD_NOTES_APP", "NOTES_DIR", newDir); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save notes directory"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":         true,
		"message":         "Notes directory updated successfully",
		"reload_required": true,
	})
}

func (h *Handlers) GetFileExtensionsSettingsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"allowed_image_extensions": strings.Join(h.config.AllowedImageExtensions, ", "),
		"allowed_file_extensions":  strings.Join(h.config.AllowedFileExtensions, ", "),
		"images_hide":              h.config.ImagesHide,
		"show_images_in_tree":      h.config.ShowImagesInTree,
		"show_files_in_tree":       h.config.ShowFilesInTree,
		"show_images_in_folder":    h.config.ShowImagesInFolder,
		"show_files_in_folder":     h.config.ShowFilesInFolder,
	})
}

func (h *Handlers) PostFileExtensionsSettingsHandler(c *gin.Context) {
	imageExtensions := strings.TrimSpace(c.PostForm("allowed_image_extensions"))
	fileExtensions := strings.TrimSpace(c.PostForm("allowed_file_extensions"))
	imagesHide := c.PostForm("images_hide") == "true" || c.PostForm("images_hide") == "on"
	showImagesInTree := c.PostForm("show_images_in_tree") == "true" || c.PostForm("show_images_in_tree") == "on"
	showFilesInTree := c.PostForm("show_files_in_tree") == "true" || c.PostForm("show_files_in_tree") == "on"
	showImagesInFolder := c.PostForm("show_images_in_folder") == "true" || c.PostForm("show_images_in_folder") == "on"
	showFilesInFolder := c.PostForm("show_files_in_folder") == "true" || c.PostForm("show_files_in_folder") == "on"

	// Save settings
	if err := h.config.SaveSetting("MD_NOTES_APP", "ALLOWED_IMAGE_EXTENSIONS", imageExtensions); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save image extensions"})
		return
	}

	if err := h.config.SaveSetting("MD_NOTES_APP", "ALLOWED_FILE_EXTENSIONS", fileExtensions); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file extensions"})
		return
	}

	imagesHideStr := "false"
	if imagesHide {
		imagesHideStr = "true"
	}
	if err := h.config.SaveSetting("MD_NOTES_APP", "IMAGES_HIDE", imagesHideStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save images hide setting"})
		return
	}

	if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_IMAGES_IN_TREE", boolToStr(showImagesInTree)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_IMAGES_IN_TREE"})
		return
	}
	if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_FILES_IN_TREE", boolToStr(showFilesInTree)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_FILES_IN_TREE"})
		return
	}
	if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_IMAGES_IN_FOLDER", boolToStr(showImagesInFolder)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_IMAGES_IN_FOLDER"})
		return
	}
	if err := h.config.SaveSetting("MD_NOTES_APP", "SHOW_FILES_IN_FOLDER", boolToStr(showFilesInFolder)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save SHOW_FILES_IN_FOLDER"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":         true,
		"message":         "File extension settings updated successfully",
		"reload_required": true,
	})
}

func boolToStr(b bool) string {
	if b {
		return "true"
	}
	return "false"
}

// --- Security (IP Ban & Thresholds) Settings ---

// GetSecuritySettingsHandler returns current security-related config
func (h *Handlers) GetSecuritySettingsHandler(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"pwd_failures_threshold":  h.config.PwdFailuresThreshold,
		"mfa_failures_threshold":  h.config.MFAFailuresThreshold,
		"failures_window_minutes": h.config.FailuresWindowMinutes,
		"auto_ban_duration_hours": h.config.AutoBanDurationHours,
		"auto_ban_permanent":      h.config.AutoBanPermanent,
	})
}

// PostSecuritySettingsHandler validates and saves security-related config
func (h *Handlers) PostSecuritySettingsHandler(c *gin.Context) {
	pwdStr := strings.TrimSpace(c.PostForm("pwd_failures_threshold"))
	mfaStr := strings.TrimSpace(c.PostForm("mfa_failures_threshold"))
	winStr := strings.TrimSpace(c.PostForm("failures_window_minutes"))
	durStr := strings.TrimSpace(c.PostForm("auto_ban_duration_hours"))
	permStr := strings.TrimSpace(c.PostForm("auto_ban_permanent"))

	// basic validation
	if pwdStr == "" || mfaStr == "" || winStr == "" || durStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "All numeric fields are required"})
		return
	}
	if _, err := strconv.Atoi(pwdStr); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid password failures threshold"})
		return
	}
	if _, err := strconv.Atoi(mfaStr); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid MFA failures threshold"})
		return
	}
	if _, err := strconv.Atoi(winStr); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid failures window (minutes)"})
		return
	}
	if _, err := strconv.Atoi(durStr); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid auto-ban duration (hours)"})
		return
	}

	// normalize perm
	perm := strings.EqualFold(permStr, "true") || permStr == "1" || strings.EqualFold(permStr, "on")
	permStr = boolToStr(perm)

	// Save values
	if err := h.config.SaveSetting("SECURITY", "PWD_FAILURES_THRESHOLD", pwdStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save PWD_FAILURES_THRESHOLD"})
		return
	}
	if err := h.config.SaveSetting("SECURITY", "MFA_FAILURES_THRESHOLD", mfaStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save MFA_FAILURES_THRESHOLD"})
		return
	}
	if err := h.config.SaveSetting("SECURITY", "FAILURES_WINDOW_MINUTES", winStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save FAILURES_WINDOW_MINUTES"})
		return
	}
	if err := h.config.SaveSetting("SECURITY", "AUTO_BAN_DURATION_HOURS", durStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save AUTO_BAN_DURATION_HOURS"})
		return
	}
	if err := h.config.SaveSetting("SECURITY", "AUTO_BAN_PERMANENT", permStr); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save AUTO_BAN_PERMANENT"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"success": true})
}
