package handlers

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

	"github.com/gin-gonic/gin"

	"gobsidian/internal/utils"
)

func (h *Handlers) CreateNotePageHandler(c *gin.Context) {
	folderPath := c.Query("folder")
	if folderPath == "" {
		folderPath = ""
	}

	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, "create", gin.H{
		"app_name":     h.config.AppName,
		"folder_path":  folderPath,
		"notes_tree":   notesTree,
		"active_path":  utils.GetActivePath(folderPath),
		"current_note": nil,
		"breadcrumbs":  utils.GenerateBreadcrumbs(folderPath),
		"image_storage_mode":  h.config.ImageStorageMode,
		"image_subfolder_name": h.config.ImageSubfolderName,
		"ContentTemplate": "create_content",
		"ScriptsTemplate": "create_scripts",
		"Page":            "create",
	})
}

func (h *Handlers) CreateNoteHandler(c *gin.Context) {
	folderPath := strings.TrimSpace(c.PostForm("folder_path"))
	title := strings.TrimSpace(c.PostForm("title"))
	content := c.PostForm("content")

	if title == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Title is required"})
		return
	}

	// Normalize slashes: treat backslashes as folder separators
	folderPath = strings.ReplaceAll(folderPath, "\\", "/")
	title = strings.ReplaceAll(title, "\\", "/")

	// Merge any subfolder segments included in title into folderPath
	if strings.Contains(title, "/") {
		dirPart := filepath.Dir(title)
		base := filepath.Base(title)
		if dirPart != "." && dirPart != "" {
			if folderPath == "" {
				folderPath = dirPart
			} else {
				folderPath = filepath.Join(folderPath, dirPart)
			}
		}
		title = base
	}

	// Strip any leading separators that might imply absolute path
	folderPath = strings.TrimPrefix(folderPath, "/")
	title = strings.TrimPrefix(title, "/")

	// Security check
	if strings.Contains(folderPath, "..") || strings.Contains(title, "..") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path or title"})
		return
	}

	// Check if path is in skipped directories (after merging title path)
	if utils.IsPathInSkippedDirs(folderPath, h.config.NotesDirSkip) {
		c.JSON(http.StatusForbidden, gin.H{"error": "Cannot create notes in this directory"})
		return
	}

	// Determine extension logic
	ext := strings.TrimPrefix(strings.ToLower(filepath.Ext(title)), ".")
	if ext == "" {
		// No extension provided: default to markdown
		title += ".md"
		ext = "md"
	} else {
		// Has extension: allow if md or in allowed file extensions
		allowed := ext == "md"
		if !allowed {
			for _, a := range h.config.AllowedFileExtensions {
				if strings.EqualFold(a, ext) {
					allowed = true
					break
				}
			}
		}
		if !allowed {
			c.JSON(http.StatusBadRequest, gin.H{"error": "File extension not allowed"})
			return
		}
	}

	// Create full path
	var notePath string
	if folderPath == "" {
		notePath = title
	} else {
		notePath = filepath.Join(folderPath, title)
	}

	fullPath := filepath.Join(h.config.NotesDir, notePath)

	// Check if file already exists
	if _, err := os.Stat(fullPath); !os.IsNotExist(err) {
		c.JSON(http.StatusConflict, gin.H{"error": "A note with this title already exists"})
		return
	}

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

	// Write file
	if err := os.WriteFile(fullPath, []byte(content), 0644); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create note"})
		return
	}

    // Redirect based on extension
    redirect := h.config.URLPrefix + "/note/" + notePath
    if strings.ToLower(ext) != "md" {
        redirect = h.config.URLPrefix + "/view_text/" + notePath
    }

    c.JSON(http.StatusOK, gin.H{
        "success":   true,
        "message":   "Note created successfully",
        "note_path": notePath,
        "redirect":  redirect,
    })
}

