package web

import (
	"bytes"
	"errors"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	webassets "ymhut-box/server/unified-management/web"
)

func (r *router) handleDownload(w http.ResponseWriter, req *http.Request) {
	name := strings.TrimPrefix(cleanPath(req.URL.Path), "/downloads/")
	if name == "" || strings.Contains(name, "..") || strings.ContainsAny(name, `/\`) {
		writeError(w, http.StatusForbidden, "FORBIDDEN", errors.New("invalid filename"))
		return
	}
	path := filepath.Join(r.cfg.DownloadsDir, name)
	resolved, err := filepath.Abs(path)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "PATH_FAILED", err)
		return
	}
	base, _ := filepath.Abs(r.cfg.DownloadsDir)
	if !strings.HasPrefix(resolved, base) {
		writeError(w, http.StatusForbidden, "FORBIDDEN", errors.New("path escape rejected"))
		return
	}
	http.ServeFile(w, req, resolved)
}

func serveStaticAsset(w http.ResponseWriter, req *http.Request, root, embedRoot, assetPath string) {
	if strings.Contains(assetPath, "..") || strings.ContainsAny(assetPath, `\`) {
		writeError(w, http.StatusForbidden, "FORBIDDEN", errors.New("invalid asset path"))
		return
	}
	if tryServeDiskFile(w, req, root, assetPath) {
		return
	}
	if serveEmbeddedFile(w, req, embedRoot+"/"+filepath.ToSlash(assetPath)) {
		return
	}
	http.NotFound(w, req)
}

func tryServeDiskFile(w http.ResponseWriter, req *http.Request, root, assetPath string) bool {
	path := filepath.Join(root, filepath.FromSlash(assetPath))
	resolved, err := filepath.Abs(path)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "PATH_FAILED", err)
		return true
	}
	base, _ := filepath.Abs(root)
	if resolved != base && !strings.HasPrefix(resolved, base+string(os.PathSeparator)) {
		writeError(w, http.StatusForbidden, "FORBIDDEN", errors.New("path escape rejected"))
		return true
	}
	info, err := os.Stat(resolved)
	if err != nil || info.IsDir() {
		return false
	}
	http.ServeFile(w, req, resolved)
	return true
}

func serveEmbeddedFile(w http.ResponseWriter, req *http.Request, name string) bool {
	if strings.Contains(name, "..") || strings.ContainsAny(name, `\`) {
		writeError(w, http.StatusForbidden, "FORBIDDEN", errors.New("invalid embedded asset path"))
		return true
	}
	data, err := webassets.ReadFile(name)
	if err != nil {
		return false
	}
	if contentType := mime.TypeByExtension(filepath.Ext(name)); contentType != "" {
		w.Header().Set("Content-Type", contentType)
	}
	http.ServeContent(w, req, filepath.Base(name), time.Time{}, bytes.NewReader(data))
	return true
}

func (r *router) servePortal(w http.ResponseWriter, req *http.Request) {
	index := filepath.Join(r.cfg.PortalWebDir, "index.html")
	if _, err := os.Stat(index); err == nil {
		http.ServeFile(w, req, index)
		return
	}
	if serveEmbeddedFile(w, req, "portal/dist/index.html") {
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, _ = w.Write([]byte(`<!doctype html><html><head><meta charset="utf-8"><title>YMhut Box</title></head><body><main><h1>YMhut Box</h1><p>Unified management service is running.</p><p><a href="/api/client/bootstrap">Client bootstrap</a> | <a href="/admin/login">Admin</a></p></main></body></html>`))
}

func (r *router) serveAdmin(w http.ResponseWriter, req *http.Request) {
	index := filepath.Join(r.cfg.AdminWebDir, "index.html")
	if _, err := os.Stat(index); err == nil {
		http.ServeFile(w, req, index)
		return
	}
	if serveEmbeddedFile(w, req, "admin/dist/index.html") {
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, _ = w.Write([]byte(`<!doctype html><html><head><meta charset="utf-8"><title>YMhut Admin</title></head><body><main><h1>YMhut Admin</h1><p>Build web/admin to enable the Vue console.</p></main></body></html>`))
}

func isPortalRoute(path string) bool {
	switch path {
	case "/", "/releases", "/sources", "/feedback", "/compatibility":
		return true
	default:
		return false
	}
}
