package server

import (
	"context"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/jackc/pgx/v5/pgxpool"
	"io/fs"
	"log/slog"
	"madsky.ru/go-tracker/internal/config"
	"madsky.ru/go-tracker/internal/storage"
	web "madsky.ru/go-tracker/web"
	"net/http"
	"os"
	"strings"
	"time"
)

type Application struct {
	Config  *config.Config
	Storage *storage.Storage
	Ctx     context.Context
}

func NewServer(ctx context.Context, client *pgxpool.Pool, logger *slog.Logger) {
	//statusRepository := status.NewRepository(client)
	//projectsRepository := project.NewRepository(client)
	//issueRepository := issue.NewRepository(client)
	//userRepository := user.NewRepository(client)

	//r.Get("/bla/assets/*", func(w http.ResponseWriter, r *http.Request) {
	//	dist, err := fs.Sub(web.DistDir, "dist")
	//	if err != nil {
	//		http.Error(w, err.Error(), http.StatusInternalServerError)
	//	}
	//	http.FileServer(http.FS(dist)).ServeHTTP(w, r)
	//})

	//handlers.RegisterAuthRoutes(mux, ctx, userRepository)
	//
	//authMux := http.NewServeMux()
	//handlers.RegisterProjectRoutes(authMux, ctx, projectsRepository)
	//handlers.RegisterStatusRoutes(authMux, ctx, statusRepository)
	//handlers.RegisterIssueRoutes(authMux, ctx, issueRepository)
	//handlers.RegisterUserRoutes(authMux, ctx, userRepository)
	//
	//mux.Handle("/api/", http.StripPrefix("/api", md.AuthMiddleware(authMux)))
	//
	//handler := md.LoggingMiddleware(mux, logger)
}

func (app *Application) Routes() http.Handler {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	r.Route("/api", func(r chi.Router) {
		r.Route("/version", func(r chi.Router) {
			r.Get("/", app.getVersion)
		})

		r.Route("/auth", func(r chi.Router) {
			r.Post("/login", app.login)
			r.Post("/register", app.register)
			r.Post("/logout", app.logout)
		})

		r.Route("/projects", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Use(app.LogRole)
			r.Get("/", app.findProjects)
			r.Post("/", app.createProject)

			r.Route("/{id}", func(r chi.Router) {
				r.Get("/", app.findProjectByID)
				r.Patch("/", app.updateProject)
				r.Delete("/", app.deleteProject)
			})
		})

		r.Route("/statuses", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Get("/", app.findStatuses)
		})

		r.Route("/issues", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Get("/", app.findIssues)
			r.Post("/", app.createIssues)
			r.Post("/positions", app.updatePositions)

			r.Route("/{id}", func(r chi.Router) {
				r.Get("/", app.findIssuesByID)
				r.Delete("/", app.deleteIssues)
			})
		})

		r.Route("/preferences", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Get("/", app.getSettings)
		})

		r.Route("/profile", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Get("/", app.getProfile)
			r.Patch("/", app.updateProfile)
			r.Delete("/", app.deleteProfile)

		})

		r.Route("/users", func(r chi.Router) {
			r.Use(app.AuthMiddleware)
			r.Get("/", app.findUsers)
		})
	})

	r.Get("/*", func(w http.ResponseWriter, r *http.Request) {
		dist, err := fs.Sub(web.DistDir, "dist")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

		file, err := dist.Open(strings.TrimPrefix(r.URL.Path, "/"))
		if err != nil {
			if os.IsNotExist(err) {
				r.URL.Path = "/"
			}
		} else {
			defer func(file fs.File) {
				err := file.Close()
				if err != nil {
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
			}(file)
		}

		http.FileServer(http.FS(dist)).ServeHTTP(w, r)
	})

	return r
}

func (app *Application) Start(mux http.Handler) error {
	srv := &http.Server{
		Addr:           "0.0.0.0:3000",
		Handler:        mux,
		ReadTimeout:    10 * time.Second,
		WriteTimeout:   10 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}

	return srv.ListenAndServe()
}