func (h *Handlers) EditNotePageHandler(c *gin.Context) {
	notePath := strings.TrimPrefix(c.Param("path"), "/")

	if !strings.HasSuffix(notePath, ".md") {
		c.HTML(http.StatusBadRequest, "error", gin.H{
			"error":           "Invalid note path",
			"app_name":        h.config.AppName,
			"message":         "Note path must end with .md",
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	// Security check
	if strings.Contains(notePath, "..") {
		c.HTML(http.StatusBadRequest, "error", gin.H{
			"error":           "Invalid path",
			"app_name":        h.config.AppName,
			"message":         "Path traversal is not allowed",
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	// Check if path is in skipped directories
	if utils.IsPathInSkippedDirs(notePath, h.config.NotesDirSkip) {
		c.HTML(http.StatusForbidden, "error", gin.H{
			"error":           "Access denied",
			"app_name":        h.config.AppName,
			"message":         "This note cannot be edited",
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	fullPath := filepath.Join(h.config.NotesDir, notePath)

	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		c.HTML(http.StatusNotFound, "error", gin.H{
			"error":           "Note not found",
			"app_name":        h.config.AppName,
			"message":         "The requested note does not exist",
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	content, err := os.ReadFile(fullPath)
	if err != nil {
		c.HTML(http.StatusInternalServerError, "error", gin.H{
			"error":           "Failed to read note",
			"app_name":        h.config.AppName,
			"message":         err.Error(),
			"ContentTemplate": "error_content",
			"ScriptsTemplate": "error_scripts",
			"Page":            "error",
		})
		return
	}

	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
	}

	title := strings.TrimSuffix(filepath.Base(notePath), ".md")
	folderPath := filepath.Dir(notePath)
	if folderPath == "." {
		folderPath = ""
	}

	c.HTML(http.StatusOK, "edit", gin.H{
		"app_name":     h.config.AppName,
		"title":        title,
		"content":      string(content),
		"note_path":    notePath,
		"folder_path":  folderPath,
		"notes_tree":   notesTree,
		"active_path":  utils.GetActivePath(folderPath),
		"current_note": notePath,
		"breadcrumbs":  utils.GenerateBreadcrumbs(folderPath),
		"image_storage_mode":  h.config.ImageStorageMode,
		"image_subfolder_name": h.config.ImageSubfolderName,
		"ContentTemplate": "edit_content",
		"ScriptsTemplate": "edit_scripts",
		"Page":            "edit",
	})
}

func (h *Handlers) EditNoteHandler(c *gin.Context) {
	notePath := strings.TrimPrefix(c.Param("path"), "/")
	content := c.PostForm("content")

	if !strings.HasSuffix(notePath, ".md") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid note path"})
		return
	}

	// Security check
	if strings.Contains(notePath, "..") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path"})
		return
	}

	// Check if path is in skipped directories
	if utils.IsPathInSkippedDirs(notePath, h.config.NotesDirSkip) {
		c.JSON(http.StatusForbidden, gin.H{"error": "This note cannot be edited"})
		return
	}

	fullPath := filepath.Join(h.config.NotesDir, notePath)

	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"error": "Note not found"})
		return
	}

	// Write updated content
	if err := os.WriteFile(fullPath, []byte(content), 0644); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save note"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success":  true,
		"message":  "Note saved successfully",
		"redirect": h.config.URLPrefix + "/note/" + notePath,
	})
}

func (h *Handlers) DeleteHandler(c *gin.Context) {
	filePath := strings.TrimPrefix(c.Param("path"), "/")

	// Security check
	if strings.Contains(filePath, "..") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid path"})
		return
	}

	// Check if path is in skipped directories
	if utils.IsPathInSkippedDirs(filePath, h.config.NotesDirSkip) {
		c.JSON(http.StatusForbidden, gin.H{"error": "Cannot delete files in this directory"})
		return
	}

	fullPath := filepath.Join(h.config.NotesDir, filePath)

	if _, err := os.Stat(fullPath); os.IsNotExist(err) {
		c.JSON(http.StatusNotFound, gin.H{"error": "File not found"})
		return
	}

	// Delete file or directory
	if err := os.RemoveAll(fullPath); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete file"})
		return
	}

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