// Copyright 2020 The Monogon Project Authors.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"

	"github.com/golang/protobuf/proto"

	pb "git.monogon.dev/source/nexantic.git/build/fietsje/proto"
)

// The Shelf is a combined cache and dependency lockfile, not unlike go.sum. It's implemented as a text proto file on
// disk, and currently stores a single mapping of shelfKeys to shelfValues, which are in order a (importpath, version)
// tuple and the `locked` structure of a dependency.
// The resulting shelf file should be commited to the nxt repository. It can be freely deleted to force recreation from
// scratch, which can be useful as there is no garbage collection implemented for it.
// The 'lockfile' aspect of the Shelf is counter-intuitive to what readers might be used to from other dependency
// management systems. It does not lock a third-party dependency to a particular version, but only locks a well defined
// version to its checksum. As such, recreating the shelf from scratch should not bump any dependencies, unless some
// upstream-project retagged a release to a different VCS commit, or a fietsje user pinned to 'master' instead of a
// particular commit. The effective changes will always be reflected in the resulting starlark repository ruleset,
// which (also being commited to source control) can be used as a canary of a version being effectively bumped.

// shelfKey is the key into the shelf map structure.
type shelfKey struct {
	importpath string
	version    string
}

// shelfValue is the entry of a shelf map structure.
type shelfValue struct {
	l *locked
}

// shelf is an in-memory representation of the shelf loaded from disk.
type shelf struct {
	path string
	data map[shelfKey]shelfValue
}

func shelfLoad(path string) (*shelf, error) {
	var data []byte
	var err error

	if _, err := os.Stat(path); os.IsNotExist(err) {
		log.Printf("Creating new shelf file at %q, this run will be slow.", path)
	} else {
		data, err = ioutil.ReadFile(path)
		if err != nil {
			return nil, fmt.Errorf("could not read shelf: %v", err)
		}
	}
	var shelfProto pb.Shelf
	err = proto.UnmarshalText(string(data), &shelfProto)
	if err != nil {
		return nil, fmt.Errorf("could not unmarshal shelf: %v", err)
	}

	res := &shelf{
		path: path,
		data: make(map[shelfKey]shelfValue),
	}

	for _, e := range shelfProto.Entry {
		k := shelfKey{
			importpath: e.ImportPath,
			version:    e.Version,
		}
		v := shelfValue{
			l: &locked{
				bazelName: e.BazelName,
				sum:       e.Sum,
				semver:    e.Semver,
			},
		}
		res.data[k] = v
	}
	return res, nil
}

// get retrieves a given lock entry from the in-memory shelf.
func (s *shelf) get(importpath, version string) *locked {
	res, ok := s.data[shelfKey{importpath: importpath, version: version}]
	if !ok {
		return nil
	}
	return res.l
}

// put stores a given locked entry in memory. This will not be commited to disk until .save() is called.
func (s *shelf) put(importpath, version string, l *locked) {
	s.data[shelfKey{importpath: importpath, version: version}] = shelfValue{l: l}
}

// save commits the shelf to disk (to the same location it was loaded from), fully overwriting from in-memory data.
func (s *shelf) save() error {
	// Build proto representation of shelf data.
	var shelfProto pb.Shelf
	for k, v := range s.data {
		shelfProto.Entry = append(shelfProto.Entry, &pb.Shelf_Entry{
			ImportPath: k.importpath,
			Version:    k.version,
			BazelName:  v.l.bazelName,
			Sum:        v.l.sum,
			Semver:     v.l.semver,
		})
	}

	// Sort shelf keys by importpath, then by version.
	sort.Slice(shelfProto.Entry, func(i, j int) bool {
		a := shelfProto.Entry[i]
		b := shelfProto.Entry[j]

		if a.ImportPath < b.ImportPath {
			return true
		}
		if a.ImportPath > b.ImportPath {
			return false
		}
		return a.Version < b.Version
	})

	// Make an in-memory representation of the marshaled shelf.
	buf := bytes.NewBuffer(nil)
	err := proto.MarshalText(buf, &shelfProto)
	if err != nil {
		return fmt.Errorf("could not serialize shelf: %v", err)
	}

	// And write it out.
	err = ioutil.WriteFile(s.path, buf.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("could not write shelf: %v", err)
	}

	return nil
}
