package repository

import (
	"context"
	"fmt"

	dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)

func convertDBWallet(wallet dbgen.Wallet) domain.Wallet {
	return domain.Wallet{
		ID:             wallet.ID,
		Balance:        domain.Currency(wallet.Balance),
		IsWithdraw:     wallet.IsWithdraw,
		IsBettable:     wallet.IsBettable,
		IsTransferable: wallet.IsTransferable,
		IsActive:       wallet.IsActive,
		UserID:         wallet.UserID,
		UpdatedAt:      wallet.UpdatedAt.Time,
		CreatedAt:      wallet.CreatedAt.Time,
	}
}

func convertCreateWallet(wallet domain.CreateWallet) dbgen.CreateWalletParams {
	return dbgen.CreateWalletParams{
		IsWithdraw:     wallet.IsWithdraw,
		IsBettable:     wallet.IsBettable,
		IsTransferable: wallet.IsTransferable,
		UserID:         wallet.UserID,
	}
}

func convertDBCustomerWallet(customerWallet dbgen.CustomerWallet) domain.CustomerWallet {
	return domain.CustomerWallet{
		ID:         customerWallet.ID,
		RegularID:  customerWallet.RegularWalletID,
		StaticID:   customerWallet.StaticWalletID,
		CustomerID: customerWallet.CustomerID,
	}
}
func convertCreateCustomerWallet(customerWallet domain.CreateCustomerWallet) dbgen.CreateCustomerWalletParams {
	return dbgen.CreateCustomerWalletParams{
		CustomerID:      customerWallet.CustomerID,
		RegularWalletID: customerWallet.RegularWalletID,
		StaticWalletID:  customerWallet.StaticWalletID,
	}
}

func convertDBGetCustomerWallet(customerWallet dbgen.GetCustomerWalletRow) domain.GetCustomerWallet {
	return domain.GetCustomerWallet{
		ID:               customerWallet.ID,
		RegularID:        customerWallet.RegularID,
		RegularBalance:   domain.Currency(customerWallet.RegularBalance),
		StaticID:         customerWallet.StaticID,
		StaticBalance:    domain.Currency(customerWallet.StaticBalance),
		CustomerID:       customerWallet.CustomerID,
		RegularUpdatedAt: customerWallet.RegularUpdatedAt.Time,
		StaticUpdatedAt:  customerWallet.StaticUpdatedAt.Time,
		CreatedAt:        customerWallet.CreatedAt.Time,
	}
}

func (s *Store) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
	newWallet, err := s.queries.CreateWallet(ctx, convertCreateWallet(wallet))
	if err != nil {
		return domain.Wallet{}, err
	}
	return convertDBWallet(newWallet), nil
}

func (s *Store) CreateCustomerWallet(ctx context.Context, customerWallet domain.CreateCustomerWallet) (domain.CustomerWallet, error) {

	newCustomerWallet, err := s.queries.CreateCustomerWallet(ctx, convertCreateCustomerWallet(customerWallet))
	if err != nil {
		return domain.CustomerWallet{}, err
	}
	return convertDBCustomerWallet(newCustomerWallet), nil
}

func (s *Store) GetWalletByID(ctx context.Context, id int64) (domain.Wallet, error) {
	wallet, err := s.queries.GetWalletByID(ctx, id)

	if err != nil {
		return domain.Wallet{}, err
	}
	return convertDBWallet(wallet), nil
}

func (s *Store) GetAllWallets(ctx context.Context) ([]domain.Wallet, error) {
	wallets, err := s.queries.GetAllWallets(ctx)
	if err != nil {
		return nil, err
	}

	var result []domain.Wallet = make([]domain.Wallet, 0, len(wallets))

	for _, wallet := range wallets {
		result = append(result, convertDBWallet(wallet))
	}
	return result, nil
}

func (s *Store) GetWalletsByUser(ctx context.Context, userID int64) ([]domain.Wallet, error) {
	wallets, err := s.queries.GetWalletByUserID(ctx, userID)
	if err != nil {
		return nil, err
	}

	var result []domain.Wallet = make([]domain.Wallet, 0, len(wallets))

	for _, wallet := range wallets {
		result = append(result, convertDBWallet(wallet))
	}
	return result, nil
}

func (s *Store) GetCustomerWallet(ctx context.Context, customerID int64) (domain.GetCustomerWallet, error) {
	customerWallet, err := s.queries.GetCustomerWallet(ctx, customerID)

	if err != nil {
		return domain.GetCustomerWallet{}, err
	}
	return convertDBGetCustomerWallet(customerWallet), nil
}

