<?php

namespace App\Services\Import;

use App\Models\Import;
use App\Models\ImportEntity;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

/**
 * ImportSimulationServiceV2 - Simulates imports using V2 handler architecture.
 *
 * Processes rows using entity handlers without persisting any data to the database.
 * Returns preview data showing what would be created/updated for each row.
 * 
 * Deduplication: Uses EntityResolutionService through handlers to accurately simulate
 * Person resolution from Contract/ClientCase chains, matching production behavior.
 */
class ImportSimulationServiceV2
{
    protected array $handlers = [];

    protected array $entityConfigs = [];

    /**
     * Simulate an import and return preview data.
     *
     * @param  Import  $import  Import record with mappings
     * @param  int  $limit  Maximum number of rows to simulate (default: 100)
     * @param  bool  $verbose  Include detailed information (default: false)
     * @return array Simulation results with row previews and statistics
     */
    public function simulate(Import $import, int $limit = 100, bool $verbose = false): array
    {
        try {
            // Load entity configurations and handlers
            $this->loadEntityConfigurations();

            // Only CSV/TXT supported
            if (! in_array($import->source_type, ['csv', 'txt'])) {
                return $this->errorPayload('Podprti so samo CSV/TXT formati.');
            }

            $filePath = $import->path;
            if (! Storage::disk($import->disk ?? 'local')->exists($filePath)) {
                return $this->errorPayload("Datoteka ni najdena: {$filePath}");
            }

            $fullPath = Storage::disk($import->disk ?? 'local')->path($filePath);
            $fh = fopen($fullPath, 'r');

            if (! $fh) {
                return $this->errorPayload("Datoteke ni mogoče odpreti: {$filePath}");
            }

            $meta = $import->meta ?? [];
            $hasHeader = (bool) ($meta['has_header'] ?? true);
            $delimiter = $meta['forced_delimiter'] ?? $meta['detected_delimiter'] ?? ',';

            $mappings = $this->loadMappings($import);
            if (empty($mappings)) {
                fclose($fh);

                return $this->errorPayload('Ni shranjenih mapiranj za ta uvoz.');
            }

            $header = null;
            $rowNum = 0;

            // Read header if present
            if ($hasHeader) {
                $header = fgetcsv($fh, 0, $delimiter);
                $rowNum++;
            }

            $simRows = [];
            $summaries = $this->initSummaries();
            $rowCount = 0;

            while (($row = fgetcsv($fh, 0, $delimiter)) !== false && $rowCount < $limit) {
                $rowNum++;
                $rowCount++;

                try {
                    $rawAssoc = $this->buildRowAssoc($row, $header);

                    // Skip empty rows
                    if ($this->rowIsEffectivelyEmpty($rawAssoc)) {
                        continue;
                    }

                    $mapped = $this->applyMappings($rawAssoc, $mappings);

                    // Group mapped data by entity (from "entity.field" to nested structure)
                    $groupedMapped = $this->groupMappedDataByEntity($mapped);

                    \Log::info('ImportSimulation: Grouped entities', [
                        'row' => $rowNum,
                        'entity_keys' => array_keys($groupedMapped),
                        'config_roots' => array_keys($this->entityConfigs),
                    ]);

                    // Simulate processing for this row
                    // Context must include 'import' for EntityResolutionService to work
                    $context = [
                        'import' => $import,
                        'simulation' => true,
                    ];

                    $rowResult = $this->simulateRow($import, $groupedMapped, $rawAssoc, $context, $verbose);

                    // Update summaries - handle both single and array results
                    foreach ($rowResult['entities'] ?? [] as $entityKey => $entityDataOrArray) {
                        // Extract entity root from key (e.g., 'person', 'contract', etc.)
                        $root = explode('.', $entityKey)[0];
                        
                        // Handle array of results (grouped entities)
                        if (is_array($entityDataOrArray) && isset($entityDataOrArray[0])) {
                            foreach ($entityDataOrArray as $entityData) {
                                $action = $entityData['action'] ?? 'skip';
                                if (!isset($summaries[$root])) {
                                    $summaries[$root] = ['create' => 0, 'update' => 0, 'skip' => 0, 'invalid' => 0];
                                }
                                $summaries[$root][$action] = ($summaries[$root][$action] ?? 0) + 1;
                            }
                        } else {
                            // Single result
                            $action = $entityDataOrArray['action'] ?? 'skip';
                            if (!isset($summaries[$root])) {
                                $summaries[$root] = ['create' => 0, 'update' => 0, 'skip' => 0, 'invalid' => 0];
                            }
                            $summaries[$root][$action] = ($summaries[$root][$action] ?? 0) + 1;
                        }
                    }

                    $simRows[] = [
                        'row_number' => $rowNum,
                        'raw_data' => $verbose ? $rawAssoc : null,
                        'entities' => $rowResult['entities'],
                        'warnings' => $rowResult['warnings'] ?? [],
                        'errors' => $rowResult['errors'] ?? [],
                    ];
                } catch (\Throwable $e) {
                    $simRows[] = [
                        'row_number' => $rowNum,
                        'raw_data' => $verbose ? ($rawAssoc ?? null) : null,
                        'entities' => [],
                        'warnings' => [],
                        'errors' => [$e->getMessage()],
                    ];
                }
            }

            fclose($fh);

            return [
                'success' => true,
                'total_simulated' => $rowCount,
                'limit' => $limit,
                'summaries' => $summaries,
                'rows' => $simRows,
                'meta' => [
                    'has_header' => $hasHeader,
                    'delimiter' => $delimiter,
                    'mappings_count' => count($mappings),
                ],
            ];
        } catch (\Throwable $e) {
            return $this->errorPayload('Napaka pri simulaciji: '.$e->getMessage());
        }
    }

