package server

import (
	"fmt"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
	"time"
)

/* this indexes and generate the page for viewing the archive directory */
func generateArchiveIndex(fsPath string, urlPath string) (string, error) {
	info, err := os.Stat(fsPath)
	if err != nil {
		return "", err
	}
	if !info.IsDir() {
		return "", fmt.Errorf("not a directory")
	}
	ents, err := os.ReadDir(fsPath)
	if err != nil {
		return "", err
	}
	type entryInfo struct {
		name  string
		isDir bool
		href  string
		size  int64
		mod   time.Time
	}
	var list []entryInfo
	for _, e := range ents {
		n := e.Name()
		full := filepath.Join(fsPath, n)
		st, err := os.Stat(full)
		if err != nil {
			continue
		}
		isd := st.IsDir()
		displayName := n
		if isd {
			displayName = n + "/"
		}
		href := path.Join(urlPath, n)
		if isd && !strings.HasSuffix(href, "/") {
			href = href + "/"
		}
		size := int64(-1)
		if !isd {
			size = st.Size()
		}
		list = append(list, entryInfo{name: displayName, isDir: isd, href: href, size: size, mod: st.ModTime()})
	}
	sort.Slice(list, func(i, j int) bool {
		if list[i].isDir != list[j].isDir {
			return list[i].isDir
		}
		return strings.ToLower(list[i].name) < strings.ToLower(list[j].name)
	})

	urlPath = strings.TrimPrefix(urlPath, "/archive")

	var b strings.Builder

	b.WriteString("<html>\n<head><title>Index of ")
	b.WriteString(template.HTMLEscapeString(urlPath))
	b.WriteString("</title></head>\n<body>\n<h1>Index of ")
	b.WriteString(template.HTMLEscapeString(urlPath))
	b.WriteString("</h1><hr><pre>")
	b.WriteString("<a href=\"../\">../</a>\n")

	nameCol := 50
	for _, ei := range list {
		escapedName := template.HTMLEscapeString(ei.name)
		dateStr := ei.mod.Local().Format("02-Jan-2006 15:04")
		var sizeStr string
		if ei.isDir {
			sizeStr = "-"
		} else {
			sizeStr = fmt.Sprintf("%d", ei.size)
		}
		spaces := 1
		if len(escapedName) < nameCol {
			spaces = nameCol - len(escapedName)
		}
		line := `<a href="` + template.HTMLEscapeString(ei.href) + `">` + escapedName + `</a>` + strings.Repeat(" ", spaces) + dateStr + strings.Repeat(" ", 19-len(sizeStr)) + sizeStr + "\n"
		b.WriteString(line)
	}
	b.WriteString("</pre><hr></body>\n</html>")
	return b.String(), nil
}

/* helper to read the archive files */
func readArchive(w http.ResponseWriter, route string) error {
	fsPath := "." + route
	if info, err := os.Stat(fsPath); err == nil && info.IsDir() {
		if page, err := generateArchiveIndex(fsPath, route); err == nil {
			w.Write([]byte(page))
			return nil
		} else {
			return err
		}
	}
	return nil
}