func (s *Store) GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error) {
	wallets, err := s.queries.GetAllBranchWallets(ctx)
	if err != nil {
		return nil, err
	}

	var result []domain.BranchWallet = make([]domain.BranchWallet, 0, len(wallets))

	for _, wallet := range wallets {
		result = append(result, domain.BranchWallet{
			ID:              wallet.ID,
			Balance:         domain.Currency(wallet.Balance),
			IsActive:        wallet.IsActive,
			UpdatedAt:       wallet.UpdatedAt.Time,
			CreatedAt:       wallet.CreatedAt.Time,
			Name:            wallet.Name,
			Location:        wallet.Location,
			BranchManagerID: wallet.BranchManagerID,
			CompanyID:       wallet.CompanyID,
			IsSelfOwned:     wallet.IsSelfOwned,
		})
	}
	return result, nil
}

func (s *Store) UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error {
	err := s.queries.UpdateBalance(ctx, dbgen.UpdateBalanceParams{
		ID:      id,
		Balance: int64(balance),
	})
	return err
}

func (s *Store) UpdateWalletActive(ctx context.Context, id int64, isActive bool) error {
	err := s.queries.UpdateWalletActive(ctx, dbgen.UpdateWalletActiveParams{
		ID:       id,
		IsActive: isActive,
	})
	return err
}

// GetBalanceSummary returns wallet balance summary
func (s *Store) GetBalanceSummary(ctx context.Context, filter domain.ReportFilter) (domain.BalanceSummary, error) {
	var summary domain.BalanceSummary

	query := `SELECT
        COALESCE(SUM(balance), 0) as total_balance,
        COALESCE(SUM(CASE WHEN is_active = true THEN balance ELSE 0 END), 0) as active_balance,
        COALESCE(SUM(CASE WHEN is_active = false THEN balance ELSE 0 END), 0) as inactive_balance,
        COALESCE(SUM(CASE WHEN is_bettable = true THEN balance ELSE 0 END), 0) as bettable_balance,
        COALESCE(SUM(CASE WHEN is_bettable = false THEN balance ELSE 0 END), 0) as non_bettable_balance
        FROM wallets`

	args := []interface{}{}
	argPos := 1

	// Add filters if provided
	if filter.CompanyID.Valid {
		query += fmt.Sprintf(" WHERE user_id IN (SELECT id FROM users WHERE company_id = $%d)", argPos)
		args = append(args, filter.CompanyID.Value)
		argPos++
	} else if filter.BranchID.Valid {
		query += fmt.Sprintf(" WHERE user_id IN (SELECT user_id FROM branch_cashiers WHERE branch_id = $%d)", argPos)
		args = append(args, filter.BranchID.Value)
		argPos++
	} else if filter.UserID.Valid {
		query += fmt.Sprintf(" WHERE user_id = $%d", argPos)
		args = append(args, filter.UserID.Value)
		argPos++
	}

	if filter.StartTime.Valid {
		query += fmt.Sprintf(" AND %screated_at >= $%d", func() string {
			if len(args) == 0 {
				return ""
			}
			return " "
		}(), argPos)
		args = append(args, filter.StartTime.Value)
		argPos++
	}
	if filter.EndTime.Valid {
		query += fmt.Sprintf(" AND created_at <= $%d", argPos)
		args = append(args, filter.EndTime.Value)
		argPos++
	}

	row := s.conn.QueryRow(ctx, query, args...)
	err := row.Scan(
		&summary.TotalBalance,
		&summary.ActiveBalance,
		&summary.InactiveBalance,
		&summary.BettableBalance,
		&summary.NonBettableBalance,
	)
	if err != nil {
		return domain.BalanceSummary{}, fmt.Errorf("failed to get balance summary: %w", err)
	}

	return summary, nil
}

func (s *Store) GetTotalWallets(ctx context.Context, filter domain.ReportFilter) (int64, error) {
	query := `SELECT COUNT(*) FROM wallets WHERE is_active = true`
	args := []interface{}{}
	argPos := 1

	// Add filters if provided
	if filter.StartTime.Valid {
		query += fmt.Sprintf(" AND %screated_at >= $%d", func() string {
			if len(args) == 0 {
				return " WHERE "
			}
			return " AND "
		}(), argPos)
		args = append(args, filter.StartTime.Value)
		argPos++
	}
	if filter.EndTime.Valid {
		query += fmt.Sprintf(" AND created_at <= $%d", argPos)
		args = append(args, filter.EndTime.Value)
		argPos++
	}

	var total int64
	row := s.conn.QueryRow(ctx, query, args...)
	err := row.Scan(&total)
	if err != nil {
		return 0, fmt.Errorf("failed to get wallet counts: %w", err)
	}

	return total, nil
}
