// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"time"

	"v.io/v23/context"
	"v.io/v23/security"
)

const (
	routeRoot      = "/"
	routeHome      = "/home"
	routeCreate    = "/create"
	routeDashboard = "/dashboard"
	routeDestroy   = "/destroy"
	routeOauth     = "/oauth2"
	routeStatic    = "/static/"
	routeStats     = "/stats"
	routeHealth    = "/health"

	paramMessage = "message"
	paramName    = "name"
	// The following parameter names are hardcorded in static/dash.js,
	// and should be changed in tandem.
	paramDashboardName    = "n"
	paramDashbordDuration = "d"

	cookieValidity = 10 * time.Minute
)

type param struct {
	key, value string
}

type params map[string]string

func makeURL(ctx *context.T, baseURL string, p params) string {
	u, err := url.Parse(baseURL)
	if err != nil {
		ctx.Errorf("Parse url error for %v: %v", baseURL, err)
		return ""
	}
	v := url.Values{}
	for param, value := range p {
		v.Add(param, value)
	}
	u.RawQuery = v.Encode()
	return u.String()
}

func replaceParam(ctx *context.T, origURL, param, value string) string {
	u, err := url.Parse(origURL)
	if err != nil {
		ctx.Errorf("Parse url error for %v: %v", origURL, err)
		return ""
	}
	v := u.Query()
	v.Set(param, value)
	u.RawQuery = v.Encode()
	return u.String()
}

type httpArgs struct {
	addr,
	externalURL,
	serverName,
	dashboardGCMMetric,
	dashboardGCMProject,
	monitoringKeyFile string
	secureCookies     bool
	oauthCreds        *oauthCredentials
	baseBlessings     security.Blessings
	baseBlessingNames []string
	// URI prefix for static assets served from (another) content server.
	staticAssetsPrefix string
	// Manages locally served resources.
	assets *assetsHelper
}

func (a httpArgs) validate() error {
	switch {
	case a.addr == "":
		return errors.New("addr is empty")
	case a.externalURL == "":
		return errors.New("externalURL is empty")
	}
	if err := a.oauthCreds.validate(); err != nil {
		return fmt.Errorf("oauth creds invalid: %v", err)
	}
	return nil
}

// startHTTP is the entry point to the http interface.  It configures and
// launches the http server, and returns a cleanup method to be called at
// shutdown time.
func startHTTP(ctx *context.T, args httpArgs) func() error {
	if err := args.validate(); err != nil {
		ctx.Fatalf("Invalid args %#v: %v", args, err)
	}
	baker := &signedCookieBaker{
		secure:   args.secureCookies,
		signKey:  args.oauthCreds.HashKey,
		validity: cookieValidity,
	}
	// mutating should be true for handlers that mutate state.  For such
	// handlers, any re-authentication should result in redirection to the
	// home page (to foil CSRF attacks that trick the user into launching
	// actions with consequences).
	newHandler := func(f handlerFunc, mutating bool) *handler {
		return &handler{
			ss: &serverState{
				ctx:  ctx,
				args: args,
			},
			baker:    baker,
			f:        f,
			mutating: mutating,
		}
	}

	http.HandleFunc(routeRoot, func(w http.ResponseWriter, r *http.Request) {
		tmplArgs := struct {
			AssetsPrefix,
			Home,
			Email,
			ServerName string
		}{
			AssetsPrefix: args.staticAssetsPrefix,
			Home:         routeHome,
			Email:        "", // Ask the user to log in.
			ServerName:   args.serverName,
		}
		if err := args.assets.executeTemplate(w, rootTmpl, tmplArgs); err != nil {
			args.assets.errorOccurred(ctx, w, r, routeHome, err)
			ctx.Infof("%s[%s] : error %v", r.Method, r.URL, err)
		}
	})
	http.Handle(routeHome, newHandler(handleHome, false))
	http.Handle(routeCreate, newHandler(handleCreate, true))
	http.Handle(routeDashboard, newHandler(handleDashboard, false))
	http.Handle(routeDestroy, newHandler(handleDestroy, true))
	http.HandleFunc(routeOauth, func(w http.ResponseWriter, r *http.Request) {
		handleOauth(ctx, args, baker, w, r)
	})
	http.Handle(routeStatic, http.StripPrefix(routeStatic, args.assets))
	http.Handle(routeStats, newHandler(handleStats, false))
	http.HandleFunc(routeHealth, func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	ln, err := net.Listen("tcp", args.addr)
	if err != nil {
		ctx.Fatalf("Listen failed: %v", err)
	}
	ctx.Infof("HTTP server at %v [%v]", ln.Addr(), args.externalURL)
	go func() {
		if err := http.Serve(ln, nil); err != nil {
			ctx.Fatalf("Serve failed: %v", err)
		}
	}()
	// NOTE(caprita): closing the listener is necessary but not sufficient
	// for graceful HTTP server shutdown (which should include draining
	// in-flight requests).  See https://github.com/facebookgo/httpdown for
	// example.
	return ln.Close
}

type serverState struct {
	ctx  *context.T
	args httpArgs
}

type requestState struct {
	email, csrfToken string
	w                http.ResponseWriter
	r                *http.Request
}

type handlerFunc func(ss *serverState, rs *requestState) error

// handler wraps handler functions and takes care of providing them with a
// Vanadium context, configuration args, and user's email address (performing
// the oauth flow if the user is not logged in yet).
type handler struct {
	ss       *serverState
	baker    cookieBaker
	f        handlerFunc
	mutating bool
}

// ServeHTTP verifies that the user is logged in, and redirects to the oauth
// flow if not.  If the user is logged in, it extracts the email address from
// the cookie and passes it to the handler function.
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := h.ss.ctx
	oauthCfg := oauthConfig(h.ss.args.externalURL, h.ss.args.oauthCreds)
	email, csrfToken, err := requireSession(ctx, oauthCfg, h.baker, w, r, h.mutating)
	if err != nil {
		h.ss.args.assets.errorOccurred(ctx, w, r, routeHome, err)
		ctx.Infof("%s[%s] : error %v", r.Method, r.URL, err)
		return
	}
	if email == "" {
		ctx.Infof("%s[%s] -> login", r.Method, r.URL)
		return
	}
	rs := &requestState{
		email:     email,
		csrfToken: csrfToken,
		w:         w,
		r:         r,
	}
	if err := h.f(h.ss, rs); err != nil {
		h.ss.args.assets.errorOccurred(ctx, w, r, makeURL(ctx, routeHome, params{paramCSRF: csrfToken}), err)
		ctx.Infof("%s[%s] : error %v", r.Method, r.URL, err)
		return
	}
	ctx.Infof("%s[%s] : OK", r.Method, r.URL)
}
