<?php

namespace App\Http\Controllers\Mall;

use App\Http\Controllers\Controller;
use App\Models\Mall\MallItem;
use App\Models\Mall\MallStorage;
use App\Models\Mall\MallHistory;
use App\Models\Enums\MallItemPricingEnum;
use App\Services\ItemIconService;
use App\Utils\ImageHelpers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\Response;

class ItemController extends Controller
{
    public function show(int $id): View
    {
        $item = MallItem::find($id);
        $suggestions = MallItem::getSuggestions(7, $item);

        return view('mall/item/show', [
            'item' => $item,
            'suggestions' => $suggestions,
        ]);
    }

    /**
     * Handle item purchase
     */
    public function buy(int $id): RedirectResponse
    {
        $item = MallItem::findOrFail($id);
        $user = Auth::user();

        if (!$item->userCanBuy()) {
            return redirect()->route('mall.item', ['id' => $id])
                ->with('error', 'You do not have enough ' . $item->pricing->name() . ' to buy this item.');
        }

        DB::beginTransaction();

        try {
            // Try to stack with an existing entry for the same vnum
            $existingItem = MallStorage::where('owner_id', $user->id)
                ->where('vnum', $item->vnum)
                ->first();

            if ($existingItem) {
                $existingItem->count += $item->quantity;
                $existingItem->save();
            } else {
                MallStorage::create([
                    'owner_id' => $user->id,
                    'count' => $item->quantity,
                    'vnum' => $item->vnum,
                ]);
            }

            // Deduct currency
            if ($item->pricing == MallItemPricingEnum::CASH) {
                $user->cash -= $item->price;
                $user->mileage += $item->price;
            } elseif ($item->pricing == MallItemPricingEnum::MILEAGE) {
                $user->mileage -= $item->price;
            }

            $user->save();

            // Record purchase in history
            MallHistory::recordPurchase(
                $user->id,
                $item->vnum,
                $item->quantity,
                $item->pricing == MallItemPricingEnum::CASH ? 'cash' : 'mileage',
                $item->price,
                $item->proto?->localized_name ?? 'Unknown Item'
            );

            DB::commit();

            $storageCount = MallStorage::getUniqueItemCount($user->id);

            return redirect()->route('mall.item', ['id' => $id])
                ->with('success', "Item purchased successfully! Go to 'User Data' to distribute your items. ({$storageCount} unique items in storage)");

        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Purchase failed for user ' . $user->id . ', item ' . $id . ': ' . $e->getMessage());

            return redirect()->route('mall.item', ['id' => $id])
                ->with('error', 'Purchase failed. Please try again.');
        }
    }

    public function generateImage(int $id, bool $isLarge = false, float $maxIconRatio = 0.8): Response
    {
        $item = MallItem::find($id);

        // Return an error image if the item is not found
        if (!$item) {
            return response()->file(public_path('assets/mall/img/error.png'));
        }

        // Try to get icon from item_list.txt mapping using vnum
        $iconName = null;
        if ($item->vnum) {
            $iconName = ItemIconService::getIconForVnum($item->vnum);
        }

        // Fall back to the database image field if vnum lookup failed
        if ($iconName === null && $item->image) {
            $iconName = $item->image;
        }

        // Return error if no icon could be determined
        if ($iconName === null) {
            return response()->file(public_path('assets/mall/img/error.png'));
        }

        // Return an error if the item image is not available on the server
        $iconPath = public_path("assets/mall/img/item/icon/{$iconName}.png");
        if (!file_exists($iconPath)) {
            return response()->file(public_path('assets/mall/img/error.png'));
        }

        // Load the proper background
        if (!$isLarge)
            $imageData = imagecreatefrompng(public_path('assets/mall/img/item/background.png'));
        else
            $imageData = imagecreatefrompng(public_path('assets/mall/img/item/background-lg.png'));

        // Get the max width or height we can work with
        $maxSquareSize = (int) (min(imagesx($imageData), imagesy($imageData)) * $maxIconRatio);

        // Load the item icon
        $itemIcon = imagecreatefrompng($iconPath);

        // Get the max dimension of the icon
        $maxIconDimension = max(imagesx($itemIcon), imagesy($itemIcon));

        // Resize the icon
        $scalingFactor = (float) $maxSquareSize / $maxIconDimension;

        // Select the best resizing algorithm based on whether we have to enlarge or reduce the icon size
        $mode = IMG_BILINEAR_FIXED;
        if ($scalingFactor < 1)
            $mode = IMG_BICUBIC_FIXED;

        $itemIcon = imagescale($itemIcon, imagesx($itemIcon) * $scalingFactor, mode: $mode);

        $destX = (imagesx($imageData) - imagesx($itemIcon)) / 2;
        $destY = (imagesy($imageData) - imagesy($itemIcon)) / 2;

        // Apply the icon onto the background
        ImageHelpers::imagecopymerge_alpha($imageData, $itemIcon, $destX, $destY, 0, 0, imagesx($itemIcon), imagesy($itemIcon), 100);

        return response()->streamDownload(
            function () use ($imageData) {
                echo imagejpeg($imageData);
            },
            headers: [
                'Content-Type' => 'image/jpeg',
                'Cache-Control' => 'max-age=3600',
            ]
        );
    }

    public function generateLargeImage(int $id): Response
    {
        return $this->generateImage($id, true, 0.7);
    }
}