package controllers

import (
	"canguidev/shelfy/internal/models"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)


type Entry struct {
    ID      int64     `json:"ID"`
    Name, Path string
    IsDir      bool
    ModTime    time.Time
    Size       int64
	Children []Entry   `json:"Children,omitempty"`
    Url      string    `json:"Url,omitempty"` // <- Ajout ici


}

func listEntries(base, rel string) ([]Entry, error) {
    dir := filepath.Join(base, rel)
    fis, err := os.ReadDir(dir)
    if err != nil {
        return nil, err
    }
    out := make([]Entry, 0, len(fis))
    for _, fi := range fis {
        info, _ := fi.Info()
        out = append(out, Entry{
            Name:    fi.Name(),
            Path:    filepath.ToSlash(filepath.Join(rel, fi.Name())),
            IsDir:   fi.IsDir(),
            ModTime: info.ModTime(),
            Size:    info.Size(),
        })
    }
    return out, nil
}

func StreamHandler(db *gorm.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        base := "upload"
        cur := c.Query("path")

        // Liste des dossiers du dossier racine
        rootEntries, err := listEntries(base, "")
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list root entries"})
            return
        }

        var dirs []Entry
        for _, e := range rootEntries {
            if e.IsDir {
                var pathDownload models.PathDownload
                // Recherche par PathName (== e.Name)
                db.Where("path_name = ?", e.Name).First(&pathDownload)
                e.ID = pathDownload.ID // 0 si non trouvé
                dirs = append(dirs, e)
            }
        }

        // Liste du chemin courant
        entries, err := listEntries(base, cur)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list entries"})
            return
        }

        for i := range entries {
            var pathDownload models.PathDownload
            db.Where("path_name = ?", entries[i].Name).First(&pathDownload)
            entries[i].ID = pathDownload.ID // 0 si non trouvé
        }

        c.JSON(http.StatusOK, gin.H{
            "dirs":        dirs,
            "entries":     entries,
            "currentPath": cur,
        })
    }
}



func DetailHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		base := "upload"
		rel := c.Query("path")
		rel = filepath.Clean("/" + rel)
		rel = strings.TrimPrefix(rel, "/") // => chemin relatif à "upload"

		absPath := filepath.Join(base, rel)
		absPath, err := filepath.Abs(absPath)
		if err != nil {
			c.JSON(500, gin.H{"error": "Path error"})
			return
		}
		baseAbs, err := filepath.Abs(base)
		if err != nil {
			c.JSON(500, gin.H{"error": "Base path error"})
			return
		}
		if !strings.HasPrefix(absPath, baseAbs) {
			c.JSON(403, gin.H{"error": "Access outside base directory is forbidden"})
			return
		}
		info, err := os.Stat(absPath)
		if err != nil {
			c.JSON(404, gin.H{"error": "Path not found"})
			return
		}

		type Entry struct {
			ID       int64     `json:"ID,omitempty"`
			Name     string    `json:"Name"`
			Path     string    `json:"Path"` // <--- Toujours RELATIF à "upload"
			IsDir    bool      `json:"IsDir"`
			ModTime  time.Time `json:"ModTime"`
			Size     int64     `json:"Size"`
			Children []Entry   `json:"Children,omitempty"`
			Url      string    `json:"Url,omitempty"` // <--- Lien d'accès au fichier
		}

		var buildTree func(absPath, relPath string, fi os.FileInfo) (Entry, error)
		buildTree = func(absPath, relPath string, fi os.FileInfo) (Entry, error) {
			entry := Entry{
				Name:    fi.Name(),
				Path:    relPath,   // <-- toujours RELATIF à la racine upload
				IsDir:   fi.IsDir(),
				ModTime: fi.ModTime(),
				Size:    fi.Size(),
			}

			if !fi.IsDir() {
				entry.Url = "/api/v1/folders/file?path=" + url.QueryEscape(relPath)
			}
			if fi.IsDir() {
				f, err := os.Open(absPath)
				if err != nil {
					return entry, err
				}
				defer f.Close()
				files, err := f.Readdir(0)
				if err != nil {
					return entry, err
				}
				for _, child := range files {
					childAbs := filepath.Join(absPath, child.Name())
					childRel := filepath.Join(relPath, child.Name())
					childEntry, err := buildTree(childAbs, childRel, child)
					if err != nil {
						continue
					}
					entry.Children = append(entry.Children, childEntry)
				}
			}
			return entry, nil
		}

		rootEntry, err := buildTree(absPath, rel, info)
		if err != nil {
			c.JSON(500, gin.H{"error": "Tree error"})
			return
		}
		c.JSON(200, rootEntry)
	}
}




