// 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 pprof

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime/pprof"
	"sort"
	"sync"
	"syscall/zx"
	"time"

	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/inspect"
	"go.fuchsia.dev/fuchsia/src/lib/component"
	syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"
)

const pprofName = "pprof"

func Setup(path string) (component.Node, func() error, error) {
	mapDir, err := mapDirFromPath(path)
	if err != nil {
		return nil, nil, err
	}

	return &component.DirectoryWrapper{
			Directory: mapDir,
		}, func() error {
			t := time.NewTicker(time.Minute)
			defer t.Stop()

			for {
				mapDir.mu.Lock()
				// Prune all but the most recent profiles. The number retained is
				// chosen arbitrarily.
				if maxProfiles := 3; len(mapDir.mu.m) > maxProfiles {
					filenames := make([]string, 0, len(mapDir.mu.m))
					for filename := range mapDir.mu.m {
						filenames = append(filenames, filename)
					}
					sort.Strings(filenames)
					for _, filename := range filenames[:len(filenames)-maxProfiles] {
						if err := mapDir.mu.m[filename].File.(*sliceFile).Close(); err != nil {
							return err
						}
						delete(mapDir.mu.m, filename)
						if err := os.Remove(filepath.Join(path, filename)); err != nil {
							syslog.Warnf("failed to remove %s: %s", filename, err)
						}
					}
				}
				mapDir.mu.Unlock()
				filename := (<-t.C).UTC().Format(time.RFC3339) + ".inspect"

				b, err := getProfilesInspectVMOBytes()
				if err != nil {
					return err
				}
				mapDir.mu.Lock()
				mapDir.mu.m[filename] = &component.FileWrapper{
					File: &sliceFile{
						b: b,
					},
				}
				mapDir.mu.Unlock()

				if err := ioutil.WriteFile(filepath.Join(path, filename), b, os.ModePerm); err != nil {
					return err
				}
			}
		}, nil
}

var _ component.Directory = (*mapDirectory)(nil)

type mapDirectory struct {
	mu struct {
		sync.Mutex
		m map[string]*component.FileWrapper
	}
}

func mapDirFromPath(path string) (*mapDirectory, error) {
	dir, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	filenames, err := dir.Readdirnames(0)
	if err != nil {
		return nil, err
	}
	if err := dir.Close(); err != nil {
		return nil, err
	}

	m := make(map[string]*component.FileWrapper)
	for _, filename := range filenames {
		f, err := os.Open(filepath.Join(path, filename))
		if err != nil {
			return nil, err
		}
		b, err := ioutil.ReadAll(f)
		if err != nil {
			return nil, err
		}
		if err := f.Close(); err != nil {
			return nil, err
		}
		m[filename] = &component.FileWrapper{
			File: &sliceFile{
				b: b,
			},
		}
	}
	var d mapDirectory
	d.mu.m = m
	return &d, nil
}

const nowName = "now.inspect"

var nowFile = component.FileWrapper{File: &pprofFile{}}

func (md *mapDirectory) Get(nodeName string) (component.Node, bool) {
	if nodeName == nowName {
		return &nowFile, true
	}
	md.mu.Lock()
	value, ok := md.mu.m[nodeName]
	md.mu.Unlock()
	return value, ok
}

func (md *mapDirectory) ForEach(fn func(string, component.Node)) {
	fn(nowName, &nowFile)
	md.mu.Lock()
	for nodeName, node := range md.mu.m {
		fn(nodeName, node)
	}
	md.mu.Unlock()
}

var _ component.File = (*sliceFile)(nil)

type sliceFile struct {
	b   []byte
	vmo zx.VMO
}

func (sf *sliceFile) GetReader() (component.Reader, uint64) {
	r := bytes.NewReader(sf.b)
	return r, uint64(r.Len())
}

func (sf *sliceFile) GetVMO() zx.VMO {
	if !sf.vmo.Handle().IsValid() {
		vmo, err := zx.NewVMO(uint64(len(sf.b)), 0)
		if err != nil {
			return zx.VMO(zx.HandleInvalid)
		}
		if err := vmo.Write(sf.b, 0); err != nil {
			return zx.VMO(zx.HandleInvalid)
		}
		sf.vmo = vmo
	}
	return sf.vmo
}

func (sf *sliceFile) Close() error {
	if sf.vmo.Handle().IsValid() {
		return sf.vmo.Close()
	}
	return nil
}

var _ component.File = (*pprofFile)(nil)

type pprofFile struct{}

func getProfilesInspectVMOBytes() ([]byte, error) {
	var b bytes.Buffer
	w, err := inspect.NewWriter(&b)
	if err != nil {
		return nil, err
	}
	nodeValueIndex, err := w.WriteNodeValueBlock(0, pprofName)
	if err != nil {
		return nil, err
	}
	for _, p := range pprof.Profiles() {
		var b bytes.Buffer
		if err := p.WriteTo(&b, 0); err != nil {
			return nil, err
		}
		if err := w.WriteBinary(nodeValueIndex, p.Name(), uint32(b.Len()), &b); err != nil {
			return nil, err
		}
	}
	return b.Bytes(), nil
}

func (p *pprofFile) GetReader() (component.Reader, uint64) {
	b, err := getProfilesInspectVMOBytes()
	if err != nil {
		panic(err)
	}
	return bytes.NewReader(b), uint64(len(b))
}

func (*pprofFile) GetVMO() zx.VMO {
	return zx.VMO(zx.HandleInvalid)
}
