// Copyright 2015 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ui

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"net/http"
	"sync"
	"time"

	"google.golang.org/protobuf/types/known/timestamppb"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/errors"
	mc "go.chromium.org/luci/gae/service/memcache"
	"go.chromium.org/luci/server/auth"
	"go.chromium.org/luci/server/router"
	"go.chromium.org/luci/server/templates"

	api "go.chromium.org/luci/scheduler/api/scheduler/v1"
	"go.chromium.org/luci/scheduler/appengine/engine"
	"go.chromium.org/luci/scheduler/appengine/internal"
)

func jobPage(ctx *router.Context) {
	c, w, r, p := ctx.Context, ctx.Writer, ctx.Request, ctx.Params
	e := config(c).Engine

	projectID := p.ByName("ProjectID")
	jobName := p.ByName("JobName")
	cursor := r.URL.Query().Get("c")

	job := jobFromEngine(ctx, projectID, jobName)
	if job == nil {
		return
	}

	wg := sync.WaitGroup{}

	var triggers []*internal.Trigger
	var triErr error

	var triageLog *engine.JobTriageLog
	var triageLogErr error

	var invsActive []*engine.Invocation
	var invsActiveErr error
	var haveInvsActive bool

	// Triggers, triage log and active invocations are shown only on the first
	// page of the results.
	if cursor == "" {
		wg.Add(1)
		go func() {
			defer wg.Done()
			triggers, triErr = e.ListTriggers(c, job)
		}()

		wg.Add(1)
		go func() {
			defer wg.Done()
			triageLog, triageLogErr = e.GetJobTriageLog(c, job)
		}()

		wg.Add(1)
		go func() {
			defer wg.Done()
			haveInvsActive = true
			invsActive, _, invsActiveErr = e.ListInvocations(c, job, engine.ListInvocationsOpts{
				PageSize:   100000000, // ~ ∞, UI doesn't paginate active invocations
				ActiveOnly: true,
			})
		}()
	}

	// Historical invocations are shown on all pages.
	var invsLog []*engine.Invocation
	var nextCursor string
	var invsLogErr error
	wg.Add(1)
	go func() {
		defer wg.Done()
		invsLog, nextCursor, invsLogErr = e.ListInvocations(c, job, engine.ListInvocationsOpts{
			PageSize:     50,
			Cursor:       cursor,
			FinishedOnly: true,
		})
	}()

	wg.Wait()

	switch {
	case invsActiveErr != nil:
		panic(errors.Annotate(invsActiveErr, "failed to fetch active invocations").Err())
	case invsLogErr != nil:
		panic(errors.Annotate(invsLogErr, "failed to fetch invocation log").Err())
	case triErr != nil:
		panic(errors.Annotate(triErr, "failed to fetch triggers").Err())
	case triageLogErr != nil:
		panic(errors.Annotate(triageLogErr, "failed to fetch triage log").Err())
	}

	// memcacheKey hashes cursor to reduce its length, since full cursor doesn't
	// fit into memcache key length limits. Use 'v2' scheme for this ('v1' was
	// used before hashing was added).
	memcacheKey := func(cursor string) string {
		blob := sha256.Sum256([]byte(job.JobID + ":" + cursor))
		encoded := base64.StdEncoding.EncodeToString(blob[:])
		return "v2:cursors:list_invocations:" + encoded
	}

	// Cheesy way of implementing bidirectional pagination with forward-only
	// datastore cursors: store mapping from a page cursor to a previous page
	// cursor in the memcache.
	prevCursor := ""
	if cursor != "" {
		if itm, err := mc.GetKey(c, memcacheKey(cursor)); err == nil {
			prevCursor = string(itm.Value())
		}
	}
	if nextCursor != "" {
		itm := mc.NewItem(c, memcacheKey(nextCursor))
		if cursor == "" {
			itm.SetValue([]byte("NULL"))
		} else {
			itm.SetValue([]byte(cursor))
		}
		itm.SetExpiration(24 * time.Hour)
		mc.Set(c, itm)
	}

	// List of invocations in job.ActiveInvocations may contain recently finished
	// invocations not yet removed from the active list by the triage procedure.
	// 'invsActive' is always more accurate, since it fetches invocations from
	// the datastore and checks their status. So update the job entity to be more
	// accurate if we can. This is important for reporting jobs with recently
	// finished invocations as not running. Otherwise the UI page may appear
	// non-consistent (no running invocations in the list, yet the job's status is
	// displayed as "Running"). This is a bit of a hack...
	if haveInvsActive {
		ids := make([]int64, len(invsActive))
		for i, inv := range invsActive {
			ids[i] = inv.ID
		}
		job.ActiveInvocations = ids
	}

	jobUI := makeJob(c, job, triageLog)
	invsActiveUI := make([]*invocation, len(invsActive))
	for i, inv := range invsActive {
		invsActiveUI[i] = makeInvocation(jobUI, inv)
	}
	invsLogUI := make([]*invocation, len(invsLog))
	for i, inv := range invsLog {
		invsLogUI[i] = makeInvocation(jobUI, inv)
	}

	templates.MustRender(c, w, "pages/job.html", map[string]interface{}{
		"Job":               jobUI,
		"ShowJobHeader":     cursor == "",
		"InvocationsActive": invsActiveUI,
		"InvocationsLog":    invsLogUI,
		"PendingTriggers":   makeTriggerList(jobUI.now, triggers),
		"PrevCursor":        prevCursor,
		"NextCursor":        nextCursor,
	})
}

