package services_astrologer

import (
	"errors"
	"fmt"

	dto "astrology-api/dto_astrologer"
	models "astrology-api/models/astrologermodel"
	repositories_astrologer "astrology-api/repositories_astrologer"
)

type walletService struct {
	repository repositories_astrologer.WalletRepository
}

func NewWalletService(
	repository repositories_astrologer.WalletRepository,
) WalletService {

	return &walletService{
		repository: repository,
	}
}

func (s *walletService) GetWallet(userID uint) (*dto.WalletResponse, error) {

	//------------------------------------------------
	// Validate Astrologer
	//------------------------------------------------

	astrologer, err := s.repository.GetAstrologerByUserID(userID)
	if err != nil {
		return nil, err
	}

	if astrologer == nil {
		return nil, errors.New("astrologer not found")
	}

	//------------------------------------------------
	// Get Wallet
	//------------------------------------------------

	wallet, err := s.repository.GetWallet(userID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Create Wallet First Time
	//------------------------------------------------

	if wallet == nil {

		initialBalance := 0.0

		wallet = &models.UserWallet{
			UserID:     userID,
			Amount:     &initialBalance,
			IsActive:   true,
			IsDelete:   false,
			CreatedBy:  int(userID),
			ModifiedBy: int(userID),
		}

		if err := s.repository.CreateWallet(wallet); err != nil {
			return nil, err
		}
	}

	//------------------------------------------------
	// Fetch Wallet Summary
	//------------------------------------------------

	availableBalance, err := s.repository.GetAvailableBalance(userID)
	if err != nil {
		return nil, err
	}

	lastThreeMonthEarnings, err := s.repository.GetLastThreeMonthEarnings(astrologer.ID)
	if err != nil {
		return nil, err
	}

	monthlyEarnings, err := s.repository.GetMonthlyEarnings(astrologer.ID)
	if err != nil {
		return nil, err
	}

	weeklyEarnings, err := s.repository.GetWeeklyEarnings(astrologer.ID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Pending Earnings
	//------------------------------------------------

	pendingEarnings, err := s.repository.GetPendingEarnings(astrologer.ID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Today's Astromall Earnings
	//------------------------------------------------

	todayAstromallEarnings, err := s.repository.GetTodayAstromallEarnings(astrologer.ID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Payable Amount
	//------------------------------------------------

	payableAmount, err := s.repository.GetPayableAmount(astrologer.ID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Rank
	//------------------------------------------------

	rank, err := s.repository.GetRank(astrologer.ID)
	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Transaction Count
	//------------------------------------------------

	_, transactionCount, err := s.repository.GetTransactions(
		astrologer.ID,
		"ALL",
		1,
		1,
	)

	if err != nil {
		return nil, err
	}

	//------------------------------------------------
	// Prepare Response
	//------------------------------------------------

	summary := dto.WalletSummaryResponse{
		LastThreeMonthEarnings: lastThreeMonthEarnings,
		MonthlyEarnings:        monthlyEarnings,
		WeeklyEarnings:         weeklyEarnings,
		Rank:                   rank,

		AvailableBalance:       availableBalance,
		PayableAmount:          payableAmount,
		TodayAstromallEarnings: todayAstromallEarnings,
		PendingEarnings:        pendingEarnings,

		TransactionCount: int(transactionCount),
	}

	response := &dto.WalletResponse{
		Status:  true,
		Message: "Wallet fetched successfully",
		Data:    summary,
	}

	return response, nil
}

func (s *walletService) GetTransactions(
	userID uint,
	filter string,
	page int,
	limit int,
) ([]dto.WalletTransactionResponse, int64, error) {

	//------------------------------------------------
	// Validate Pagination
	//------------------------------------------------

	if page <= 0 {
		page = 1
	}

	if limit <= 0 {
		limit = 10
	}

	if limit > 100 {
		limit = 100
	}

	//------------------------------------------------
	// Default Filter
	//------------------------------------------------

	if filter == "" {
		filter = "ALL"
	}

	//------------------------------------------------
	// Validate Astrologer
	//------------------------------------------------

	astrologer, err := s.repository.GetAstrologerByUserID(userID)
	if err != nil {
		return nil, 0, err
	}

	if astrologer == nil {
		return nil, 0, errors.New("astrologer not found")
	}

	//------------------------------------------------
	// Get Transactions
	//------------------------------------------------

	transactions, total, err := s.repository.GetTransactions(
		astrologer.ID,
		filter,
		page,
		limit,
	)

	if err != nil {
		return nil, 0, err
	}

	if transactions == nil {
		transactions = []dto.WalletTransactionResponse{}
	}

	return transactions, total, nil
}

func (s *walletService) GetTransactionByID(
	userID uint,
	transactionID uint,
) (*dto.WalletTransactionResponse, error) {

	//------------------------------------------------
	// Validate Astrologer
	//------------------------------------------------

	astrologer, err := s.repository.GetAstrologerByUserID(userID)
	if err != nil {
		return nil, err
	}

	if astrologer == nil {
		return nil, errors.New("astrologer not found")
	}

	//------------------------------------------------
	// Get Transaction
	//------------------------------------------------

	transaction, err := s.repository.GetTransactionByID(transactionID, astrologer.ID)
	if err != nil {
		return nil, err
	}

	if transaction == nil {
		return nil, errors.New("transaction not found")
	}

	//------------------------------------------------
	// Security Check
	//------------------------------------------------

	if transaction.AstrologerID != astrologer.ID {
		return nil, errors.New("you are not authorized to access this transaction")
	}

	//------------------------------------------------
	// Prepare Response
	//------------------------------------------------

	response := &dto.WalletTransactionResponse{
		ID: transaction.ID,
		TransactionID: fmt.Sprintf(
			"%d%d%s",
			transaction.AstrologerID,
			transaction.ID,
			transaction.CreatedAt.Format("20060102150405"),
		),
		ReferenceID:     transaction.ReferenceID,
		TransactionType: transaction.TransactionType,
		CreditAmount:    transaction.Credit,
		DebitAmount:     transaction.Debit,
		BalanceAfter:    transaction.BalanceAfter,
		IsCredit:        transaction.Credit > 0,
		Remarks:         transaction.Remarks,
		Status:          "Success",
	}

	//------------------------------------------------
	// Amount
	//------------------------------------------------

	if transaction.Credit > 0 {
		response.Amount = transaction.Credit
	} else {
		response.Amount = transaction.Debit
	}

	//------------------------------------------------
	// Date Time
	//------------------------------------------------

	if transaction.CreatedAt != nil {
		response.TransactionDate = transaction.CreatedAt.Format("02 Jan 2006")
		response.TransactionTime = transaction.CreatedAt.Format("03:04 PM")
	}

	//------------------------------------------------
	// Title & Icon
	//------------------------------------------------

	switch transaction.TransactionType {

	case "CHAT":
		response.Title = "Chat Earnings"
		response.Icon = "chat"

	case "CALL":
		response.Title = "Call Earnings"
		response.Icon = "call"

	case "REPORT":
		response.Title = "Report Earnings"
		response.Icon = "report"

	case "ASTROMALL":
		response.Title = "Astromall Earnings"
		response.Icon = "shopping"

	case "GIFT":
		response.Title = "Gift Received"
		response.Icon = "gift"

	default:
		response.Title = transaction.TransactionType
		response.Icon = "wallet"
	}

	//------------------------------------------------
	// Description
	//------------------------------------------------

	response.Description = transaction.Remarks

	return response, nil
}

func (s *walletService) GetSettlementHistory(userID uint) ([]dto.WithdrawResponse, error) {

	//------------------------------------------------
	// Validate Astrologer
	//------------------------------------------------

	astrologer, err := s.repository.GetAstrologerByUserID(userID)
	if err != nil {
		return nil, err
	}

	if astrologer == nil {
		return nil, errors.New("astrologer not found")
	}

	//------------------------------------------------
	// Get Settlement History
	//------------------------------------------------

	history, err := s.repository.GetSettlementHistory(astrologer.ID)
	if err != nil {
		return nil, err
	}

	response := make([]dto.WithdrawResponse, 0, len(history))

	for _, item := range history {

		settlement := dto.WithdrawResponse{
			ID:            item.ID,
			Amount:        item.Amount,
			Status:        item.SettlementStatus,
			PaymentMethod: item.PaymentMode,
		}

		if item.CreatedAt != nil {
			settlement.RequestDate = item.CreatedAt.Format("02 Jan 2006 03:04 PM")
		}

		if item.SettlementDate != nil {
			settlement.SettlementDate = item.SettlementDate.Format("02 Jan 2006 03:04 PM")
		}

		response = append(response, settlement)
	}

	return response, nil
}
