package repo

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"tangled.org/core/appview/middleware"
	"tangled.org/core/appview/pipelines"
)

func (rp *Repo) Router(mw *middleware.Middleware) http.Handler {
	r := chi.NewRouter()
	r.Get("/", rp.Index)
	r.Get("/commit-statuses", pipelines.StatusesHandler(rp.oauth, rp.repoResolver, rp.pages, rp.logger))
	r.Get("/opengraph", rp.Opengraph)
	r.Get("/feed.atom", rp.AtomFeed)
	r.Get("/commits/{ref}", rp.Log)
	r.Route("/tree/{ref}", func(r chi.Router) {
		r.Get("/", rp.Index)
		r.Get("/*", rp.Tree)
	})
	r.Get("/commit/{ref}.diff", rp.CommitRawDiff)
	r.Get("/commit/{ref}.patch", rp.CommitRawPatch)
	r.Get("/commit/{ref}", rp.Commit)
	r.Get("/branches", rp.Branches)
	r.Delete("/branches", rp.DeleteBranch)
	r.Route("/tags", func(r chi.Router) {
		r.Get("/", rp.Tags)
		r.Route("/{tag}", func(r chi.Router) {
			r.Get("/", rp.Tag)
			r.Get("/download/{file}", rp.DownloadArtifact)

			// require repo:push to upload or delete artifacts
			//
			// additionally: only the uploader can truly delete an artifact
			// (record+blob will live on their pds)
			r.Group(func(r chi.Router) {
				r.Use(middleware.AuthMiddleware(rp.oauth))
				r.Use(mw.RepoPermissionMiddleware("repo:push"))
				r.Post("/upload", rp.AttachArtifact)
				r.Delete("/{file}", rp.DeleteArtifact)
			})
		})
	})
	r.Get("/blob/{ref}/*", rp.Blob)
	r.Get("/raw/{ref}/*", rp.RepoBlobRaw)

	// intentionally doesn't use /* as this isn't
	// a file path
	r.Get("/archive/{ref}", rp.DownloadArchive)

	r.With(middleware.Paginate).Get("/stars", rp.Stars)
	r.With(middleware.Paginate).Get("/forks", rp.Forks)

	r.Route("/fork", func(r chi.Router) {
		r.Use(middleware.AuthMiddleware(rp.oauth))
		r.Get("/", rp.ForkRepo)
		r.Post("/", rp.ForkRepo)
		r.With(mw.RepoPermissionMiddleware("repo:owner")).Route("/sync", func(r chi.Router) {
			r.Post("/", rp.SyncRepoFork)
		})
	})

	r.Route("/compare", func(r chi.Router) {
		r.Get("/", rp.CompareNew) // start an new comparison

		// we have to wildcard here since we want to support GitHub's compare syntax
		//   /compare/{ref1}...{ref2}
		// for example:
		//   /compare/master...some/feature
		//   /compare/master...example.com:another/feature <- this is a fork
		r.Get("/*", rp.Compare)
	})

	// label panel in issues/pulls/discussions/tasks
	r.Route("/label", func(r chi.Router) {
		r.Get("/", rp.LabelPanel)
		r.Get("/edit", rp.EditLabelPanel)
	})

	r.Get("/search", rp.Search)

	// settings routes, needs auth
	r.Group(func(r chi.Router) {
		r.Use(middleware.AuthMiddleware(rp.oauth))
		r.With(mw.RepoPermissionMiddleware("repo:settings")).Route("/settings", func(r chi.Router) {
			r.Get("/", rp.Settings)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Put("/base", rp.EditBaseSettings)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/spindle", rp.EditSpindle)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Put("/label", rp.AddLabelDef)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Delete("/label", rp.DeleteLabelDef)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/label/subscribe", rp.SubscribeLabel)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/label/unsubscribe", rp.UnsubscribeLabel)
			r.With(mw.RepoPermissionMiddleware("repo:invite")).Put("/collaborator", rp.AddCollaborator)
			r.With(mw.RepoPermissionMiddleware("repo:invite")).Delete("/collaborator", rp.RemoveCollaborator)
			r.With(mw.RepoPermissionMiddleware("repo:delete")).Delete("/delete", rp.DeleteRepo)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Post("/rename", rp.RenameRepo)
			r.Put("/branches/default", rp.SetDefaultBranch)
			r.Put("/secrets", rp.Secrets)
			r.Delete("/secrets", rp.Secrets)
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Route("/sites", func(r chi.Router) {
				r.Put("/", rp.SaveRepoSiteConfig)
				r.Delete("/", rp.DeleteRepoSiteConfig)
			})
			r.With(mw.RepoPermissionMiddleware("repo:owner")).Route("/hooks", func(r chi.Router) {
				r.Get("/", rp.Webhooks)
				r.Post("/", rp.AddWebhook)
				r.Put("/{id}", rp.UpdateWebhook)
				r.Delete("/{id}", rp.DeleteWebhook)
				r.Post("/{id}/toggle", rp.ToggleWebhook)
				r.Get("/{id}/deliveries", rp.WebhookDeliveries)
			})
		})
	})

	return r
}
