package ledger

import (
	"context"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

// Ledger handles double-entry accounting
type Ledger struct {
	db *pgxpool.Pool
}

// NewLedger creates a new ledger
func NewLedger(db *pgxpool.Pool) *Ledger {
	return &Ledger{db: db}
}

// Entry represents a ledger entry
type Entry struct {
	ID          string
	CustomerID  string
	AccountType string // "asset", "liability", "equity"
	Amount      string
	Currency    string
	Description string
	Reference   string
	CreatedAt   time.Time
}

// CreateEntry creates a double-entry ledger entry
func (l *Ledger) CreateEntry(ctx context.Context, debit, credit *Entry) error {
	tx, err := l.db.Begin(ctx)
	if err != nil {
		return fmt.Errorf("failed to begin transaction: %w", err)
	}
	defer tx.Rollback(ctx)

	// Insert debit entry
	debitQuery := `
		INSERT INTO ledger_entries (
			customer_id, account_type, amount, currency, description, reference, side, created_at
		) VALUES ($1, $2, $3, $4, $5, $6, 'debit', NOW())
	`
	_, err = tx.Exec(ctx, debitQuery,
		debit.CustomerID, debit.AccountType, debit.Amount, debit.Currency,
		debit.Description, debit.Reference,
	)
	if err != nil {
		return fmt.Errorf("failed to create debit entry: %w", err)
	}

	// Insert credit entry
	creditQuery := `
		INSERT INTO ledger_entries (
			customer_id, account_type, amount, currency, description, reference, side, created_at
		) VALUES ($1, $2, $3, $4, $5, $6, 'credit', NOW())
	`
	_, err = tx.Exec(ctx, creditQuery,
		credit.CustomerID, credit.AccountType, credit.Amount, credit.Currency,
		credit.Description, credit.Reference,
	)
	if err != nil {
		return fmt.Errorf("failed to create credit entry: %w", err)
	}

	return tx.Commit(ctx)
}

// GetBalance gets account balance for a customer
func (l *Ledger) GetBalance(ctx context.Context, customerID, accountType string) (string, error) {
	query := `
		SELECT 
			SUM(CASE WHEN side = 'debit' THEN amount::numeric ELSE -amount::numeric END) as balance
		FROM ledger_entries
		WHERE customer_id = $1 AND account_type = $2
	`

	var balance string
	err := l.db.QueryRow(ctx, query, customerID, accountType).Scan(&balance)
	if err != nil {
		return "0", nil
	}

	return balance, nil
}

