<?php
/**
 * Import Validator Class
 * 
 * This class handles validation of import records and generates file numbers
 */
class ImportValidator {
    private $conn;
    private $importType;
    
    /**
     * Constructor
     * 
     * @param mysqli $conn Database connection
     * @param string $importType Type of import (transit_shipment or local_shipment)
     */
    public function __construct($conn, $importType) {
        $this->conn = $conn;
        $this->importType = $importType;
    }
    
    /**
     * Validate a single record
     * 
     * @param array $recordData The record data
     * @param array $columns Column configuration
     * @return array Validation result
     */
    public function validateRecord($recordData, $columns) {
        $errors = [];
        $warnings = [];
        $isValid = true;
        
        // Validate each field based on its configuration
        foreach ($columns as $column) {
            $fieldName = $column['field_name'];
            $fieldValue = $recordData[$fieldName] ?? null;
            
            // Check required fields
            if ($column['is_required'] && (is_null($fieldValue) || trim($fieldValue) === '')) {
                $errors[] = "{$column['display_name']} is required.";
                $isValid = false;
                continue;
            }
            
            // Skip validation for empty optional fields
            if ((!isset($fieldValue) || trim($fieldValue) === '') && !$column['is_required']) {
                continue;
            }
            
            // Apply validation rules
            if (!empty($column['validation_rules'])) {
                $validationErrors = $this->applyValidationRules($fieldName, $fieldValue, $column['validation_rules'], $column['field_type']);
                
                if (!empty($validationErrors)) {
                    $errors = array_merge($errors, $validationErrors);
                    $isValid = false;
                }
            }
            
            // Special validation for specific fields
            switch ($fieldName) {
                case 'customer':
                    if (!$this->validateCustomerId($fieldValue)) {
                        $errors[] = "Invalid customer reference. Customer not found.";
                        $isValid = false;
                    }
                    break;
                
                case 'transporter':
                    if (!empty($fieldValue) && !$this->validateTransporterId($fieldValue)) {
                        $errors[] = "Invalid transporter reference. Transporter not found.";
                        $isValid = false;
                    }
                    break;
                
                case 'destination':
                    if (!$this->validateDestination($fieldValue)) {
                        $errors[] = "Invalid destination format. Should be in format: XX-YY (e.g., RW-KI).";
                        $isValid = false;
                    }
                    break;
                
                case 'container_size':
                    if (!in_array($fieldValue, ['20', '40', '40HC'])) {
                        $errors[] = "Invalid container size. Allowed values: 20, 40, 40HC.";
                        $isValid = false;
                    }
                    break;
            }
        }
        
        // Generate a file number if the record is valid
        $generatedFileNumber = null;
        if ($isValid) {
            try {
                $generatedFileNumber = $this->generateFileNumber($recordData);
            } catch (Exception $e) {
                $errors[] = "Error generating file number: " . $e->getMessage();
                $isValid = false;
            }
        }
        
        return [
            'is_valid' => $isValid,
            'errors' => $errors,
            'warnings' => $warnings,
            'generated_file_number' => $generatedFileNumber
        ];
    }
    
    /**
     * Apply validation rules to a field
     * 
     * @param string $fieldName Field name
     * @param mixed $fieldValue Field value
     * @param array $rules Validation rules
     * @param string $fieldType Field type
     * @return array Validation errors
     */
    private function applyValidationRules($fieldName, $fieldValue, $rules, $fieldType) {
        $errors = [];
        
        // Basic type validation
        switch ($fieldType) {
            case 'number':
                if (!is_numeric($fieldValue)) {
                    $errors[] = "$fieldName must be a number.";
                } else {
                    // Validate numeric rules
                    if (isset($rules['min']) && floatval($fieldValue) < $rules['min']) {
                        $errors[] = "$fieldName must be at least {$rules['min']}.";
                    }
                    
                    if (isset($rules['max']) && floatval($fieldValue) > $rules['max']) {
                        $errors[] = "$fieldName must not exceed {$rules['max']}.";
                    }
                }
                break;
                
            case 'date':
                $date = date_create_from_format('Y-m-d', $fieldValue);
                if (!$date && $fieldValue !== '') {
                    $errors[] = "$fieldName must be a valid date in YYYY-MM-DD format.";
                }
                break;
                
            case 'select':
                if (isset($rules['values']) && !in_array($fieldValue, $rules['values'])) {
                    $validValues = implode(', ', $rules['values']);
                    $errors[] = "$fieldName must be one of: $validValues.";
                } elseif (isset($rules['source'])) {
                    // This is handled in special validation
                }
                break;
                
            case 'text':
            case 'textarea':
                if (isset($rules['min_length']) && strlen($fieldValue) < $rules['min_length']) {
                    $errors[] = "$fieldName must be at least {$rules['min_length']} characters.";
                }
                
                if (isset($rules['max_length']) && strlen($fieldValue) > $rules['max_length']) {
                    $errors[] = "$fieldName must not exceed {$rules['max_length']} characters.";
                }
                
                if (isset($rules['pattern'])) {
                    if (!preg_match($rules['pattern'], $fieldValue)) {
                        $errors[] = "$fieldName has an invalid format.";
                    }
                }
                break;
        }
        
        return $errors;
    }
    
