package usecase

import (
	"context"
	"testing"
	"time"

	"github.com/gofrs/uuid/v5"
	"github.com/saveinmed/backend-go/internal/domain"
)

func TestGetFormattedLedgerPaginationDefaults(t *testing.T) {
	svc, repo := newTestService()
	ctx := context.Background()
	companyID := uuid.Must(uuid.NewV7())

	repo.ledgerEntries = []domain.LedgerEntry{
		{ID: uuid.Must(uuid.NewV7()), CompanyID: companyID, AmountCents: 100, Type: "SALE", Description: "Sale 1"},
		{ID: uuid.Must(uuid.NewV7()), CompanyID: companyID, AmountCents: 200, Type: "SALE", Description: "Sale 2"},
		{ID: uuid.Must(uuid.NewV7()), CompanyID: companyID, AmountCents: -50, Type: "FEE", Description: "Fee"},
	}

	resp, err := svc.GetFormattedLedger(ctx, companyID, 0, 0)
	if err != nil {
		t.Fatalf("failed to get ledger: %v", err)
	}

	if resp.CurrentPage != 1 {
		t.Errorf("expected CurrentPage 1, got %d", resp.CurrentPage)
	}
	if resp.TotalPages != 1 {
		t.Errorf("expected TotalPages 1, got %d", resp.TotalPages)
	}
	if resp.TotalCount != 3 {
		t.Errorf("expected TotalCount 3, got %d", resp.TotalCount)
	}
	if len(resp.Items) != 3 {
		t.Errorf("expected 3 items, got %d", len(resp.Items))
	}
}

func TestGetFormattedLedgerPaginationSlicesResults(t *testing.T) {
	svc, repo := newTestService()
	ctx := context.Background()
	companyID := uuid.Must(uuid.NewV7())

	for i := 0; i < 25; i++ {
		repo.ledgerEntries = append(repo.ledgerEntries, domain.LedgerEntry{
			ID:          uuid.Must(uuid.NewV7()),
			CompanyID:   companyID,
			AmountCents: int64(100 + i),
			Type:        "SALE",
			Description: "Sale",
			CreatedAt:   time.Now(),
		})
	}

	resp, err := svc.GetFormattedLedger(ctx, companyID, 2, 10)
	if err != nil {
		t.Fatalf("failed to get ledger: %v", err)
	}

	if resp.TotalPages != 3 {
		t.Errorf("expected TotalPages 3, got %d", resp.TotalPages)
	}
	if len(resp.Items) != 10 {
		t.Errorf("expected 10 items, got %d", len(resp.Items))
	}
	if resp.Items[0].AmountCents != 110 {
		t.Errorf("expected first item amount 110, got %d", resp.Items[0].AmountCents)
	}
}

func TestRequestWithdrawalValidatesAmount(t *testing.T) {
	svc, repo := newTestService()
	ctx := context.Background()
	companyID := uuid.Must(uuid.NewV7())
	repo.balance = 100000

	_, err := svc.RequestWithdrawal(ctx, companyID, 0, "Bank Info")
	if err == nil {
		t.Error("expected error for zero amount")
	}
}

func TestRequestWithdrawalStoresLedgerAndWithdrawal(t *testing.T) {
	svc, repo := newTestService()
	ctx := context.Background()
	companyID := uuid.Must(uuid.NewV7())
	repo.balance = 90000

	withdrawal, err := svc.RequestWithdrawal(ctx, companyID, 45000, "Bank Info")
	if err != nil {
		t.Fatalf("failed to request withdrawal: %v", err)
	}

	if len(repo.ledgerEntries) != 1 {
		t.Fatalf("expected 1 ledger entry, got %d", len(repo.ledgerEntries))
	}
	if repo.ledgerEntries[0].AmountCents != -45000 {
		t.Errorf("expected ledger amount -45000, got %d", repo.ledgerEntries[0].AmountCents)
	}
	if len(repo.withdrawals) != 1 {
		t.Fatalf("expected 1 withdrawal, got %d", len(repo.withdrawals))
	}
	if withdrawal.ID != repo.withdrawals[0].ID {
		t.Errorf("expected withdrawal to be stored in repository")
	}
}

func TestUploadDocumentAndListDocuments(t *testing.T) {
	svc, _ := newTestService()
	ctx := context.Background()
	companyID := uuid.Must(uuid.NewV7())

	_, err := svc.UploadDocument(ctx, companyID, "CNPJ", "http://example.com/doc.pdf")
	if err != nil {
		t.Fatalf("failed to upload document: %v", err)
	}

	docs, err := svc.GetCompanyDocuments(ctx, companyID)
	if err != nil {
		t.Fatalf("failed to list documents: %v", err)
	}
	if len(docs) != 1 {
		t.Errorf("expected 1 document, got %d", len(docs))
	}
	if docs[0].Type != "CNPJ" {
		t.Errorf("expected document type 'CNPJ', got '%s'", docs[0].Type)
	}
}
