package pkg

import (
	"github.com/julienschmidt/httprouter"
	"mime"
	"net/http"
)

func NewRouter(db *Db) http.Handler {
	companyRouter := httprouter.New()
	companyRouter.GET("/profile", GetProfileForm)
	companyRouter.POST("/profile", HandleProfileForm)
	companyRouter.GET("/tax-details", GetCompanyTaxDetailsForm)
	companyRouter.POST("/tax-details", HandleCompanyTaxDetailsForm)
	companyRouter.POST("/tax", HandleAddCompanyTax)
	companyRouter.DELETE("/tax/:taxId", HandleDeleteCompanyTax)
	companyRouter.POST("/payment-method", HandleAddPaymentMethod)
	companyRouter.DELETE("/payment-method/:paymentMethodId", HandleDeletePaymentMethod)
	companyRouter.GET("/contacts", IndexContacts)
	companyRouter.POST("/contacts", HandleAddContact)
	companyRouter.GET("/contacts/:slug", GetContactForm)
	companyRouter.PUT("/contacts/:slug", HandleUpdateContact)
	companyRouter.PUT("/contacts/:slug/tags", HandleUpdateContactTags)
	companyRouter.GET("/contacts/:slug/tags/edit", ServeEditContactTags)
	companyRouter.GET("/products", IndexProducts)
	companyRouter.POST("/products", HandleAddProduct)
	companyRouter.GET("/products/:slug", GetProductForm)
	companyRouter.PUT("/products/:slug", HandleUpdateProduct)
	companyRouter.PUT("/products/:slug/tags", HandleUpdateProductTags)
	companyRouter.GET("/products/:slug/tags/edit", ServeEditProductTags)
	companyRouter.GET("/invoices", IndexInvoices)
	companyRouter.POST("/invoices", HandleAddInvoice)
	companyRouter.GET("/invoices/:slug", ServeInvoice)
	companyRouter.PUT("/invoices/:slug", HandleUpdateInvoice)
	companyRouter.POST("/invoices/:slug", HandleNewInvoiceAction)
	companyRouter.GET("/invoices/:slug/edit", ServeEditInvoice)
	companyRouter.POST("/invoices/:slug/edit", HandleEditInvoiceAction)
	companyRouter.PUT("/invoices/:slug/tags", HandleUpdateInvoiceTags)
	companyRouter.GET("/invoices/:slug/tags/edit", ServeEditInvoiceTags)
	companyRouter.GET("/quotes", IndexQuotes)
	companyRouter.POST("/quotes", HandleAddQuote)
	companyRouter.GET("/quotes/:slug", ServeQuote)
	companyRouter.PUT("/quotes/:slug", HandleUpdateQuote)
	companyRouter.POST("/quotes/:slug", HandleNewQuoteAction)
	companyRouter.GET("/quotes/:slug/edit", ServeEditQuote)
	companyRouter.POST("/quotes/:slug/edit", HandleEditQuoteAction)
	companyRouter.PUT("/quotes/:slug/tags", HandleUpdateQuoteTags)
	companyRouter.GET("/quotes/:slug/tags/edit", ServeEditQuoteTags)
	companyRouter.GET("/search/products", HandleProductSearch)
	companyRouter.GET("/expenses", IndexExpenses)
	companyRouter.POST("/expenses", HandleAddExpense)
	companyRouter.GET("/expenses/:slug", ServeExpenseForm)
	companyRouter.PUT("/expenses/:slug", HandleUpdateExpense)
	companyRouter.PUT("/expenses/:slug/tags", HandleUpdateExpenseTags)
	companyRouter.GET("/expenses/:slug/tags/edit", ServeEditExpenseTags)
	companyRouter.GET("/expenses/:slug/download/:filename", ServeExpenseAttachment)
	companyRouter.GET("/", ServeDashboard)

	router := httprouter.New()
	router.ServeFiles("/static/*filepath", http.Dir("web/static"))
	router.GET("/login", GetLoginForm)
	router.POST("/login", HandleLoginForm)
	router.POST("/logout", Authenticated(HandleLogout))

	companyHandler := Authenticated(CompanyHandler(companyRouter))
	router.GET("/company/:slug/*rest", companyHandler)
	router.POST("/company/:slug/*rest", companyHandler)
	router.PUT("/company/:slug/*rest", companyHandler)
	router.DELETE("/company/:slug/*rest", companyHandler)

	router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
		user := getUser(r)
		if user.LoggedIn {
			conn := getConn(r)
			company := &Company{
				Slug: conn.MustGetText(r.Context(), "", "select slug::text from company order by company_id limit 1"),
			}
			http.Redirect(w, r, companyURI(company, "/"), http.StatusFound)
		} else {
			mustRenderWebTemplate(w, r, "home.gohtml", nil)
		}
	})

	var handler http.Handler = router
	handler = MethodOverrider(handler)
	handler = LocaleSetter(db, handler)
	handler = LoginChecker(db, handler)
	handler = Recoverer(handler)
	handler = Logger(handler)
	return handler
}

func MethodOverrider(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			contentType := r.Header.Get("Content-Type")
			contentType, _, err := mime.ParseMediaType(contentType)
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if contentType == "multipart/form-data" {
				if err := r.ParseMultipartForm(20 << 20); err != nil {
					http.Error(w, err.Error(), http.StatusBadRequest)
					return
				}
			} else {
				if err := r.ParseForm(); err != nil {
					http.Error(w, err.Error(), http.StatusBadRequest)
					return
				}
			}
			override := r.FormValue(overrideMethodName)
			if override == http.MethodDelete || override == http.MethodPut {
				r2 := new(http.Request)
				*r2 = *r
				r2.Method = override
				r = r2
			}
		}
		next.ServeHTTP(w, r)
	})
}
