<?php

namespace App\Services;

use App\Services\PwHexParser\Decoder;
use App\Services\PwHexParser\AutoDetector;
use Illuminate\Support\Facades\Cache;

class ItemDecodeService
{
    /**
     * Decode item hex data with all addon descriptions resolved
     * 
     * @param string $hexData
     * @param int|null $itemId
     * @param int|null $mask
     * @return array
     */
    public function decode(string $hexData, ?int $itemId = null, ?int $mask = null): array
    {
        // If mask is not provided or is 0, try to lookup from RAE table
        if (empty($mask) && $itemId && $itemId > 0) {
            $mask = $this->getItemMaskFromRAE($itemId);
        }

        // If hex data is empty or too short, return error
        if (strlen($hexData) < 8) {
            return [
                'success' => false,
                'error' => 'Hex data too short',
            ];
        }

        try {
            $decoder = new Decoder();
            $autoDetector = new AutoDetector($decoder);
            
            // Use mask as flag hint for better type detection
            $flag = $mask !== null && $mask > 0 ? (string) $mask : null;
            
            // Detect and decode the item
            $candidates = $autoDetector->detect($hexData, $flag);
            
            if (empty($candidates)) {
                return [
                    'success' => false,
                    'error' => 'Could not detect item type',
                ];
            }

            // Get the best candidate
            $bestMatch = $candidates[0];
            
            if ($bestMatch['match_type'] === 'error') {
                return [
                    'success' => false,
                    'error' => $bestMatch['error'] ?? 'Failed to decode',
                ];
            }

            $decodedData = $bestMatch['data'] ?? [];
            
            // Get addon descriptions from RAE_Addons.tab
            $addonsMap = $this->getAddonsMap();
            
            // Resolve addon descriptions
            $resolveAddons = function(array $addonsList) use ($addonsMap) {
                $resolved = [];
                foreach ($addonsList as $addon) {
                    $id = $addon['id'] ?? 0;
                    $value = $addon['value'] ?? 0;
                    $isEngrave = false;
                    
                    $addonInfo = $addonsMap[$id] ?? null;
                    $addonType = 0;
                    
                    // Try masking out the 0x4000 bit (16384) for embedded addons
                    if (!$addonInfo && ($id & 16384)) {
                        $cleanId = $id ^ 16384;
                        $addonInfo = $addonsMap[$cleanId] ?? null;
                    }

                    // Try masking out the 0x2000 bit (8192) for engrave addons
                    if (!$addonInfo && ($id & 8192)) {
                        $cleanId = $id ^ 8192;
                        $addonInfo = $addonsMap[$cleanId] ?? null;
                        $isEngrave = true;
                    }
                    
                    if ($addonInfo) {
                        $desc = $addonInfo['desc'];
                        $addonType = $addonInfo['type'] ?? 0;
                    } else {
                        // Fallback: If we detected it's engraved but didn't find definition,
                        // we still treat it as engrave but with unknown desc
                        if ($id & 8192) {
                            $desc = "Unknown Engrave ($id)";
                            $isEngrave = true;
                        } else {
                            $desc = "Unknown Addon ($id)";
                        }
                    }
                    
                    // Convert value based on type (0=normal, 2=percentage, 3=interval, 4=float)
                    if ($addonType === 4) {
                        $packed = pack('V', $value);
                        $displayValue = round(unpack('f', $packed)[1], 2);
                    } elseif ($addonType === 3) {
                        $displayValue = round($value * 0.05, 2);
                    } else {
                        $displayValue = $value;
                    }

                    // Clean addon description - extract only meaningful part
                    $cleanDesc = $this->cleanAddonDescription($desc);

                    if (strpos($cleanDesc, '+') !== false || strpos($cleanDesc, '-') !== false) {
                        if (substr($cleanDesc, -1) === '+') {
                            $display = $cleanDesc . $displayValue;
                        } elseif (substr($cleanDesc, -2) === '+%') {
                            $display = substr($cleanDesc, 0, -1) . $displayValue . '%';
                        } elseif (substr($cleanDesc, -2) === '-%') {
                            $display = substr($cleanDesc, 0, -1) . $displayValue . '%';
                        } elseif (substr($cleanDesc, -1) === '-') {
                            $display = $cleanDesc . $displayValue;
                        } else {
                            $display = $cleanDesc . ' ' . $displayValue;
                        }
                    } else {
                        $display = $cleanDesc . ' ' . $displayValue;
                    }

                    $addon['description'] = $display;
                    $addon['is_engrave'] = $isEngrave;
                    $resolved[] = $addon;
                }
                return $resolved;
            };
            
            // Resolve all addon types
            $addons = $decodedData['addons'] ?? [
                'normal_addons' => [],
                'refine_addons' => [],
                'special_addons' => [],
                'socket_addons' => [],
            ];
            
            // Handle special addons with skill description lookup
            $resolvedSpecialAddons = [];
            foreach ($addons['special_addons'] ?? [] as $addon) {
                $skillId = $addon['value'] ?? 0;
                $descriptionId = ($skillId * 10) + 1;
                $skillDesc = $this->getSkillDescription($descriptionId);
                $addon['description'] = $skillDesc ?: "Skill #{$skillId}";
                $addon['description_html'] = $skillDesc ?: "Skill #{$skillId}";
                $addon['skill_id'] = $skillId;
                $resolvedSpecialAddons[] = $addon;
            }
            
            // Separate engrave addons from normal addons based on resolved flag
            $allNormalAddons = $resolveAddons($addons['normal_addons'] ?? []);
            $normalAddons = [];
            $engraveAddons = [];
            
            foreach ($allNormalAddons as $addon) {
                if ($addon['is_engrave'] ?? false) {
                    $engraveAddons[] = $addon;
                } else {
                    $normalAddons[] = $addon;
                }
            }

            // Resolve socket addons with item names from RAE
            $resolvedSocketAddons = [];
            $sockets = $decodedData['sockets'] ?? [];
            foreach ($addons['socket_addons'] ?? [] as $index => $addon) {
                $socketItemId = $addon['id'] ?? 0;
                $addonValue = $addon['value'] ?? 0;

                // Get socket item ID from sockets array
                $socketItemIndex = $addon['index'] ?? $index;
                // Convert from 1-based to 0-based for array access
                $arrayIndex = $socketItemIndex - 1;
                $socketItemIdForName = $sockets[$arrayIndex] ?? 0;

                // Get addon info from RAE_Addons.tab
                $addonInfo = $addonsMap[$socketItemId] ?? null;
                $addonDesc = '';
                $addonType = 0;

                if ($addonInfo) {
                    $addonDesc = $addonInfo['desc'];
                    $addonType = $addonInfo['type'] ?? 0;
                } else {
                    $addonDesc = "Unknown Addon ($socketItemId)";
                }

                // Convert value based on type
                if ($addonType === 4) {
                    $packed = pack('V', $addonValue);
                    $displayValue = round(unpack('f', $packed)[1], 2);
                } elseif ($addonType === 3) {
                    $displayValue = round($addonValue * 0.05, 2);
                } else {
                    $displayValue = $addonValue;
                }

                // Format addon description
                $cleanAddonDesc = $this->cleanAddonDescription($addonDesc);
                if (strpos($cleanAddonDesc, '+') !== false || strpos($cleanAddonDesc, '-') !== false) {
                    if (substr($cleanAddonDesc, -1) === '+') {
                        $display = $cleanAddonDesc . $displayValue;
                    } elseif (substr($cleanAddonDesc, -2) === '+%') {
                        $display = substr($cleanAddonDesc, 0, -1) . $displayValue . '%';
                    } elseif (substr($cleanAddonDesc, -2) === '-%') {
                        $display = substr($cleanAddonDesc, 0, -1) . $displayValue . '%';
                    } elseif (substr($cleanAddonDesc, -1) === '-') {
                        $display = $cleanAddonDesc . $displayValue;
                    } else {
                        $display = $cleanAddonDesc . ' ' . $displayValue;
                    }
                } else {
                    $display = $cleanAddonDesc . ' ' . $displayValue;
                }

                // Get socket item name from RAE_Exported_Table.tab
                $socketItemName = '';
                if ($socketItemIdForName > 0) {
                    $socketItemName = $this->getItemNameFromRAE($socketItemIdForName);
                }

                // Combine: "Diamond of Tiger Atk. Level +1"
                if (!empty($socketItemName)) {
                    $finalDisplay = $socketItemName . ' ' . $display;
                } else {
                    $finalDisplay = $display;
                }

                $addon['description'] = $finalDisplay;
                $addon['socket_item_name'] = $socketItemName;
                $addon['socket_item_id'] = $socketItemIdForName;
                $resolvedSocketAddons[] = $addon;
            }

            $resolvedAddons = [
                'normal_addons' => $normalAddons,
                'refine_addons' => $resolveAddons($addons['refine_addons'] ?? []),
                'special_addons' => $resolvedSpecialAddons,
                'socket_addons' => $resolvedSocketAddons,
                'engrave_addons' => $engraveAddons,
            ];



            // Structure the response
            return [
                'success' => true,
                'item_type' => $bestMatch['type'],
                'match_type' => $bestMatch['match_type'],
                'mask_flags' => $bestMatch['mask_flags'] ?? [],
                'decoded' => [
                    'durability' => [
                        'current' => $decodedData['min_durability'] ?? null,
                        'max' => $decodedData['max_durability'] ?? null,
                    ],
                    'level' => $decodedData['level'] ?? null,
                    'sockets_count' => $decodedData['sockets_count'] ?? 0,
                    'addons_count' => $decodedData['addons_count'] ?? 0,
                    'addons' => $resolvedAddons,
                    'sockets' => $decodedData['sockets'] ?? [],
                    'attack_rate' => $decodedData['attack_rate'] ?? null,
                    'item_type' => $decodedData['item_type'] ?? null,
                    // Damage stats (for weapons)
                    'min_physical_damage' => $decodedData['min_physical_damage'] ?? null,
                    'max_physical_damage' => $decodedData['max_physical_damage'] ?? null,
                    'min_magic_damage' => $decodedData['min_magic_damage'] ?? null,
                    'max_magic_damage' => $decodedData['max_magic_damage'] ?? null,
                    // Attack stats (for jewelry/accessories)
                    'physical_attack' => $decodedData['physical_attack'] ?? null,
                    'magic_attack' => $decodedData['magic_attack'] ?? null,
                    // Defense stats
                    'physical_defense' => $decodedData['physical_defense'] ?? null,
                    'dodge' => $decodedData['dodge'] ?? null,
                    'evasion' => $decodedData['evasion'] ?? null,
                    // Resistances
                    'metal_resistance' => $decodedData['metal_resistance'] ?? null,
                    'wood_resistance' => $decodedData['wood_resistance'] ?? null,
                    'water_resistance' => $decodedData['water_resistance'] ?? null,
                    'fire_resistance' => $decodedData['fire_resistance'] ?? null,
                    'earth_resistance' => $decodedData['earth_resistance'] ?? null,
                    // HP/MP
                    'hp' => $decodedData['hp'] ?? null,
                    'mp' => $decodedData['mp'] ?? null,
                ],

                'raw' => $decodedData,
            ];

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => 'Decode failed: ' . $e->getMessage(),
            ];
        }
    }

    /**
     * Get item mask from RAE_Exported_Table.tab
     */
    public function getItemMaskFromRAE(int $itemId): ?int
    {
        $cacheKey = "rae_item_mask_{$itemId}";
        return Cache::remember($cacheKey, 3600, function () use ($itemId) {
            $filePath = public_path('img/RAE_Exported_Table.tab');
            if (!file_exists($filePath)) {
                return null;
            }

            $handle = fopen($filePath, 'r');
            if (!$handle) {
                return null;
            }

            try {
                while (($line = fgets($handle)) !== false) {
                    $line = trim($line);
                    if (empty($line)) {
                        continue;
                    }

                    $parts = explode("\t", $line);

                    if (count($parts) >= 1) {
                        $id = (int) trim($parts[0]);

                        if ($id === $itemId) {
                            $foundMask = null;
                            for ($i = 4; $i < count($parts); $i++) {
                                if (isset($parts[$i])) {
                                    $potentialMask = (int) trim($parts[$i]);
                                    if ($potentialMask > 0 && $potentialMask < 100000000) {
                                        $foundMask = $potentialMask;
                                    }
                                }
                            }
                            return $foundMask;
                        }
                    }
                }
            } finally {
                fclose($handle);
            }

            return null;
        });
    }

    /**
     * Get item name from RAE_Exported_Table.tab
     */
    public function getItemNameFromRAE(int $itemId): ?string
    {
        $cacheKey = "rae_item_name_{$itemId}";
        return Cache::remember($cacheKey, 3600, function () use ($itemId) {
            $filePath = public_path('img/RAE_Exported_Table.tab');
            if (!file_exists($filePath)) {
                return null;
            }

            $handle = fopen($filePath, 'r');
            if (!$handle) {
                return null;
            }

            try {
                while (($line = fgets($handle)) !== false) {
                    $line = trim($line);
                    if (empty($line)) {
                        continue;
                    }

                    $parts = explode("\t", $line);

                    if (count($parts) >= 3) {
                        $id = (int) trim($parts[0]);

                        if ($id === $itemId) {
                            return trim($parts[2]);
                        }
                    }
                }
            } finally {
                fclose($handle);
            }

            return null;
        });
    }

    /**
     * Get addons map from RAE_Addons.tab
     */
    public function getAddonsMap(): array
    {
        return Cache::remember('rae_addons_map', 3600, function () {
            $filePath = public_path('img/RAE_Addons.tab');
            if (!file_exists($filePath)) {
                return [];
            }

            $addons = [];
            $content = file_get_contents($filePath);
            
            $lines = explode("\n", $content);
            foreach ($lines as $line) {
                $line = trim($line);
                if (empty($line)) continue;

                $parts = explode(';', $line);
                if (count($parts) >= 4) {
                    $id = (int)$parts[0];
                    $type = (int)$parts[2];
                    $desc = trim($parts[3]);
                    $addons[$id] = [
                        'desc' => $desc,
                        'type' => $type,
                    ];
                }
            }
            return $addons;
        });
    }

    /**
     * Get skill description from skillstr.txt
     */
    public function getSkillDescription(int $skillId): ?string
    {
        try {
            $filePath = public_path('img/skillstr.txt');
            
            if (!file_exists($filePath)) {
                return null;
            }

            $cacheKey = "skill_desc_{$skillId}";
            return Cache::remember($cacheKey, 3600, function () use ($filePath, $skillId) {
                $content = file_get_contents($filePath);
                if ($content === false) {
                    return null;
                }
                
                // Handle UTF-16 encoding
                if (substr($content, 0, 2) === "\xFF\xFE") {
                    $content = mb_convert_encoding($content, 'UTF-8', 'UTF-16LE');
                } elseif (substr($content, 0, 2) === "\xFE\xFF") {
                    $content = mb_convert_encoding($content, 'UTF-8', 'UTF-16BE');
                }
                
                $lines = explode("\n", $content);

                $found = false;
                $description = '';
                
                foreach ($lines as $line) {
                    if ($found) {
                        if (preg_match('/^\d+\t/', trim($line))) {
                            break;
                        }
                        
                        $lineContent = rtrim($line, "\r\n");
                        $description .= $lineContent . ' ';
                        
                        $trimmed = trim($description);
                        if (substr($trimmed, -1) === '"') {
                            $description = str_replace('"', '', $description);
                            $description = preg_replace('/\s+/', ' ', $description);
                            return trim($description);
                        }
                        
                        continue;
                    }
                    
                    $trimmedLine = trim($line);
                    if (empty($trimmedLine)) {
                        continue;
                    }

                    $parts = explode("\t", $trimmedLine, 2);
                    
                    if (count($parts) >= 2) {
                        $id = (int) trim($parts[0]);
                        
                        if ($id === $skillId) {
                            $found = true;
                            $description = $parts[1];
                            
                            $trimmed = rtrim($description);
                            if (substr($trimmed, -1) === '"') {
                                $description = str_replace('"', '', $description);
                                $description = preg_replace('/\s+/', ' ', $description);
                                return trim($description);
                            }
                        }
                    }
                }
                
                if ($found && !empty($description)) {
                    $description = str_replace('"', '', $description);
                    $description = preg_replace('/\s+/', ' ', $description);
                    return trim($description);
                }

                return null;
            });
        } catch (\Exception $e) {
            return null;
        }
    }

    /**
     * Clean addon description - extract only meaningful part
     * Examples:
     * "3 Rnd. R8 Wep. Random PhysAtk +" -> "PhysAtk +"
     * "Engrave: Physical Defense +" -> "Physical Defense +"
     * "Atk. Level +" -> "Atk. Level +"
     */
    private function cleanAddonDescription(string $description): string
    {
        // Remove "Engrave: " prefix if exists
        $cleaned = str_replace('Engrave: ', '', $description);

        // Remove "Random " prefix if exists
        if (preg_match('/Random\s+(.+)$/', $cleaned, $matches)) {
            $cleaned = trim($matches[1]);
        }

        // Handle patterns like "3 Rnd. R8 Wep. Random PhysAtk +"
        // Extract only the part after "Random "
        $randomPos = strpos($cleaned, 'Random ');
        if ($randomPos !== false) {
            $cleaned = trim(substr($cleaned, $randomPos + 7));
        }

        return $cleaned;
    }
}
