package api

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"gitea.local/admin/hspguard/internal/admin"
	"gitea.local/admin/hspguard/internal/auth"
	"gitea.local/admin/hspguard/internal/cache"
	"gitea.local/admin/hspguard/internal/config"
	"gitea.local/admin/hspguard/internal/oauth"
	"gitea.local/admin/hspguard/internal/repository"
	"gitea.local/admin/hspguard/internal/storage"
	"gitea.local/admin/hspguard/internal/user"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
)

type APIServer struct {
	addr    string
	repo    *repository.Queries
	storage *storage.FileStorage
	cache   *cache.Client
	cfg     *config.AppConfig
}

func NewAPIServer(addr string, db *repository.Queries, minio *storage.FileStorage, cache *cache.Client, cfg *config.AppConfig) *APIServer {
	return &APIServer{
		addr:    addr,
		repo:    db,
		storage: minio,
		cache:   cache,
		cfg:     cfg,
	}
}

func (s *APIServer) Run() error {
	router := chi.NewRouter()
	router.Use(middleware.Logger)

	// workDir, _ := os.Getwd()
	// staticDir := http.Dir(filepath.Join(workDir, "static"))
	// FileServer(router, "/static", staticDir)

	oauthHandler := oauth.NewOAuthHandler(s.repo, s.cache, s.cfg)

	router.Route("/api/v1", func(r chi.Router) {
		userHandler := user.NewUserHandler(s.repo, s.storage, s.cfg)
		userHandler.RegisterRoutes(r)

		authHandler := auth.NewAuthHandler(s.repo, s.cache, s.cfg)
		authHandler.RegisterRoutes(r)

		oauthHandler.RegisterRoutes(r)

		adminHandler := admin.New(s.repo, s.cfg)
		adminHandler.RegisterRoutes(r)
	})

	router.Get("/.well-known/jwks.json", oauthHandler.WriteJWKS)
	router.Get("/.well-known/openid-configuration", oauthHandler.OpenIdConfiguration)

	router.Get("/*", func(w http.ResponseWriter, r *http.Request) {
		path := "./dist" + r.URL.Path
		if _, err := os.Stat(path); os.IsNotExist(err) {
			http.ServeFile(w, r, "./dist/index.html")
			return
		}
		http.FileServer(http.Dir("./dist")).ServeHTTP(w, r)
	})

	// Handle unknown routes
	router.NotFound(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusNotFound)
		_, _ = fmt.Fprint(w, `{"error": "404 - route not found"}`)
	})

	router.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusMethodNotAllowed)
		_, _ = fmt.Fprint(w, `{"error": "405 - method not allowed"}`)
	})

	log.Println("Listening on", s.addr)

	return http.ListenAndServe(s.addr, router)
}