    /**
     * Simulate processing a single row without database writes.
     * 
     * Updated to match ImportServiceV2 logic:
     * - Process entities in priority order from entity configs
     * - Accumulate entity results in context for chain resolution
     * - Pass proper context to handlers for EntityResolutionService
     */
    protected function simulateRow(Import $import, array $mapped, array $raw, array $context, bool $verbose): array
    {
        $entities = [];
        $warnings = [];
        $errors = [];
        $entityResults = [];

        // Process entities in configured priority order (like ImportServiceV2)
        foreach ($this->entityConfigs as $root => $config) {
            // Check if this entity exists in mapped data
            $mappedKey = $this->findMappedKey($mapped, $root, $config);
            
            if (!$mappedKey || !isset($mapped[$mappedKey])) {
                continue;
            }

            $handler = $this->handlers[$root] ?? null;

            if (!$handler) {
                continue;
            }

            try {
                // Check if this is an array of entities (grouped)
                $entityDataArray = is_array($mapped[$mappedKey]) && isset($mapped[$mappedKey][0]) 
                    ? $mapped[$mappedKey] 
                    : [$mapped[$mappedKey]];
                
                $results = [];
                
                foreach ($entityDataArray as $entityData) {
                    // Validate
                    $validation = $handler->validate($entityData);
                    if (!$validation['valid']) {
                        $results[] = [
                            'action' => 'invalid',
                            'data' => $entityData,
                            'errors' => $validation['errors'],
                        ];
                        continue;
                    }

                    // Skip empty/invalid data that handlers would skip during real import
                    // Phone: skip if nu is 0, empty, or #N/A
                    if ($root === 'phone') {
                        $nu = $entityData['nu'] ?? null;
                        if (empty($nu) || $nu === '0' || $nu === '#N/A' || trim((string)$nu) === '') {
                            continue; // Skip this phone entirely
                        }
                    }
                    
                    // Address: skip if address is empty or #N/A
                    if ($root === 'address') {
                        $address = $entityData['address'] ?? null;
                        if (empty($address) || $address === '#N/A' || trim((string)$address) === '') {
                            continue; // Skip this address entirely
                        }
                    }
                    
                    // Email: skip if value is 0, empty, or #N/A
                    if ($root === 'email') {
                        $email = $entityData['value'] ?? null;
                        if (empty($email) || $email === '0' || $email === '#N/A' || trim((string)$email) === '') {
                            continue; // Skip this email entirely
                        }
                    }

                    // DEBUG: Log context for grouped entities
                    if (in_array($root, ['phone', 'address'])) {
                        Log::info("ImportSimulation: Resolving grouped entity", [
                            'entity' => $root,
                            'data' => $entityData,
                            'has_person_in_context' => isset($entityResults['person']),
                            'person_id' => $entityResults['person']['entity']->id ?? null,
                            'context_keys' => array_keys(array_merge($context, $entityResults)),
                        ]);
                    }

                    // Resolve existing entity (uses EntityResolutionService internally)
                    // Pass accumulated entityResults as context for chain resolution
                    try {
                        $existingEntity = $handler->resolve($entityData, array_merge($context, $entityResults));
                    } catch (\Throwable $resolutionError) {
                        // In simulation mode, resolution may fail due to simulated entities
                        // Just treat as new entity
                        \Log::debug("ImportSimulation: Resolution failed (treating as new)", [
                            'entity' => $root,
                            'error' => $resolutionError->getMessage(),
                        ]);
                        $existingEntity = null;
                    }

                    if ($existingEntity) {
                        // Would update existing
                        $results[] = [
                            'action' => 'update',
                            'reference' => $this->getEntityReference($existingEntity, $root),
                            'existing_id' => $existingEntity->id ?? null,
                            'data' => $entityData,
                            'existing_data' => $verbose ? $this->extractExistingData($existingEntity) : null,
                            'changes' => $verbose ? $this->detectChanges($existingEntity, $entityData) : null,
                        ];
                        
                        // Add to entityResults for subsequent handlers
                        $entityResults[$root] = [
                            'entity' => $existingEntity,
                            'action' => 'updated',
                        ];
                    } else {
                        // Would create new
                        $results[] = [
                            'action' => 'create',
                            'data' => $entityData,
                        ];
                        
                        // Simulate entity creation for context (no actual ID)
                        // Mark as simulated so resolution service knows not to use model methods
                        $simulatedEntity = (object) $entityData;
                        $simulatedEntity->_simulated = true;
                        
                        $entityResults[$root] = [
                            'entity' => $simulatedEntity,
                            'action' => 'inserted',
                            '_simulated' => true,
                        ];
                    }
                }
                
                // Store results (single or array)
                $entities[$mappedKey] = (count($results) === 1) ? $results[0] : $results;
            } catch (\Throwable $e) {
                $entities[$mappedKey] = [
                    'action' => 'error',
                    'errors' => [$e->getMessage()],
                ];
                $errors[] = "{$root}: {$e->getMessage()}";
            }
        }

        return compact('entities', 'warnings', 'errors');
    }

