<?php

namespace App\Services\Character;

use App\Services\Api\API;

class CharacterInventoryService
{
    protected API $api;

    public function __construct(API $api)
    {
        $this->api = $api;
    }

    /**
     * Process items for inventory updates
     *
     * @param  string  $location  (pocket, storehouse, equipment)
     * @return array [updatedCount, addedCount, deletedCount]
     */
    public function processItemsUpdate(int $roleId, array $newItems, array $currentItems, string $location): array
    {
        $updatedCount = 0;
        $addedCount = 0;
        $deletedCount = 0;

        // Build list of positions in new items
        $newPositions = [];
        foreach ($newItems as $newItem) {
            if (($newItem['id'] ?? 0) > 0) {
                $newPositions[] = $newItem['pos'] ?? -1;
            }
        }

        // Check for items to delete (exist in current but not in new)
        foreach ($currentItems as $currentItem) {
            $currentPos = $currentItem['pos'] ?? -1;
            $currentId = $currentItem['id'] ?? 0;
            if ($currentId > 0 && ! in_array($currentPos, $newPositions)) {
                try {
                    \Log::info("Deleting item at pos {$currentPos} in {$location} - ID: {$currentId}");
                    $result = $this->api->deleteItem($roleId, $currentPos, $location);
                    if ($result['success']) {
                        $deletedCount++;
                        \Log::info("Successfully deleted item at pos {$currentPos}");
                    } else {
                        \Log::warning("Failed to delete item at pos {$currentPos} in {$location}: ".($result['message'] ?? 'Unknown error'));
                    }
                } catch (\Exception $e) {
                    \Log::error("Exception deleting item at pos {$currentPos} in {$location}: ".$e->getMessage());
                }
            }
        }

        // Process new/updated items
        foreach ($newItems as $newItem) {
            $itemPos = $newItem['pos'] ?? null;
            if ($itemPos === null) {
                \Log::warning("Skipping item without position in {$location}");

                continue;
            }

            // Skip if item ID is 0 or not set
            $newItemId = $newItem['id'] ?? 0;
            if ($newItemId <= 0) {
                \Log::debug("Skipping item with ID {$newItemId} at pos {$itemPos} in {$location}");

                continue;
            }

            // Find current item by pos
            $currentItem = null;
            foreach ($currentItems as $ci) {
                if (($ci['pos'] ?? -1) == $itemPos) {
                    $currentItem = $ci;
                    break;
                }
            }

            // If slot is empty, add new item
            if (! $currentItem || ($currentItem['id'] ?? 0) <= 0) {
                try {
                    $result = $this->api->addItem($roleId, $itemPos, $newItem, $location);
                    if ($result['success']) {
                        $addedCount++;
                    } else {
                        \Log::warning("Failed to add item at pos {$itemPos} in {$location}: ".($result['message'] ?? 'Unknown error'));
                    }
                } catch (\Exception $e) {
                    \Log::error("Exception adding item at pos {$itemPos} in {$location}: ".$e->getMessage());
                }

                continue;
            }

            // Check if any field changed
            $hasChanges = false;
            $itemFields = config('game.item_fields');
            foreach ($itemFields as $field) {
                if (array_key_exists($field, $newItem) && ($newItem[$field] ?? null) !== ($currentItem[$field] ?? null)) {
                    $hasChanges = true;
                    break;
                }
            }

            if ($hasChanges) {
                try {
                    $result = $this->api->updateItem($roleId, $itemPos, $newItem, $location);
                    if ($result['success']) {
                        $updatedCount++;
                    } else {
                        \Log::warning("Failed to update item at pos {$itemPos} in {$location}: ".($result['message'] ?? 'Unknown error'));
                    }
                } catch (\Exception $e) {
                    \Log::error("Exception updating item at pos {$itemPos} in {$location}: ".$e->getMessage());
                }
            }
        }

        return [$updatedCount, $addedCount, $deletedCount];
    }

    /**
     * Update inventory section (pocket, storehouse, equipment)
     * Uses raw bytes approach for reliable updates
     *
     * @return array ['success' => bool, 'message' => string]
     */
    public function updateInventorySection(int $roleId, array $data, string $location): array
    {
        $methodMap = [
            'pocket' => 'getRoleInventory',
            'storehouse' => 'getRoleStorehouse',
            'equipment' => 'getRoleEquipment',
        ];

        $getMethod = $methodMap[$location] ?? null;

        if (! $getMethod) {
            return [
                'success' => false,
                'message' => "Invalid location: {$location}",
            ];
        }

        $currentData = $this->api->{$getMethod}($roleId);

        if ($currentData === null || $currentData === false) {
            return [
                'success' => false,
                'message' => "Failed to get {$location} data",
            ];
        }

        $messages = [];
        $updatedCount = 0;
        $addedCount = 0;
        $deletedCount = 0;

        $itemsKey = config("game.inventory_locations.{$location}");

        if (isset($data[$itemsKey])) {
            $currentItems = $currentData[$itemsKey] ?? [];
            $newItems = $data[$itemsKey];

            [$updatedCount, $addedCount, $deletedCount] = $this->processItemsUpdate($roleId, $newItems, $currentItems, $location);
            $messages[] = "$updatedCount modified, $addedCount added, $deletedCount deleted";
        }

        // Handle money update if present
        if (isset($data['money'])) {
            $newMoney = (int) $data['money'];
            $oldMoney = $currentData['money'] ?? 0;
            if ($newMoney != $oldMoney) {
                $updateMethod = 'update'.ucfirst($location).'Money';
                $result = $this->api->{$updateMethod}($roleId, $newMoney);
                if ($result['success']) {
                    $messages[] = 'money updated';
                }
            }
        }

        return [
            'success' => true,
            'message' => ucfirst($location).' updated successfully ('.implode(', ', $messages).')',
            'counts' => [
                'updated' => $updatedCount,
                'added' => $addedCount,
                'deleted' => $deletedCount,
            ],
        ];
    }

    /**
     * Get inventory data
     */
    public function getInventory(int $roleId): array
    {
        $pocket = $this->api->getRoleInventory($roleId);

        return [
            'inventory' => $pocket['inv'] ?? [],
            'capacity' => $pocket['capacity'] ?? 0,
        ];
    }

    /**
     * Get equipment data
     */
    public function getEquipment(int $roleId): array
    {
        $equipment = $this->api->getRoleEquipment($roleId);

        return [
            'equipment' => $equipment['eqp'] ?? [],
        ];
    }

    /**
     * Get storehouse data
     */
    public function getStorehouse(int $roleId): array
    {
        $storehouse = $this->api->getRoleStorehouse($roleId);
        $status = $this->api->getRoleStatus($roleId);

        return [
            'storehouse' => $storehouse['store'] ?? [],
            'capacity' => $storehouse['capacity'] ?? 0,
            'has_password' => ! empty($status['storehousepasswd'] ?? ''),
        ];
    }
}
