<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;

class ItemDataService
{
    /**
     * In-memory cache for item data to avoid reading file multiple times per request
     */
    protected static array $memoryCache = [];

    /**
     * Path to RAE_Exported_Table.tab file
     */
    protected string $filePath;

    public function __construct()
    {
        $this->filePath = public_path('img/RAE_Exported_Table.tab');
    }

    /**
     * Get item data by ID
     *
     * @param  int|string  $itemId
     * @return array{id: int, name: string|null, color: string|null, description: string|null}
     */
    public function getItemData($itemId): array
    {
        $itemId = (string) $itemId;

        // Check in-memory cache first (fastest)
        if (isset(self::$memoryCache[$itemId])) {
            return self::$memoryCache[$itemId];
        }

        // Check persistent cache (faster than file read)
        $cacheKey = "item_data_{$itemId}";
        $cached = Cache::get($cacheKey);
        if ($cached !== null) {
            self::$memoryCache[$itemId] = $cached;

            return $cached;
        }

        // Read from file as last resort
        $data = $this->findItemInFile($itemId);
        self::$memoryCache[$itemId] = $data;
        Cache::put($cacheKey, $data, now()->addHours(24));

        return $data;
    }

    /**
     * Get multiple items data by IDs
     *
     * @return array<int, array>
     */
    public function getMultipleItemsData(array $itemIds): array
    {
        $result = [];
        $toFind = [];

        // Check in-memory and persistent cache first
        foreach ($itemIds as $itemId) {
            $itemId = (string) $itemId;
            if (isset(self::$memoryCache[$itemId])) {
                $result[$itemId] = self::$memoryCache[$itemId];
            } else {
                $cacheKey = "item_data_{$itemId}";
                $cached = Cache::get($cacheKey);
                if ($cached !== null) {
                    self::$memoryCache[$itemId] = $cached;
                    $result[$itemId] = $cached;
                } else {
                    $toFind[] = $itemId;
                }
            }
        }

        // Find remaining items in file
        if (! empty($toFind)) {
            $found = $this->findMultipleItemsInFile($toFind);
            foreach ($found as $itemId => $data) {
                self::$memoryCache[$itemId] = $data;
                Cache::put("item_data_{$itemId}", $data, now()->addHours(24));
                $result[$itemId] = $data;
            }
            // Cache negative lookups (items not found) to prevent repeated file reads
            foreach ($toFind as $itemId) {
                if (! isset($found[$itemId])) {
                    $default = [
                        'id' => (int) $itemId,
                        'name' => null,
                        'color' => null,
                        'description' => null,
                    ];
                    self::$memoryCache[$itemId] = $default;
                    Cache::put("item_data_{$itemId}", $default, now()->addHours(24));
                }
            }
        }

        return $result;
    }

    /**
     * Get item name by ID
     */
    public function getItemName($itemId): ?string
    {
        return $this->getItemData($itemId)['name'];
    }

    /**
     * Get item color by ID
     */
    public function getItemColor($itemId): ?string
    {
        return $this->getItemData($itemId)['color'];
    }

    /**
     * Get item description by ID
     */
    public function getItemDescription($itemId): ?string
    {
        return $this->getItemData($itemId)['description'];
    }

    /**
     * Get clean description (without color codes and carriage returns)
     */
    public function getCleanDescription($itemId): ?string
    {
        $description = $this->getItemDescription($itemId);
        if (! $description) {
            return null;
        }

        // Remove color codes like ^ffcb4a and carriage returns
        return preg_replace('/\^[a-fA-F0-9]{6}/', '', str_replace("\r", ' ', $description));
    }

    /**
     * Find a single item in the RAE file
     */
    protected function findItemInFile(string $itemId): array
    {
        $default = [
            'id' => (int) $itemId,
            'name' => null,
            'color' => null,
            'description' => null,
        ];

        if (! file_exists($this->filePath)) {
            return $default;
        }

        $file = fopen($this->filePath, 'r');
        if (! $file) {
            return $default;
        }

        while (($line = fgets($file)) !== false) {
            $parts = explode("\t", trim($line));

            if (count($parts) >= 3 && trim($parts[0]) === $itemId) {
                fclose($file);

                return [
                    'id' => (int) $itemId,
                    'name' => trim($parts[2]) ?: null,
                    'color' => trim($parts[1]) ?: null,
                    'description' => isset($parts[3]) ? trim($parts[3]) : null,
                ];
            }
        }

        fclose($file);

        return $default;
    }

