package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

type SaveRequest struct {
	Content string `json:"content"`
	Path    string `json:"path,omitempty"`
}

type ContentResponse struct {
	Content string `json:"content"`
	Path    string `json:"path,omitempty"`
}

func main() {
	r := gin.Default()

	// Configure CORS
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"http://localhost:5173"},
		AllowMethods:     []string{"GET", "POST", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Type"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
	}))

	// Serve the compiled Vite app
	r.StaticFS("/assets", http.Dir("./dist/assets"))
	r.StaticFile("/", "./dist/index.html")

	// API routes
	api := r.Group("/api")
	{
		api.GET("/content", getContent)
		api.POST("/save", saveContent)
		api.POST("/upload-image", uploadImage)
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	fmt.Printf("Server running on http://localhost:%s\n", port)
	r.Run(":" + port)
}

func getContent(c *gin.Context) {
	// Get the file path from the query parameter or use default
	filePath := c.Query("path")
	if filePath == "" {
		filePath = "content.md"
	}

	// Ensure path is within the allowed directory
	filePath = filepath.Join("content", filePath)

	// Check if file exists
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		// Return empty content if file doesn't exist
		c.JSON(http.StatusOK, ContentResponse{
			Content: "# New Document\n\nStart writing here...",
			Path:    filePath,
		})
		return
	}

	// Read the file
	content, err := ioutil.ReadFile(filePath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file"})
		return
	}

	c.JSON(http.StatusOK, ContentResponse{
		Content: string(content),
		Path:    filePath,
	})
}

func saveContent(c *gin.Context) {
	var req SaveRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
		return
	}

	// Get the file path from the request or use default
	filePath := req.Path
	if filePath == "" {
		filePath = "content.md"
	}

	// Ensure path is within the allowed directory
	filePath = filepath.Join("content", filePath)

	// Create directory if it doesn't exist
	dir := filepath.Dir(filePath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create directory"})
		return
	}

	// Write the content to the file
	if err := ioutil.WriteFile(filePath, []byte(req.Content), 0644); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Content saved successfully", "path": filePath})
}

func uploadImage(c *gin.Context) {
	// Parse the multipart form
	if err := c.Request.ParseMultipartForm(10 << 20); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File too large"})
		return
	}

	file, handler, err := c.Request.FormFile("image")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid file"})
		return
	}
	defer file.Close()

	// Check file type
	if !strings.HasPrefix(handler.Header.Get("Content-Type"), "image/") {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File is not an image"})
		return
	}

	// Read the file
	buffer := make([]byte, handler.Size)
	if _, err := file.Read(buffer); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file"})
		return
	}

	// Encode to base64
	contentType := handler.Header.Get("Content-Type")
	base64String := "data:" + contentType + ";base64," + base64.StdEncoding.EncodeToString(buffer)

	c.JSON(http.StatusOK, gin.H{"url": base64String})
}