// Copyright 2022 The Go 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 legacydb

import (
	"fmt"
	"io/fs"
	"path/filepath"
	"reflect"
	"strings"

	"golang.org/x/exp/maps"
	"golang.org/x/exp/slices"
	dbv1 "golang.org/x/vulndb/internal/database"
	"golang.org/x/vulndb/internal/derrors"
	"golang.org/x/vulndb/internal/osv"
	"golang.org/x/vulndb/internal/report"
)

// Load reads the contents of dbPath into a Database, and errors if:
//   - Any files are malformed (cannot be unmarshaled)
//   - The database has missing files (based on the module and ID indexes)
//   - The database has unexpected files not listed in the indexes
//   - The database is internally inconsistent
func Load(dbPath string) (_ *Database, err error) {
	derrors.Wrap(&err, "Load(%s)", dbPath)

	d, err := rawLoad(dbPath)
	if err != nil {
		return nil, err
	}
	if err := d.checkNoUnexpectedFiles(dbPath); err != nil {
		return nil, err
	}
	if err := d.checkInternalConsistency(); err != nil {
		return nil, err
	}

	return d, nil
}

// rawLoad reads the contents of dbPath into a Database, and errors
// if any files are malformed, or the database has missing files
// (based on the module and ID indexes).
func rawLoad(dbPath string) (_ *Database, err error) {
	defer derrors.Wrap(&err, "Load(%q)", dbPath)

	d := &Database{
		Index:      make(DBIndex),
		IDsByAlias: make(IDsByAlias),
	}

	if err := report.UnmarshalFromFile(filepath.Join(dbPath, indexFile), &d.Index); err != nil {
		return nil, fmt.Errorf("invalid or missing index.json: %v", err)
	}

	d.EntriesByModule, err = loadEntriesByModule(dbPath, d.Index)
	if err != nil {
		return nil, err
	}

	d.EntriesByID, err = loadEntriesByID(dbPath)
	if err != nil {
		return nil, err
	}

	if err := report.UnmarshalFromFile(filepath.Join(dbPath, aliasesFile), &d.IDsByAlias); err != nil {
		return nil, fmt.Errorf("invalid or missing aliases.json: %v", err)
	}

	return d, nil
}

func (d *Database) checkNoUnexpectedFiles(dbPath string) error {
	return filepath.WalkDir(dbPath, func(path string, f fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		fname := f.Name()
		ext := filepath.Ext(fname)
		dir := filepath.Dir(path)

		switch {
		// Skip directories.
		case f.IsDir():
			return nil
		// Skip files in the v1 spec.
		case ext == ".gz" || dbv1.IsIndexEndpoint(fname):
			return nil
		// In the top-level directory, web files and index files are OK.
		case dir == dbPath && isIndexOrWebFile(fname, ext):
			return nil
		// All non-directory and non-web files should end in ".json".
		case ext != ".json":
			return fmt.Errorf("found unexpected non-JSON file %s", path)
		// All files in the ID directory (except the index) should have
		// corresponding entries in EntriesByID.
		case dir == filepath.Join(dbPath, idDirectory):
			if fname == indexFile {
				return nil
			}
			id := report.GoID(fname)
			if _, ok := d.EntriesByID[id]; !ok {
				return fmt.Errorf("found unexpected file %q which is not present in %s", fname, filepath.Join(idDirectory, indexFile))
			}
		// All other files should have corresponding entries in
		// EntriesByModule.
		default:
			module := strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(path, dbPath), "/"), ".json")
			unescaped, err := unescapeModulePath(module)
			if err != nil {
				return fmt.Errorf("could not unescape module file %s: %v", path, err)
			}
			if _, ok := d.EntriesByModule[unescaped]; !ok {
				return fmt.Errorf("found unexpected module %q which is not present in %s", unescaped, indexFile)
			}
		}
		return nil
	})
}

func isIndexOrWebFile(filename, ext string) bool {
	return ext == ".ico" ||
		ext == ".html" ||
		// HTML files may have no extension.
		ext == "" ||
		filename == indexFile ||
		filename == aliasesFile
}

