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

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"testing"
	"time"

	"golang.org/x/telemetry/internal/mmap"
	"golang.org/x/telemetry/internal/telemetry"
	"golang.org/x/telemetry/internal/testenv"
)

// this test traces the life of a counter from creation
// through two file.rotate()s, followed by a failure to rotate
func TestRotateCounters(t *testing.T) {
	testenv.SkipIfUnsupportedPlatform(t)
	t.Logf("GOOS %s GOARCH %s", runtime.GOOS, runtime.GOARCH)
	setup(t)
	defer restore()

	now := getnow()
	CounterTime = func() time.Time { return now }

	var f file
	defer close(&f)
	c := f.New("gophers")
	if c.ptr.count != nil {
		t.Error("new counter has non-nil ptr.count")
	}
	c.Inc() // make sure neither hits Counter.add()
	c.Inc() // second use takes a different code path
	// at this point c.file is not mapped so c's value is stored in extra.
	if c.ptr.count != nil {
		t.Error("counter without mapped file has non-nil ptr.count")
	}
	if c.file.current.Load() != nil {
		t.Error("counter has mapped file unexpectedly")
	}
	state := c.state.load()
	if state.extra() != 2 {
		// the value of c is in its extra field
		t.Errorf("got %d, expected 2", state.extra())
	}
	// Read should give the same answer
	if v, err := Read(c); err != nil || v != 2 {
		t.Errorf("Read got %d, %v, expected 2, nil", v, err)
	}
	f.rotate()
	c.Inc() // this goes through counter.add() safely
	if c.file.current.Load() == nil {
		t.Error("rotated file has no mapping")
	}
	// rotate called c.releaseLock(), moving c's value from extra to the file
	state = c.state.load()
	if state.extra() != 0 {
		t.Errorf("got %d, expected 0", state.extra())
	}
	if c.ptr.count == nil {
		t.Errorf("c has unexpected nil ptr")
	} else if c.ptr.count.Load() != 3 {
		// the value of c is in the mapped file
		t.Errorf("got %d, expected 3", c.ptr.count.Load())
	}
	// and Read should give the same result
	if v, err := Read(c); err != nil || v != 3 {
		t.Errorf("Read gave %d, %v, expected 3, nil", v, err)
	}

	// move into the future and rotate the file, remapping it
	now = now.Add(7 * 24 * time.Hour)
	f.rotate()
	if got, want := f.timeBegin.Format("2006-01-02"), now.Format("2006-01-02"); got != want {
		t.Errorf("f.timeBegin = %q, want %q", got, want)
	}

	// c has value 0 in the new file
	// but c won't have a pointer until the next Inc()
	state = c.state.load()
	if c.ptr.count == nil {
		t.Errorf("c unexpedtedly has nil ptr")
	} else if state.havePtr() {
		t.Error("unexpected pointer")
	}
	if state.extra() != 0 {
		t.Errorf("got %d, expected 0", state.extra())
	}
	c.Inc()
	state = c.state.load()
	if state.extra() != 0 {
		// as expected
		t.Errorf("got %d, expected 0", state.extra())
	}
	if !state.havePtr() {
		t.Errorf("expectd havePtr")
	}
	if c.ptr.count == nil || c.ptr.count.Load() != 1 {
		t.Errorf("c has wrong value")
	}
	// add a counter
	y := f.New("counter")

	// simulate failure to remap
	oldmap := memmap
	now = now.Add(7 * 24 * time.Hour)
	memmap = func(*os.File, *mmap.Data) (mmap.Data, error) { return mmap.Data{}, fmt.Errorf("too bad") }
	f.rotate()
	memmap = oldmap

	// no mapping
	if f.current.Load() != nil {
		t.Errorf("unexpected mapping")
	}
	c.Inc()
	// c should not have a pointer, but its internal
	// count should have been incremented
	if c.ptr.count != nil {
		t.Error("expected nil ptr")
	}
	if c.state.load().extra() != 1 {
		t.Errorf("got %d, but expected extra to be 1", c.state.load().extra())
	}
	// make sure a new counter doesn't fault
	x := f.New("newcounter")
	x.Inc()
	if x.state.load().extra() != 1 {
		t.Errorf("got %d, but expected extra to be 1", c.state.load().extra())
	}
	// make sure an existing unused counter doesn't fault
	// (it's incremented, but not visible externally)
	y.Inc()
	if y.state.load().extra() != 1 {
		t.Errorf("got %d, but expected extra to be 1", c.state.load().extra())
	}
}

// return the current date according to counterTime()
func getnow() time.Time {
	year, month, day := CounterTime().Date()
	now := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
	return now
}

func TestRotate(t *testing.T) {
	testenv.SkipIfUnsupportedPlatform(t)

	t.Logf("GOOS %s GOARCH %s", runtime.GOOS, runtime.GOARCH)
	now := getnow()
	setup(t)
	defer restore()
	// pretend something was uploaded
	os.WriteFile(filepath.Join(telemetry.Default.UploadDir(), "anything"), []byte{}, 0666)
	var f file
	defer close(&f)
	c := f.New("gophers")
	c.Inc()
	var modified int
	for i := 0; i < 2; i++ {
		// nothing should change on the second rotate
		f.rotate()
		fi, err := os.ReadDir(telemetry.Default.LocalDir())
		if err != nil || len(fi) != 2 {
			t.Fatalf("err=%v, len(fi) = %d, want 2", err, len(fi))
		}
		x := fi[0].Name()
		y := x[len(x)-len("2006-01-02")-len(".v1.count") : len(x)-len(".v1.count")]
		us, err := time.ParseInLocation("2006-01-02", y, time.UTC)
		if err != nil {
			t.Fatal(err)
		}
		// we expect today's date?
		if us != now {
			t.Errorf("us = %v, want %v, i=%d y=%s", us, now, i, y)
		}
		fd, err := os.Open(filepath.Join(telemetry.Default.LocalDir(), fi[0].Name()))
		if err != nil {
			t.Fatal(err)
		}
		stat, err := fd.Stat()
		if err != nil {
			t.Fatal(err)
		}
		mt := stat.ModTime().Nanosecond()
		if modified == 0 {
			modified = mt
		}
		if modified != mt {
			t.Errorf("modified = %v, want %v", mt, modified)
		}
		fd.Close()
	}
	CounterTime = func() time.Time { return now.Add(7 * 24 * time.Hour) }
	f.rotate()
	fi, err := os.ReadDir(telemetry.Default.LocalDir())
	if err != nil || len(fi) != 3 {
		t.Fatalf("err=%v, len(fi) = %d, want 3", err, len(fi))
	}
}

// These were useful while debugging failed mapping
func (s *counterState) String() string {
	if s == nil {
		return "nil"
	}
	return s.load().String()
}

func (b counterStateBits) String() string {
	rdrs := b.readers()
	locked := b.locked()
	if locked {
		rdrs = 0 // rdrs == 1<<30 - 1
	}
	havePtr := b&stateHavePtr != 0
	extra := uint64(b&stateExtra) >> stateExtraShift
	return fmt.Sprintf("rdrs:0x%x locked:%v\thavePtr:%v\textra:%d", rdrs, locked, havePtr, extra)
}
