// Copyright 2023 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 upload

import (
	"fmt"
	"os"
	"sync"
	"time"

	"golang.org/x/telemetry/internal/counter"
	"golang.org/x/telemetry/internal/telemetry"
)

// time and date handling

var distantPast = 21 * 24 * time.Hour

// reports that are too old (21 days) are not uploaded
func (u *uploader) tooOld(date string, uploadStartTime time.Time) bool {
	t, err := time.Parse(telemetry.DateOnly, date)
	if err != nil {
		u.logger.Printf("tooOld: %v", err)
		return false
	}
	age := uploadStartTime.Sub(t)
	return age > distantPast
}

// counterDateSpan parses the counter file named fname and returns the (begin,
// end) span recorded in its metadata, or an error if this data could not be
// extracted.
func (u *uploader) counterDateSpan(fname string) (begin, end time.Time, _ error) {
	parsed, err := u.parseCountFile(fname)
	if err != nil {
		return time.Time{}, time.Time{}, err
	}
	timeBegin, ok := parsed.Meta["TimeBegin"]
	if !ok {
		return time.Time{}, time.Time{}, fmt.Errorf("missing counter metadata for TimeBegin")
	}
	begin, err = time.Parse(time.RFC3339, timeBegin)
	if err != nil {
		return time.Time{}, time.Time{}, fmt.Errorf("failed to parse TimeBegin: %v", err)
	}
	timeEnd, ok := parsed.Meta["TimeEnd"]
	if !ok {
		return time.Time{}, time.Time{}, fmt.Errorf("missing counter metadata for TimeEnd")
	}
	end, err = time.Parse(time.RFC3339, timeEnd)
	if err != nil {
		return time.Time{}, time.Time{}, fmt.Errorf("failed to parse TimeEnd: %v", err)
	}
	return begin, end, nil
}

// avoid parsing count files multiple times
type parsedCache struct {
	mu sync.Mutex
	m  map[string]*counter.File
}

func (u *uploader) parseCountFile(fname string) (*counter.File, error) {
	u.cache.mu.Lock()
	defer u.cache.mu.Unlock()
	if u.cache.m == nil {
		u.cache.m = make(map[string]*counter.File)
	}
	if f, ok := u.cache.m[fname]; ok {
		return f, nil
	}
	buf, err := os.ReadFile(fname)
	if err != nil {
		return nil, fmt.Errorf("parse ReadFile: %v for %s", err, fname)
	}
	f, err := counter.Parse(fname, buf)
	if err != nil {

		return nil, fmt.Errorf("parse Parse: %v for %s", err, fname)
	}
	u.cache.m[fname] = f
	return f, nil
}