////////////////////////////////////////////////////////////////////////////////
// Actions.

var errCannotTriggerPausedJob = errors.New("cannot trigger paused job")

func triggerJobAction(c *router.Context) {
	handleJobAction(c, func(job *engine.Job) error {
		ctx := c.Context
		eng := config(ctx).Engine

		// Paused jobs just silently ignore triggers. Warn the user.
		if job.Paused {
			return errCannotTriggerPausedJob
		}

		// Generate random ID for the trigger, since we need one. They are usually
		// used to guarantee idempotency, and thus should be provided by the
		// triggering side (which in this case is end-user's browser). We could
		// potentially generate the ID in Javascript and submit the trigger via URL
		// fetch,  and retry on transient errors until success, but this looks like
		// too much hassle for little gains.
		buf := make([]byte, 8)
		if _, err := rand.Read(buf); err != nil {
			return err
		}
		id := hex.EncodeToString(buf)

		// This will check the ACL and submit the trigger.
		return eng.EmitTriggers(ctx, map[*engine.Job][]*internal.Trigger{
			job: {
				{
					Id:            id,
					Created:       timestamppb.New(clock.Now(ctx)),
					Title:         "Triggered via web UI",
					EmittedByUser: string(auth.CurrentIdentity(ctx)),
					Payload: &internal.Trigger_Webui{
						Webui: &api.WebUITrigger{},
					},
				},
			},
		})
	})
}

func pauseJobAction(c *router.Context) {
	handleJobAction(c, func(job *engine.Job) error {
		return config(c.Context).Engine.PauseJob(c.Context, job)
	})
}

func resumeJobAction(c *router.Context) {
	handleJobAction(c, func(job *engine.Job) error {
		return config(c.Context).Engine.ResumeJob(c.Context, job)
	})
}

func abortJobAction(c *router.Context) {
	handleJobAction(c, func(job *engine.Job) error {
		return config(c.Context).Engine.AbortJob(c.Context, job)
	})
}

func handleJobAction(c *router.Context, cb func(*engine.Job) error) {
	projectID := c.Params.ByName("ProjectID")
	jobName := c.Params.ByName("JobName")

	job := jobFromEngine(c, projectID, jobName)
	if job == nil {
		return
	}

	switch err := cb(job); {
	case err == errCannotTriggerPausedJob:
		uiErrCannotTriggerPausedJob.render(c)
	case err == engine.ErrNoPermission:
		uiErrActionForbidden.render(c)
	case err != nil:
		panic(err)
	default:
		http.Redirect(c.Writer, c.Request, fmt.Sprintf("/jobs/%s/%s", projectID, jobName), http.StatusFound)
	}
}