    /**
     * Find multiple items in the RAE file (more efficient for batch lookups)
     */
    protected function findMultipleItemsInFile(array $itemIds): array
    {
        $result = [];
        $remaining = array_flip($itemIds);

        if (! file_exists($this->filePath)) {
            return $result;
        }

        $file = fopen($this->filePath, 'r');
        if (! $file) {
            return $result;
        }

        while (($line = fgets($file)) !== false && ! empty($remaining)) {
            $parts = explode("\t", trim($line));

            if (count($parts) >= 3) {
                $id = trim($parts[0]);
                if (isset($remaining[$id])) {
                    $result[$id] = [
                        'id' => (int) $id,
                        'name' => trim($parts[2]) ?: null,
                        'color' => trim($parts[1]) ?: null,
                        'description' => isset($parts[3]) ? trim($parts[3]) : null,
                    ];
                    unset($remaining[$id]);
                }
            }
        }

        fclose($file);

        return $result;
    }

    /**
     * Clear the in-memory cache
     */
    public static function clearMemoryCache(): void
    {
        self::$memoryCache = [];
    }

    /**
     * Clear the persistent cache
     */
    public static function clearPersistentCache(): void
    {
        // Clear all item data cache entries
        // Note: This is a simplified approach. For production, consider using cache tags if supported.
        Cache::flush();
    }

    /**
     * Clear all caches (both memory and persistent)
     */
    public static function clearCache(): void
    {
        self::clearMemoryCache();
        self::clearPersistentCache();
    }

    /**
     * Get all items from RAE file (for autocomplete/search)
     * Returns limited set for performance
     *
     * @param  int  $limit  Maximum number of items to return
     */
    public function getAllItems(int $limit = 100): array
    {
        $items = [];

        if (! file_exists($this->filePath)) {
            return $items;
        }

        $file = fopen($this->filePath, 'r');
        if (! $file) {
            return $items;
        }

        $count = 0;
        while (($line = fgets($file)) !== false && $count < $limit) {
            $parts = explode("\t", trim($line));

            if (count($parts) >= 3 && ! empty(trim($parts[2]))) {
                $id = trim($parts[0]);
                $items[] = [
                    'id' => (int) $id,
                    'name' => trim($parts[2]),
                    'color' => trim($parts[1]) ?: 'FFFFFF',
                    'icon' => $this->getItemIcon($id),
                ];
                $count++;
            }
        }

        fclose($file);

        return $items;
    }

    /**
     * Search items by ID or name
     */
    public function searchItems(string $query, int $limit = 20): array
    {
        $items = [];

        if (! file_exists($this->filePath)) {
            return $items;
        }

        $file = fopen($this->filePath, 'r');
        if (! $file) {
            return $items;
        }

        $count = 0;
        $queryLower = strtolower($query);

        while (($line = fgets($file)) !== false && $count < $limit) {
            $parts = explode("\t", trim($line));

            if (count($parts) >= 3) {
                $id = trim($parts[0]);
                $name = trim($parts[2]);
                $nameLower = strtolower($name);
                if (! empty($name) && (str_contains($id, $query) || str_contains($nameLower, $queryLower))) {
                    $items[] = [
                        'id' => (int) $id,
                        'name' => $name,
                        'color' => trim($parts[1]) ?: 'FFFFFF',
                        'icon' => $this->getItemIcon($id),
                    ];
                    $count++;
                }
            }
        }

        fclose($file);

        return $items;
    }

    /**
     * Get item icon URL
     *
     * @param  int|string  $itemId
     */
    public function getItemIcon($itemId): string
    {
        return "/img/Icons/{$itemId}.png";
    }

    /**
     * Get full item data with icon
     *
     * @param  int|string  $itemId
     */
    public function getItemWithIcon($itemId): array
    {
        $data = $this->getItemData($itemId);
        $data['icon'] = $this->getItemIcon($itemId);

        return $data;
    }
}
