<?php
/**
 * Invoice Number Service
 *
 * @package Easy_Invoice
 * @subpackage Services
 */

namespace EasyInvoice\Services;

/**
 * InvoiceNumberService Class
 * 
 * Handles automatic generation of invoice numbers based on settings.
 */
class InvoiceNumberService {
    
    /**
     * Generate the next invoice number
     *
     * @return string The generated invoice number
     */
    public function generateNextNumber(): string {
        // Get settings
        $prefix = get_option('easy_invoice_invoice_prefix', 'INV-');
        
        // Get the next number to use
        $next_number = get_option('easy_invoice_next_invoice_number', 1);
        
        // Find the next unique number
        $unique_number = $this->findNextUniqueNumber($next_number, $prefix);
        
        // Update the counter to the number we actually used + 1 for next time
        update_option('easy_invoice_next_invoice_number', $unique_number + 1);
        
        return $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT);
    }
    
    /**
     * Get the next invoice number without incrementing
     *
     * @return string The next invoice number
     */
    public function getNextNumber(): string {
        $prefix = get_option('easy_invoice_invoice_prefix', 'INV-');
        $next_number = get_option('easy_invoice_next_invoice_number', 1);
        
        // Find what the next unique number would be
        $unique_number = $this->findNextUniqueNumber($next_number, $prefix);
        
        return $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT);
    }
    
    /**
     * Reset the invoice number counter
     *
     * @param int $new_starting_number The new starting number
     * @return void
     */
    public function resetCounter(int $new_starting_number = 1): void {
        update_option('easy_invoice_next_invoice_number', $new_starting_number);
    }
    
    /**
     * Check if an invoice number already exists
     *
     * @param string $invoice_number The invoice number to check
     * @return bool True if the number exists, false otherwise
     */
    public function numberExists(string $invoice_number): bool {
        global $wpdb;
        
        $result = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->postmeta} 
            WHERE meta_key = '_easy_invoice_number' 
            AND meta_value = %s",
            $invoice_number
        ));
        
        return intval($result) > 0;
    }
    
    /**
     * Generate a unique invoice number (handles duplicates)
     *
     * @return string A unique invoice number
     */
    public function generateUniqueNumber(): string {
        // Get settings
        $prefix = get_option('easy_invoice_invoice_prefix', 'INV-');
        
        // Get the next number to use from the current settings
        $next_number = get_option('easy_invoice_next_invoice_number', 1);
        
        // Find the next unique number
        $unique_number = $this->findNextUniqueNumber($next_number, $prefix);
        
        // Update the counter to the number we actually used + 1 for next time
        update_option('easy_invoice_next_invoice_number', $unique_number + 1);
        
        $final_number = $prefix . str_pad($unique_number, 6, '0', STR_PAD_LEFT);
        
        return $final_number;
    }
    
    /**
     * Find the next unique number starting from the given number
     *
     * @param int $start_number The number to start checking from
     * @param string $prefix The prefix to use for checking
     * @return int The next unique number
     */
    private function findNextUniqueNumber(int $start_number, string $prefix): int {
        $current_number = $start_number;
        $max_attempts = 1000; // Prevent infinite loops
        $attempts = 0;
        
        while ($attempts < $max_attempts) {
            $invoice_number = $prefix . str_pad($current_number, 6, '0', STR_PAD_LEFT);
            
            if (!$this->numberExists($invoice_number)) {
                return $current_number;
            }
            
            $current_number++;
            $attempts++;
        }
        
        // If we can't find a unique number, add timestamp to ensure uniqueness
        return $current_number + time();
    }
    
    /**
     * Get the highest invoice number from existing invoices
     *
     * @return int The highest invoice number found
     */
    public function getHighestInvoiceNumber(): int {
        global $wpdb;
        
        $prefix = get_option('easy_invoice_invoice_prefix', 'INV-');
        
        // Get all invoice numbers from the database
        $results = $wpdb->get_results($wpdb->prepare(
            "SELECT meta_value FROM {$wpdb->postmeta} 
            WHERE meta_key = '_easy_invoice_number' 
            AND meta_value LIKE %s
            ORDER BY meta_value DESC
            LIMIT 1",
            $prefix . '%'
        ));
        
        if (empty($results)) {
            return 0;
        }
        
        $highest_number = $results[0]->meta_value;
        
        // Extract the number part (remove prefix and padding)
        $number_part = str_replace($prefix, '', $highest_number);
        $number_part = ltrim($number_part, '0');
        
        return intval($number_part);
    }
    
    /**
     * Format an invoice number with custom formatting
     *
     * @param int $number The number to format
     * @param string $prefix The prefix to use
     * @param int $padding The number of digits to pad to
     * @return string The formatted invoice number
     */
    public function formatNumber(int $number, string $prefix = 'INV-', int $padding = 6): string {
        return $prefix . str_pad($number, $padding, '0', STR_PAD_LEFT);
    }
} 