package main

import (
	_ "embed"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/a-h/templ"
	"github.com/moh682/portfolio/components"
	"github.com/moh682/portfolio/domain"
	"github.com/moh682/portfolio/middlewares"
)

func templHandlerWithOptions(component templ.Component) http.Handler {
	t := templ.Handler(component, templ.WithStatus(200), templ.WithContentType("text/html"))

	log.Println("templHandlerWithOptions: ", t.Status)

	return t
}

func rootHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		handler.ServeHTTP(w, r)
	})
}

// SafeFileServer wraps http.FileServer to only serve specific file types from specific directories
func SafeFileServer(root http.FileSystem) http.Handler {
	fileServer := http.FileServer(root)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Set security headers
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("X-Frame-Options", "DENY")
		w.Header().Set("X-XSS-Protection", "1; mode=block")

		log.Println("path", r.URL.Path)

		// Only allow specific file extensions
		if allowed := func(path string) bool {
			allowedExts := map[string]bool{
				".js":   true,
				".css":  true,
				".png":  true,
				".jpg":  true,
				".jpeg": true,
				".svg":  true,
				".ico":  true,
			}
			for ext := range allowedExts {
				if strings.HasSuffix(path, ext) {
					return true
				}
			}
			return false
		}(r.URL.Path); !allowed {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

		fileServer.ServeHTTP(w, r)
	})
}

//go:embed assets/json/experiences.json
var embeddedExperiences []byte

//go:embed assets/json/projects.json
var embeddedProjects []byte

func main() {
	server := http.NewServeMux()

	// Serve static files with restrictions
	staticFS := http.Dir("static")
	server.Handle("GET /assets/", http.StripPrefix("/assets/", SafeFileServer(staticFS)))

	server.Handle("GET /about", templHandlerWithOptions(components.AboutPage()))

	var exps []domain.Experience
	err := json.Unmarshal(embeddedExperiences, &exps)
	if err != nil {
		log.Panic(err)
	}
	server.Handle("GET /experiences", templHandlerWithOptions(components.ExperiencesPage(exps)))

	var projects []domain.Project
	err = json.Unmarshal(embeddedProjects, &projects)
	if err != nil {
		log.Panic(err)
	}
	server.Handle("GET /projects", templHandlerWithOptions(components.ProjectsPage(projects)))

	server.Handle("GET /contact", templHandlerWithOptions(components.ContactPage()))
	server.Handle("GET /{$}", templHandlerWithOptions(components.LandingPage()))

	// 404 fallback page
	server.Handle("GET /", templHandlerWithOptions(components.NotFound()))

	// TODO: add Blogs to my portfolio website
	// server.Handle("GET /blogs", templHandlerWithOptions(components.AboutPage()))

	fmt.Println("Listening on :8080")
	log.Panic(
		http.ListenAndServe(":8080",
			middlewares.Combine(
				middlewares.Logger(server),
			),
		),
	)
}
