package paymenthandler

import (
	"testing"
	"time"

	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/stretchr/testify/assert"
)

func TestStripeInvoiceBelongsToMonth(t *testing.T) {
	a := assert.New(t)
	augStart := time.Date(2026, 8, 1, 0, 0, 0, 0, time.UTC)
	sepStart := augStart.AddDate(0, 1, 0)

	// invoice in the target month via its parsed StartDate (newStripeInvoice
	// resolves invoice_start metadata into StartDate before AR consumes it).
	inv := &forms.StripeInvoice{
		StartDate: augStart,
	}
	a.True(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// invoice_start outside the target month -> falls through to merged_months.
	inv = &forms.StripeInvoice{
		StartDate: time.Date(2026, 7, 15, 0, 0, 0, 0, time.UTC),
	}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// auto-push single-month invoice: no invoice_start, merged_months == month.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "2026-08",
		},
	}
	a.True(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// merged carryover batch: merged_months covers older months too; the
	// newest covered month decides attribution.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "2026-06,2026-08",
		},
	}
	a.True(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// merged batch whose newest month is not the target month.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "2026-05,2026-07",
		},
	}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// future month must not leak into the current AR table.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "2026-09",
		},
	}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// no metadata at all.
	inv = &forms.StripeInvoice{}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// empty merged_months.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "",
		},
	}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// garbage tokens in merged_months never equal a "yyyy-mm" target month.
	inv = &forms.StripeInvoice{
		Metadata: map[string]string{
			PushMetadataMergedMonths: "not-a-month,,,2026-08",
		},
	}
	a.False(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))

	// StartDate in target month wins even if merged_months points elsewhere.
	inv = &forms.StripeInvoice{
		StartDate: augStart,
		Metadata: map[string]string{
			PushMetadataMergedMonths: "2026-07",
		},
	}
	a.True(stripeInvoiceBelongsToMonth(inv, augStart, sepStart))
}

func TestInvoicePushMetaFullSet(t *testing.T) {
	a := assert.New(t)
	may := time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC)
	jun := time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC)
	meta := invoicePushMeta([]forms.Invoice{
		{InvoiceID: 11, StartDate: may, EndDate: may.AddDate(0, 0, 1)},
		{InvoiceID: 22, StartDate: jun, EndDate: jun.AddDate(0, 0, 1)},
	}, ChargeModeManual)

	a.Equal("11,22", meta[PushMetadataMergedInvoiceIDs])
	a.Equal("2026-05,2026-06", meta[PushMetadataMergedMonths])
	a.Equal(string(ChargeModeManual), meta[PushMetadataChargeMode])
	a.Equal("1777593600", meta[Start]) // 2026-05-01T00:00:00Z (min start across batch)
	a.Equal("1780358400", meta[End])   // 2026-06-02T00:00:00Z (max end across batch)
}

func TestInvoicePushMetaSingleAndEdge(t *testing.T) {
	a := assert.New(t)

	// Single invoice (Pay path): same shape, its own month and period.
	aug := time.Date(2026, 8, 15, 0, 0, 0, 0, time.UTC)
	meta := invoicePushMeta([]forms.Invoice{
		{InvoiceID: 7, StartDate: aug, EndDate: aug.AddDate(0, 0, 1)},
	}, ChargeModeAuto)
	a.Equal("7", meta[PushMetadataMergedInvoiceIDs])
	a.Equal("2026-08", meta[PushMetadataMergedMonths])
	a.Equal(string(ChargeModeAuto), meta[PushMetadataChargeMode])
	a.Equal("1786752000", meta[Start]) // 2026-08-15T00:00:00Z
	a.Equal("1786838400", meta[End])   // 2026-08-16T00:00:00Z

	// Invoices without a period (carryover rows may carry nil dates on the
	// local side) must not produce zero-time epoch values.
	meta = invoicePushMeta([]forms.Invoice{
		{InvoiceID: 8},
	}, ChargeModeAuto)
	a.Equal("8", meta[PushMetadataMergedInvoiceIDs])
	a.Equal("", meta[PushMetadataMergedMonths])
	_, hasStart := meta[Start]
	_, hasEnd := meta[End]
	a.False(hasStart, "no invoice_start when the batch has no period")
	a.False(hasEnd, "no invoice_end when the batch has no period")

	// Empty batch: charge_mode only.
	meta = invoicePushMeta(nil, ChargeModeAuto)
	a.Len(meta, 1)
	a.Equal(string(ChargeModeAuto), meta[PushMetadataChargeMode])
}