    /**
     * Find the mapped key for an entity (supports aliases and common variations).
     */
    protected function findMappedKey(array $mapped, string $canonicalRoot, $config): ?string
    {
        // Check canonical root exactly
        if (isset($mapped[$canonicalRoot])) {
            return $canonicalRoot;
        }

        // Build comprehensive list of variations
        $variations = [$canonicalRoot];
        
        // Generate plural variations (handle -y endings correctly)
        if (str_ends_with($canonicalRoot, 'y') && !str_ends_with($canonicalRoot, 'ay') && !str_ends_with($canonicalRoot, 'ey')) {
            // activity -> activities
            $variations[] = substr($canonicalRoot, 0, -1) . 'ies';
        } else {
            // address -> addresses
            $variations[] = $canonicalRoot . 's';
        }
        
        // Add singular form (remove trailing s or ies)
        if (str_ends_with($canonicalRoot, 'ies')) {
            $variations[] = substr($canonicalRoot, 0, -3) . 'y'; // activities -> activity
        } else {
            $variations[] = rtrim($canonicalRoot, 's'); // addresses -> address
        }
        
        // Add person_ prefixed versions
        $variations[] = 'person_' . $canonicalRoot;
        
        // person_activity -> person_activities
        if (str_ends_with($canonicalRoot, 'y') && !str_ends_with($canonicalRoot, 'ay') && !str_ends_with($canonicalRoot, 'ey')) {
            $variations[] = 'person_' . substr($canonicalRoot, 0, -1) . 'ies';
        } else {
            $variations[] = 'person_' . $canonicalRoot . 's';
        }
        
        // Special handling: if canonical is 'address', also check 'person_addresses'
        if ($canonicalRoot === 'address') {
            $variations[] = 'person_addresses';
        }
        // Special handling: if canonical is 'phone', also check 'person_phones'
        if ($canonicalRoot === 'phone') {
            $variations[] = 'person_phones';
        }
        // Reverse: if canonical has 'person_', also check without it
        if (str_starts_with($canonicalRoot, 'person_')) {
            $withoutPerson = str_replace('person_', '', $canonicalRoot);
            $variations[] = $withoutPerson;
            // Handle plural variations
            if (str_ends_with($withoutPerson, 'y') && !str_ends_with($withoutPerson, 'ay') && !str_ends_with($withoutPerson, 'ey')) {
                $variations[] = substr($withoutPerson, 0, -1) . 'ies';
            } else {
                $variations[] = rtrim($withoutPerson, 's');
                $variations[] = $withoutPerson . 's';
            }
        }
        
        $variations = array_unique($variations);

        foreach ($variations as $variation) {
            if (isset($mapped[$variation])) {
                \Log::debug("ImportSimulation: Matched entity", [
                    'canonical_root' => $canonicalRoot,
                    'matched_key' => $variation,
                ]);
                return $variation;
            }
        }

        // Check aliases if configured
        if (isset($config->options['aliases'])) {
            $aliases = is_array($config->options['aliases']) ? $config->options['aliases'] : [];
            foreach ($aliases as $alias) {
                if (isset($mapped[$alias])) {
                    return $alias;
                }
            }
        }

        \Log::debug("ImportSimulation: No match found for entity", [
            'canonical_root' => $canonicalRoot,
            'tried_variations' => array_slice($variations, 0, 5),
            'available_keys' => array_keys($mapped),
        ]);

        return null;
    }

