package restic

import (
	"context"
	"fmt"
	"os"
	"restic/errors"
	"time"
)

// ErrNoSnapshotFound is returned when no snapshot for the given criteria could be found.
var ErrNoSnapshotFound = errors.New("no snapshot found")

// FindLatestSnapshot finds latest snapshot with optional target/directory, tags and hostname filters.
func FindLatestSnapshot(ctx context.Context, repo Repository, targets []string, tagLists []TagList, hostname string) (ID, error) {
	var (
		latest   time.Time
		latestID ID
		found    bool
	)

	for snapshotID := range repo.List(ctx, SnapshotFile) {
		snapshot, err := LoadSnapshot(ctx, repo, snapshotID)
		if err != nil {
			return ID{}, errors.Errorf("Error listing snapshot: %v", err)
		}
		if snapshot.Time.Before(latest) || (hostname != "" && hostname != snapshot.Hostname) {
			continue
		}

		if !snapshot.HasTagList(tagLists) {
			continue
		}

		if !snapshot.HasPaths(targets) {
			continue
		}

		latest = snapshot.Time
		latestID = snapshotID
		found = true
	}

	if !found {
		return ID{}, ErrNoSnapshotFound
	}

	return latestID, nil
}

// FindSnapshot takes a string and tries to find a snapshot whose ID matches
// the string as closely as possible.
func FindSnapshot(repo Repository, s string) (ID, error) {

	// find snapshot id with prefix
	name, err := Find(repo.Backend(), SnapshotFile, s)
	if err != nil {
		return ID{}, err
	}

	return ParseID(name)
}

// FindFilteredSnapshots yields Snapshots filtered from the list of all
// snapshots.
func FindFilteredSnapshots(ctx context.Context, repo Repository, host string, tags []TagList, paths []string) Snapshots {
	results := make(Snapshots, 0, 20)

	for id := range repo.List(ctx, SnapshotFile) {
		sn, err := LoadSnapshot(ctx, repo, id)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not load snapshot %v: %v\n", id.Str(), err)
			continue
		}
		if (host != "" && host != sn.Hostname) || !sn.HasTagList(tags) || !sn.HasPaths(paths) {
			continue
		}

		results = append(results, sn)
	}
	return results
}