package processor

import (
	"apskel-pos-be/internal/mappers"
	"apskel-pos-be/internal/models"
	"apskel-pos-be/internal/repository"
	"context"
	"fmt"
	"math/rand"
	"time"
)

type VoucherProcessor struct {
	voucherRepo *repository.VoucherRepository
}

func NewVoucherProcessor(voucherRepo *repository.VoucherRepository) *VoucherProcessor {
	return &VoucherProcessor{
		voucherRepo: voucherRepo,
	}
}

// GetRandomVouchersForSpin retrieves random vouchers for spin feature
func (p *VoucherProcessor) GetRandomVouchersForSpin(ctx context.Context, req *models.ListVouchersForSpinRequest) (*models.ListVouchersForSpinResponse, error) {
	// Set default limit if not provided
	limit := req.Limit
	if limit <= 0 {
		limit = 10 // Default limit
	}
	if limit > 50 {
		limit = 50 // Max limit
	}

	// Get random vouchers from repository
	vouchers, err := p.voucherRepo.GetRandomVouchers(ctx, limit)
	if err != nil {
		return nil, fmt.Errorf("failed to get random vouchers: %w", err)
	}

	// Convert to spin response format
	voucherResponses := make([]models.VoucherSpinResponse, len(vouchers))
	for i, voucher := range vouchers {
		voucherResponses[i] = *mappers.VoucherEntityToSpinResponse(&voucher)
	}

	return &models.ListVouchersForSpinResponse{
		Vouchers: voucherResponses,
		Count:    len(voucherResponses),
	}, nil
}

// GetVoucherByID retrieves a voucher by ID
func (p *VoucherProcessor) GetVoucherByID(ctx context.Context, voucherID int64) (*models.VoucherResponse, error) {
	voucher, err := p.voucherRepo.GetByID(ctx, voucherID)
	if err != nil {
		return nil, fmt.Errorf("voucher not found: %w", err)
	}

	return mappers.VoucherEntityToResponse(voucher), nil
}

// GetVoucherByCode retrieves a voucher by voucher code
func (p *VoucherProcessor) GetVoucherByCode(ctx context.Context, voucherCode string) (*models.VoucherResponse, error) {
	voucher, err := p.voucherRepo.GetByVoucherCode(ctx, voucherCode)
	if err != nil {
		return nil, fmt.Errorf("voucher not found: %w", err)
	}

	return mappers.VoucherEntityToResponse(voucher), nil
}

// ListVouchers retrieves vouchers with pagination
func (p *VoucherProcessor) ListVouchers(ctx context.Context, page, limit int) (*models.PaginatedVoucherResponse, error) {
	offset := (page - 1) * limit

	vouchers, total, err := p.voucherRepo.List(ctx, offset, limit)
	if err != nil {
		return nil, fmt.Errorf("failed to list vouchers: %w", err)
	}

	// Convert to response format
	voucherResponses := make([]models.VoucherResponse, len(vouchers))
	for i, voucher := range vouchers {
		voucherResponses[i] = *mappers.VoucherEntityToResponse(&voucher)
	}

	totalPages := int((total + int64(limit) - 1) / int64(limit))

	return &models.PaginatedVoucherResponse{
		Data:       voucherResponses,
		TotalCount: int(total),
		Page:       page,
		Limit:      limit,
		TotalPages: totalPages,
	}, nil
}

// GetRandomVouchersByRows retrieves random vouchers organized into rows
func (p *VoucherProcessor) GetRandomVouchersByRows(ctx context.Context, req *models.ListVouchersByRowsRequest) (*models.ListVouchersByRowsResponse, error) {
	// Set default values if not provided
	rows := req.Rows
	if rows <= 0 {
		rows = 4 // Default to 4 rows
	}
	if rows > 10 {
		rows = 10 // Max 10 rows
	}

	// Get random vouchers organized by rows
	voucherRows, err := p.voucherRepo.GetRandomVouchersByRows(ctx, rows, req.WinnerNumber)
	if err != nil {
		return nil, fmt.Errorf("failed to get random vouchers by rows: %w", err)
	}

	// Convert to response format and select winners
	responseRows := make([]models.VoucherRow, len(voucherRows))
	totalVouchers := 0

	for i, row := range voucherRows {
		vouchers := make([]models.VoucherSpinResponse, len(row))

		// Select a random winner from this row if there are vouchers
		if len(row) > 0 {
			// Select random winner
			rand.Seed(time.Now().UnixNano() + int64(i)) // Add row index for different seed
			winnerIndex := rand.Intn(len(row))

			// Mark as winner in database
			err := p.voucherRepo.MarkAsWinner(ctx, row[winnerIndex].ID)
			if err != nil {
				// Log error but continue - don't fail the entire request
				fmt.Printf("Failed to mark voucher %d as winner: %v\n", row[winnerIndex].ID, err)
			} else {
				// Update the voucher object to reflect the change
				row[winnerIndex].IsWinner = true
			}
		}

		// Convert all vouchers to response format
		for j, voucher := range row {
			vouchers[j] = *mappers.VoucherEntityToSpinResponse(&voucher)
		}

		responseRows[i] = models.VoucherRow{
			RowNumber: i + 1, // Row numbers start from 1
			Vouchers:  vouchers,
		}
		totalVouchers += len(row)
	}

	return &models.ListVouchersByRowsResponse{
		Rows:          responseRows,
		TotalRows:     len(responseRows),
		TotalVouchers: totalVouchers,
	}, nil
}