    /**
     * Group mapped data by entity from "entity.field" format to nested structure.
     * Handles both single values and arrays (for grouped entities like multiple addresses).
     * 
     * Special handling:
     * - activity.note arrays are kept together (single activity with multiple notes)
     * - Other array values create separate entity instances (e.g., multiple addresses)
     * 
     * Input: ['person.first_name' => 'John', 'person.last_name' => 'Doe', 'email.value' => ['a@b.com', 'c@d.com']]
     * Output: ['person' => ['first_name' => 'John', 'last_name' => 'Doe'], 'email' => [['value' => 'a@b.com'], ['value' => 'c@d.com']]]
     */
    protected function groupMappedDataByEntity(array $mapped): array
    {
        $grouped = [];

        foreach ($mapped as $key => $value) {
            if (!str_contains($key, '.')) {
                continue;
            }

            [$entity, $field] = explode('.', $key, 2);

            // Handle array values
            if (is_array($value)) {
                // Special case: activity.note should be kept as array in single instance
                if ($entity === 'activity' || $entity === 'activities') {
                    if (!isset($grouped[$entity])) {
                        $grouped[$entity] = [];
                    }
                    $grouped[$entity][$field] = $value; // Keep as array
                } else {
                    // For other entities, only create multiple instances if:
                    // 1. Entity doesn't exist yet, OR
                    // 2. Entity has no other fields yet (is empty array)
                    if (!isset($grouped[$entity])) {
                        $grouped[$entity] = [];
                    }
                    
                    // If entity already has string-keyed fields, just set the array as field value
                    // Otherwise, create separate instances
                    $hasStringKeys = !empty($grouped[$entity]) && isset(array_keys($grouped[$entity])[0]) && is_string(array_keys($grouped[$entity])[0]);
                    
                    if ($hasStringKeys) {
                        // Entity has fields already - don't split, keep array as-is
                        $grouped[$entity][$field] = $value;
                    } else {
                        // Create separate entity instances for each array value
                        foreach ($value as $idx => $val) {
                            if (!isset($grouped[$entity][$idx])) {
                                $grouped[$entity][$idx] = [];
                            }
                            $grouped[$entity][$idx][$field] = $val;
                        }
                    }
                }
            } else {
                // Single value
                if (!isset($grouped[$entity])) {
                    $grouped[$entity] = [];
                }

                // Check if entity is already an array of instances (from previous grouped field)
                if (!empty($grouped[$entity]) && is_int(array_key_first($grouped[$entity]))) {
                    // Entity has multiple instances - add field to all instances
                    foreach ($grouped[$entity] as &$instance) {
                        if (is_array($instance)) {
                            $instance[$field] = $value;
                        }
                    }
                    unset($instance);
                } else {
                    // Simple associative array - add field
                    $grouped[$entity][$field] = $value;
                }
            }
        }

        return $grouped;
    }