    /**
     * Validate a customer ID
     * 
     * @param mixed $customerId Customer ID
     * @return bool True if valid, false otherwise
     */
    private function validateCustomerId($customerId) {
        $stmt = $this->conn->prepare("SELECT COUNT(*) as count FROM customers WHERE customer_id = ?");
        $stmt->bind_param("i", $customerId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        
        return ($row['count'] > 0);
    }
    
    /**
     * Validate a transporter ID
     * 
     * @param mixed $transporterId Transporter ID
     * @return bool True if valid, false otherwise
     */
    private function validateTransporterId($transporterId) {
        $stmt = $this->conn->prepare("SELECT COUNT(*) as count FROM transporter_info WHERE id = ?");
        $stmt->bind_param("i", $transporterId);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        
        return ($row['count'] > 0);
    }
    
    /**
     * Validate a destination
     * 
     * @param string $destination Destination
     * @return bool True if valid, false otherwise
     */
    private function validateDestination($destination) {
        // Expected format: XX-YY (e.g., RW-KI)
        return preg_match('/^[A-Z]{2}-[A-Z]{2}$/', $destination);
    }
    
    /**
     * Generate a file number based on import type and destination
     * 
     * @param array $recordData Record data
     * @return string Generated file number
     */
    private function generateFileNumber($recordData) {
        $destination = $recordData['destination'] ?? '';
        
        if (empty($destination)) {
            throw new Exception("Destination is required to generate a file number.");
        }
        
        // Split the destination into country and city
        list($country, $city) = explode('-', $destination);
        
        // Get current year (YY format)
        $year = date('y');
        
        // Get the last used number for this prefix combination
        $query = "SELECT file_number FROM files 
                  WHERE file_number LIKE 'RFT/{$country}/{$city}/%/{$year}' 
                  ORDER BY id DESC LIMIT 1";
        
        $result = $this->conn->query($query);
        
        if ($result && $result->num_rows > 0) {
            $row = $result->fetch_assoc();
            $lastFileNumber = $row['file_number'];
            
            // Extract the numeric part
            $parts = explode('/', $lastFileNumber);
            $lastNumber = intval($parts[3]);
            $newNumber = $lastNumber + 1;
        } else {
            // No existing records for this combination, check if there's a general numbering scheme
            $query = "SELECT file_number FROM files 
                      WHERE file_number LIKE 'RFT/%/%/%/{$year}' 
                      ORDER BY id DESC LIMIT 1";
            
            $result = $this->conn->query($query);
            
            if ($result && $result->num_rows > 0) {
                $row = $result->fetch_assoc();
                $lastFileNumber = $row['file_number'];
                
                // Extract the numeric part
                $parts = explode('/', $lastFileNumber);
                $lastNumber = intval($parts[3]);
                $newNumber = $lastNumber + 1;
            } else {
                // No existing records at all for this year, start with 1
                $newNumber = 1;
            }
        }
        
        // Format with leading zeros (3 digits)
        $formattedNumber = sprintf("%03d", $newNumber);
        
        // Construct the file number in format RFT/XX/YY/NNN/YY
        $fileNumber = "RFT/{$country}/{$city}/{$formattedNumber}/{$year}";
        
        return $fileNumber;
    }
}
?>