func (d *Database) checkInternalConsistency() error {
	if il, ml := len(d.Index), len(d.EntriesByModule); il != ml {
		return fmt.Errorf("length mismatch: there are %d module entries in the index, and %d module directory entries", il, ml)
	}

	for module, modified := range d.Index {
		entries, ok := d.EntriesByModule[module]
		if !ok || len(entries) == 0 {
			return fmt.Errorf("no module directory found for indexed module %s", module)
		}

		var wantModified osv.Time
		for _, entry := range entries {
			if mod := entry.Modified; mod.After(wantModified.Time) {
				wantModified = mod
			}

			entryByID, ok := d.EntriesByID[entry.ID]
			if !ok {
				return fmt.Errorf("no advisory found for ID %s listed in %s", entry.ID, module)
			}
			if !reflect.DeepEqual(entry, entryByID) {
				return fmt.Errorf("inconsistent OSV contents in module and ID advisory for %s", entry.ID)
			}

			var found bool
			for _, affected := range entry.Affected {
				m := affected.Module.Path
				if m == module {
					found = true
					break
				}
			}
			if !found {
				return fmt.Errorf("%s does not reference %s", entry.ID, module)
			}
		}
		if modified != wantModified.Time {
			return fmt.Errorf("incorrect modified timestamp for module %s: want %s, got %s", module, wantModified.Time, modified)
		}
	}

	for id, entry := range d.EntriesByID {
		for _, affected := range entry.Affected {
			module := affected.Module.Path
			entries, ok := d.EntriesByModule[module]
			if !ok || len(entries) == 0 {
				return fmt.Errorf("module %s not found (referenced by %s)", module, id)
			}
			found := false
			for _, gotEntry := range entries {
				if gotEntry.ID == id {
					found = true
					break
				}
			}
			if !found {
				return fmt.Errorf("%s does not have an entry in %s", id, module)
			}
		}
		for _, alias := range entry.Aliases {
			gotEntries, ok := d.IDsByAlias[alias]
			if !ok || len(gotEntries) == 0 {
				return fmt.Errorf("alias %s not found in aliases.json (alias of %s)", alias, id)
			}
			found := false
			for _, gotID := range gotEntries {
				if gotID == id {
					found = true
					break
				}
			}
			if !found {
				return fmt.Errorf("%s is not listed as an alias of %s in aliases.json", entry.ID, alias)
			}
		}
		if entry.Published.After(entry.Modified.Time) {
			return fmt.Errorf("%s: published time (%s) cannot be after modified time (%s)", entry.ID, entry.Published, entry.Modified)
		}
	}

	for alias, goIDs := range d.IDsByAlias {
		for _, goID := range goIDs {
			entry, ok := d.EntriesByID[goID]
			if !ok {
				return fmt.Errorf("no advisory found for %s listed under %s", goID, alias)
			}

			if !slices.Contains(entry.Aliases, alias) {
				return fmt.Errorf("advisory %s does not reference alias %s", goID, alias)
			}
		}
	}

	return nil
}
func loadEntriesByID(dbPath string) (EntriesByID, error) {
	var ids []string
	if err := report.UnmarshalFromFile(filepath.Join(dbPath, idDirectory, indexFile), &ids); err != nil {
		return nil, fmt.Errorf("invalid or missing ID/index.json: %v", err)
	}

	entriesByID := make(EntriesByID, len(ids))
	for _, id := range ids {
		var entry osv.Entry
		err := report.UnmarshalFromFile(filepath.Join(dbPath, idDirectory, id+".json"), &entry)
		if err != nil {
			return nil, fmt.Errorf("invalid or missing OSV file: %v", err)
		}
		entriesByID[id] = &entry
	}
	return entriesByID, nil
}

func loadEntriesByModule(dbPath string, index DBIndex) (EntriesByModule, error) {
	entriesByModule := make(EntriesByModule, len(index))
	for _, module := range maps.Keys(index) {
		emodule, err := escapeModulePath(module)
		if err != nil {
			return nil, err
		}
		fpath := filepath.Join(dbPath, emodule+".json")
		var entries []*osv.Entry
		err = report.UnmarshalFromFile(fpath, &entries)
		if err != nil {
			return nil, fmt.Errorf("invalid or missing module directory: %v", err)
		}
		entriesByModule[module] = entries
	}
	return entriesByModule, nil
}