    /**
     * Determine if entity data is grouped (array of instances).
     */
    protected function isGroupedEntity($data): bool
    {
        if (!is_array($data)) {
            return false;
        }
        
        // Check if numeric array (multiple instances)
        $keys = array_keys($data);
        return isset($keys[0]) && is_int($keys[0]);
    }

    /**
     * Extract existing entity data as array.
     */
    protected function extractExistingData($entity): array
    {
        if (method_exists($entity, 'toArray')) {
            return $entity->toArray();
        }

        return (array) $entity;
    }

    /**
     * Detect changes between existing entity and new data.
     */
    protected function detectChanges($existingEntity, array $newData): array
    {
        $changes = [];

        foreach ($newData as $key => $newValue) {
            $oldValue = $existingEntity->{$key} ?? null;

            // Convert to comparable formats
            if ($oldValue instanceof \Carbon\Carbon) {
                $oldValue = $oldValue->format('Y-m-d');
            }

            if ($oldValue != $newValue && ! ($oldValue === null && $newValue === '')) {
                $changes[$key] = [
                    'old' => $oldValue,
                    'new' => $newValue,
                ];
            }
        }

        return $changes;
    }

    /**
     * Get a reference string for an entity.
     */
    protected function getEntityReference($entity, string $root): string
    {
        if (isset($entity->reference)) {
            return (string) $entity->reference;
        }
        if (isset($entity->value)) {
            return (string) $entity->value;
        }
        if (isset($entity->title)) {
            return (string) $entity->title;
        }
        if (isset($entity->id)) {
            return "{$root}#{$entity->id}";
        }

        return 'N/A';
    }

    /**
     * Load entity configurations from database.
     */
    protected function loadEntityConfigurations(): void
    {
        $entities = ImportEntity::where('is_active', true)
            ->orderBy('priority', 'desc')
            ->get();

        foreach ($entities as $entity) {
            $this->entityConfigs[$entity->canonical_root] = $entity;

            // Instantiate handler if configured
            if ($entity->handler_class && class_exists($entity->handler_class)) {
                $this->handlers[$entity->canonical_root] = app($entity->handler_class, ['entity' => $entity]);
            }
        }
    }

    /**
     * Get handler for entity root.
     */
    protected function getHandler(string $root)
    {
        return $this->handlers[$root] ?? null;
    }

    /**
     * Load mappings from import_mappings table.
     * Uses target_field in "entity.field" format.
     * Supports multiple sources mapping to same target (for groups).
     */
    protected function loadMappings(Import $import): array
    {
        $rows = \DB::table('import_mappings')
            ->where('import_id', $import->id)
            ->orderBy('position')
            ->get(['source_column', 'target_field', 'transform', 'apply_mode', 'options']);

        $mappings = [];
        foreach ($rows as $row) {
            $source = trim((string) $row->source_column);
            $target = trim((string) $row->target_field);

            if ($source === '' || $target === '') {
                continue;
            }

            // Use unique key combining source and target to avoid overwriting
            $key = $source . '→' . $target;
            
            // target_field is in "entity.field" format
            $mappings[$key] = [
                'source' => $source,
                'target' => $target,
                'transform' => $row->transform ?? null,
                'apply_mode' => $row->apply_mode ?? 'both',
                'options' => $row->options ? json_decode($row->options, true) : [],
            ];
        }

        return $mappings;
    }

    /**
     * Build associative array from row data.
     */
    protected function buildRowAssoc(array $row, ?array $header): array
    {
        if ($header) {
            return array_combine($header, array_pad($row, count($header), null));
        }

        // Use numeric indices if no header
        return array_combine(
            array_map(fn ($i) => "col_{$i}", array_keys($row)),
            $row
        );
    }

    /**
     * Check if row is effectively empty.
     */
    protected function rowIsEffectivelyEmpty(array $assoc): bool
    {
        foreach ($assoc as $value) {
            if ($value !== null && $value !== '') {
                return false;
            }
        }

        return true;
    }

