// Copyright 2020 The Fuchsia 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 omaha

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"

	"go.fuchsia.dev/fuchsia/tools/lib/color"
	"go.fuchsia.dev/fuchsia/tools/lib/logger"
)

type OmahaServer struct {
	serverURL    string
	updateHost   string
	updatePkg    string
	server       *http.Server
	mux          *http.ServeMux
	shuttingDown chan struct{}
}

type timestamp struct {
	ElapsedSeconds int `json:"elapsed_seconds"`
	ElapsedDays    int `json:"elapsed_days"`
}

type omahaURL struct {
	Codebase string `json:"codebase"`
}

type omahaURLs struct {
	Url []omahaURL `json:"url"`
}

type pkg struct {
	Name     string `json:"name"`
	Fp       string `json:"fp"`
	Required bool   `json:"required"`
}

type packages struct {
	Pkg []pkg `json:"package"`
}

type action struct {
	Run   string `json:"run,omitempty"`
	Event string `json:"event"`
}

type actions struct {
	Action []action `json:"action"`
}

type manifest struct {
	Version  string   `json:"version"`
	Actions  actions  `json:"actions"`
	Packages packages `json:"packages"`
}

type updateCheck struct {
	Status   string    `json:"status"`
	Urls     omahaURLs `json:"urls"`
	Manifest manifest  `json:"manifest"`
}

type app struct {
	CohortHint  string      `json:"cohorthint"`
	AppId       string      `json:"appid"`
	Cohort      string      `json:"cohort"`
	Status      string      `json:"status"`
	CohortName  string      `json:"cohortname"`
	UpdateCheck updateCheck `json:"updatecheck"`
}

type responseConfig struct {
	Server   string    `json:"server"`
	Protocol string    `json:"protocol"`
	DayStart timestamp `json:"timestamp"`
	App      []app     `json:"app"`
}

type response struct {
	Response responseConfig `json:"response"`
}

// NewOmahaServer starts an http server that serves the omaha response. The
// `serverAddress` is the address the server will listen on. The
// `localHostname` is the hostname running the server from the perspective of
// the test device.
func NewOmahaServer(ctx context.Context, serverAddress string, localHostname string) (*OmahaServer, error) {
	l := logger.NewLogger(
		logger.DebugLevel,
		color.NewColor(color.ColorAuto),
		os.Stdout,
		os.Stderr,
		"omaha-server: ")
	l.SetFlags(logger.Ldate | logger.Ltime | logger.LUTC | logger.Lshortfile)
	ctx = logger.WithLogger(ctx, l)

	listener, err := net.Listen("tcp", serverAddress)
	if err != nil {
		return nil, err
	}

	port := listener.Addr().(*net.TCPAddr).Port
	logger.Infof(ctx, "Serving Omaha from %d", port)

	hostname := strings.ReplaceAll(localHostname, "%", "%25")

	var serverURL string
	if strings.Contains(hostname, ":") {
		// This is an IPv6 address, use brackets for an IPv6 literal
		serverURL = fmt.Sprintf("http://[%s]:%d", hostname, port)
	} else {
		serverURL = fmt.Sprintf("http://%s:%d", hostname, port)
	}

	mux := http.NewServeMux()
	server := &http.Server{
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			logger.Infof(ctx, "Got request %s", r.RequestURI)
			mux.ServeHTTP(w, r)
		}),
	}

	go func() {
		if err := server.Serve(listener); err != http.ErrServerClosed {
			logger.Fatalf(ctx, "failed to shutdown server: %s", err)
		}
	}()

	shuttingDown := make(chan struct{})

	// Tear down the server if the context expires.
	go func() {
		select {
		case <-shuttingDown:
		case <-ctx.Done():
			server.Shutdown(ctx)
		}
	}()

	o := OmahaServer{
		serverURL:    serverURL,
		updateHost:   "",
		updatePkg:    "",
		server:       server,
		mux:          mux,
		shuttingDown: shuttingDown,
	}
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)
		if len(o.updateHost) == 0 || len(o.updatePkg) == 0 {
			w.Write([]byte(`{"status": "noupdate"}`))
		} else {
			j, err := json.Marshal(&response{
				Response: responseConfig{
					Server:   "prod",
					Protocol: "3.0",
					DayStart: timestamp{
						ElapsedSeconds: 400,
						ElapsedDays:    200,
					},
					App: []app{{
						CohortHint: "a-cohort-hint",
						AppId:      "some-id",
						Cohort:     "1:1:",
						Status:     "ok",
						CohortName: "a-cohort-name",
						UpdateCheck: updateCheck{
							Status: "ok",
							Urls: omahaURLs{
								Url: []omahaURL{{Codebase: o.updateHost}},
							},
							Manifest: manifest{
								Version: "0.1.2.3",
								Actions: actions{
									Action: []action{{
										Run:   o.updatePkg,
										Event: "update",
									},
										{
											Event: "postinstall",
										}},
								},
								Packages: packages{
									Pkg: []pkg{{
										Name:     o.updatePkg,
										Fp:       "2.0.1.2.3",
										Required: true,
									}},
								},
							},
						}},
					},
				},
			})
			if err != nil {
				logger.Infof(ctx, "Could not marshal JSON")
			}
			w.Write(j)
		}
	})
	return &o, nil
}

// Shutdown shuts down the Omaha Server.
func (o *OmahaServer) Shutdown(ctx context.Context) {
	o.server.Shutdown(ctx)
	close(o.shuttingDown)
}

// URL returns the URL of the Omaha Server that the target can use to talk to Omaha.
func (o *OmahaServer) URL() string {
	return o.serverURL
}

// Service this update package URL as the current update package.
func (o *OmahaServer) SetUpdatePkgURL(ctx context.Context, updatePkgURL string) error {
	// Expected input format: fuchsia-pkg://fuchsia.com/update?hash=abcdef
	u, err := url.Parse(updatePkgURL)
	if err != nil {
		return fmt.Errorf("invalid update package URL %q: %w", updatePkgURL, err)
	}

	if u.Scheme != "fuchsia-pkg" {
		return fmt.Errorf("scheme must be fuchsia-pkg, not %q", u.Scheme)
	}

	if u.Host == "" {
		return fmt.Errorf("update package URL's host must not be empty")
	}

	logger.Infof(ctx, "Omaha Server update package set to %q %q", u.Host, u.String())

	o.updateHost = fmt.Sprintf("fuchsia-pkg://%s", u.Host)

	logger.Infof(ctx, "Omaha Server update package set to %q", u.String())

	// The updatePkg field is the URL with the scheme and host stripped off.
	u.Scheme = ""
	u.Host = ""
	o.updatePkg = u.String()

	return nil
}