    /**
     * Apply mappings to raw row data.
     * Returns array keyed by "entity.field".
     * 
     * Updated to match ImportServiceV2:
     * - Supports group option for concatenating multiple sources
     * - Returns flat array with "entity.field" keys (no nesting)
     */
    protected function applyMappings(array $raw, array $mappings): array
    {
        $mapped = [];
        
        // Group mappings by target field to handle concatenation (same as ImportServiceV2)
        $groupedMappings = [];
        foreach ($mappings as $mapping) {
            $target = $mapping['target'];
            if (!isset($groupedMappings[$target])) {
                $groupedMappings[$target] = [];
            }
            $groupedMappings[$target][] = $mapping;
        }
        
        foreach ($groupedMappings as $targetField => $fieldMappings) {
            // Group by group number from options
            $valuesByGroup = [];
            
            foreach ($fieldMappings as $mapping) {
                $source = $mapping['source'];
                
                if (!isset($raw[$source])) {
                    continue;
                }
                
                $value = $raw[$source];
                
                // Apply transform if specified
                if (!empty($mapping['transform'])) {
                    $value = $this->applyTransform($value, $mapping['transform']);
                }
                
                // Get group from options
                $options = $mapping['options'] ?? [];
                $group = $options['group'] ?? null;
                
                // Group values by their group number (same logic as ImportServiceV2)
                if ($group !== null) {
                    // Same group = concatenate
                    if (!isset($valuesByGroup[$group])) {
                        $valuesByGroup[$group] = [];
                    }
                    $valuesByGroup[$group][] = $value;
                } else {
                    // No group = each gets its own group
                    $valuesByGroup[] = [$value];
                }
            }
            
            // Now set the values - KEEP FLAT, DON'T NEST
            foreach ($valuesByGroup as $values) {
                if (count($values) === 1) {
                    // Single value - add to array if key exists, otherwise set directly
                    if (isset($mapped[$targetField])) {
                        // Convert to array and append
                        if (!is_array($mapped[$targetField])) {
                            $mapped[$targetField] = [$mapped[$targetField]];
                        }
                        $mapped[$targetField][] = $values[0];
                    } else {
                        $mapped[$targetField] = $values[0];
                    }
                } else {
                    // Multiple values in same group - concatenate with newline
                    $concatenated = implode("\n", array_filter($values, fn($v) => !empty($v) && trim((string)$v) !== ''));
                    if (!empty($concatenated)) {
                        if (isset($mapped[$targetField])) {
                            // Convert to array and append
                            if (!is_array($mapped[$targetField])) {
                                $mapped[$targetField] = [$mapped[$targetField]];
                            }
                            $mapped[$targetField][] = $concatenated;
                        } else {
                            $mapped[$targetField] = $concatenated;
                        }
                    }
                }
            }
        }

        return $mapped;
    }
    
    /**
     * Set nested value in array using dot notation.
     * If the key already exists, convert to array and append the new value.
     * 
     * Same logic as ImportServiceV2.
     */
    protected function setNestedValue(array &$array, string $key, mixed $value): void
    {
        $keys = explode('.', $key);
        $current = &$array;

        foreach ($keys as $i => $k) {
            if ($i === count($keys) - 1) {
                // If key already exists, convert to array and append
                if (isset($current[$k])) {
                    // Convert existing single value to array if needed
                    if (!is_array($current[$k])) {
                        $current[$k] = [$current[$k]];
                    }
                    // Append new value
                    $current[$k][] = $value;
                } else {
                    // Set as single value
                    $current[$k] = $value;
                }
            } else {
                if (!isset($current[$k]) || !is_array($current[$k])) {
                    $current[$k] = [];
                }
                $current = &$current[$k];
            }
        }
    }

    /**
     * Apply transform to a value.
     */
    protected function applyTransform(mixed $value, string $transform): mixed
    {
        return match ($transform) {
            'trim' => trim((string) $value),
            'upper' => strtoupper((string) $value),
            'lower' => strtolower((string) $value),
            'decimal' => (float) str_replace(',', '.', (string) $value),
            default => $value,
        };
    }

    /**
     * Initialize summary counters.
     */
    protected function initSummaries(): array
    {
        $summaries = [];

        foreach (array_keys($this->entityConfigs) as $root) {
            $summaries[$root] = [
                'create' => 0,
                'update' => 0,
                'skip' => 0,
                'invalid' => 0,
            ];
        }

        return $summaries;
    }

    /**
     * Create error payload.
     */
    protected function errorPayload(string $message): array
    {
        return [
            'success' => false,
            'error' => $message,
            'total_simulated' => 0,
            'summaries' => [],
            'rows' => [],
        ];
    }
}
