<?php

namespace App\Http\Controllers\Frontend\Service;

use App\Http\Controllers\Controller;
use App\Http\Requests\Frontend\Service\ExchangeGoldRequest;
use App\Http\Requests\Frontend\Service\ExchangeItemRequest;
use App\Http\Requests\Frontend\Service\RenameRoleRequest;
use App\Http\Requests\Frontend\Service\ServiceRequest;
use App\Http\Resources\BaseResource;
use App\Models\IngameServiceSetting;
use App\Services\Analytics\StatsService;
use App\Services\Api\API;
use App\Services\Gaming\IngameService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;
use Inertia\Response;

final class ServiceController extends Controller
{
    public function __construct(
        private API $api,
        private StatsService $statsService,
        private IngameService $ingameService,
    ) {}

    public function index(): Response
    {
        $user = Auth::user();

        $serverOnline = $this->api->serverOnline();
        $characters = [];

        if ($serverOnline) {
            $rolesData = $this->api->getRoles($user->ID);
            $roles = $rolesData['roles'] ?? [];

            $onlineList = $this->api->getOnlineList();
            $onlineRoleIds = array_column($onlineList, 'roleid');

            foreach ($roles as $role) {
                try {
                    $status = $this->api->getRoleStatus($role['id']);
                    $characters[] = [
                        'id' => $role['id'],
                        'name' => $role['name'],
                        'level' => ($status ?? [])['level'] ?? 0,
                        'is_online' => in_array($role['id'], $onlineRoleIds),
                    ];
                } catch (\Exception $e) {
                    $characters[] = [
                        'id' => $role['id'],
                        'name' => $role['name'],
                        'level' => 0,
                        'is_online' => in_array($role['id'], $onlineRoleIds),
                    ];
                }
            }
        }

        return Inertia::render('frontend/ingame/index', [
            'userGold' => $user->gold ?? 0,
            'characters' => $characters,
            'serverOnline' => $serverOnline,
            'ingameServices' => [
                'teleport' => [
                    'enabled' => IngameServiceSetting::isEnabled('teleport'),
                    'price' => IngameServiceSetting::getPrice('teleport'),
                ],
                'max_meridian' => [
                    'enabled' => IngameServiceSetting::isEnabled('max_meridian'),
                    'price' => IngameServiceSetting::getPrice('max_meridian'),
                ],
                'reset_storepass' => [
                    'enabled' => IngameServiceSetting::isEnabled('reset_storepass'),
                    'price' => IngameServiceSetting::getPrice('reset_storepass'),
                ],
                'reset_title' => [
                    'enabled' => IngameServiceSetting::isEnabled('reset_title'),
                    'price' => IngameServiceSetting::getPrice('reset_title'),
                ],
                'rename_role' => [
                    'enabled' => IngameServiceSetting::isEnabled('rename_role'),
                    'price' => IngameServiceSetting::getPrice('rename_role'),
                ],
                'item_exchange' => [
                    'enabled' => IngameServiceSetting::isEnabled('item_exchange'),
                    'price' => IngameServiceSetting::getPrice('item_exchange'),
                    'item_id' => IngameServiceSetting::get('item_exchange_item_id', 11208),
                    'item_name' => $this->ingameService->getItemName(IngameServiceSetting::get('item_exchange_item_id', 11208)),
                ],
                'cultivation_reset' => [
                    'enabled' => IngameServiceSetting::isEnabled('cultivation_reset'),
                    'price' => IngameServiceSetting::getPrice('cultivation_reset'),
                    'hex' => IngameServiceSetting::get('cultivation_reset_hex', '060000009f000000000000000a000000a700000000000000010000007a050000000000000a000000a1000000000000000a0000009e000000000000000a000000a0000000000000000a000000'),
                ],
            ],
        ]);
    }

    public function teleport(ServiceRequest $request): JsonResponse
    {
        $result = $this->ingameService->execute(
            serviceName: 'teleport',
            roleId: $request->getRoleId(),
            serviceCallback: function (int $roleId): array {
                $posx = (float) IngameServiceSetting::get('teleport_posx', 448.0);
                $posy = (float) IngameServiceSetting::get('teleport_posy', 900.0);
                $posz = (float) IngameServiceSetting::get('teleport_posz', 210.0);
                $worldtag = (int) IngameServiceSetting::get('teleport_worldtag', 1);

                return $this->api->teleportRole($roleId, $posx, $posy, $posz, $worldtag);
            },
        );

        return BaseResource::makeEnvelope(
            resource: $result,
            success: $result['success'],
            error: $result['error'] ?? null,
            status: $result['success'] ? 200 : 400,
        );
    }

    public function maxMeridian(ServiceRequest $request): JsonResponse
    {
        $result = $this->ingameService->execute(
            serviceName: 'max_meridian',
            roleId: $request->getRoleId(),
            serviceCallback: fn (int $roleId): array => $this->api->maxMeridian($roleId),
            additionalValidation: function (int $roleId): ?array {
                $status = $this->api->getRoleStatus($roleId);
                $roleLevel = (int) (($status ?? [])['level'] ?? 0);

                if ($roleLevel < 40) {
                    return [
                        'success' => false,
                        'error' => "Character must be at least level 40. Current level: {$roleLevel}",
                    ];
                }

                return null;
            },
        );

        return BaseResource::makeEnvelope(
            resource: $result,
            success: $result['success'],
            error: $result['error'] ?? null,
            status: $result['success'] ? 200 : 400,
        );
    }

    public function resetStorehousePassword(ServiceRequest $request): JsonResponse
    {
        $result = $this->ingameService->execute(
            serviceName: 'reset_storepass',
            roleId: $request->getRoleId(),
            serviceCallback: fn (int $roleId): array => $this->api->clearStorehousePassword($roleId),
        );

        return BaseResource::makeEnvelope(
            resource: $result,
            success: $result['success'],
            error: $result['error'] ?? null,
            status: $result['success'] ? 200 : 400,
        );
    }

    public function resetTitle(ServiceRequest $request): JsonResponse
    {
        $result = $this->ingameService->execute(
            serviceName: 'reset_title',
            roleId: $request->getRoleId(),
            serviceCallback: fn (int $roleId): array => $this->api->resetTitle($roleId),
        );

        return BaseResource::makeEnvelope(
            resource: $result,
            success: $result['success'],
            error: $result['error'] ?? null,
            status: $result['success'] ? 200 : 400,
        );
    }

    public function renameRole(RenameRoleRequest $request): JsonResponse
    {
        $error = $this->ingameService->checkServiceEnabled('rename_role');
        if ($error) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $error['error'], status: 400);
        }

        $user = Auth::user();
        $roleId = $request->getRoleId();
        $newName = $request->getNewName();
        $price = IngameServiceSetting::getPrice('rename_role');

        $error = $this->ingameService->checkGoldBalance($price);
        if ($error) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $error['error'], status: 400);
        }

        $roleCheck = $this->ingameService->verifyRoleOwnership($user->ID, $roleId);
        if (! $roleCheck['found']) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $roleCheck['error']['error'], status: 400);
        }

        $offlineCheck = $this->ingameService->checkRoleOffline($roleId);
        if ($offlineCheck) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $offlineCheck['error'], status: 400);
        }

        $oldName = $roleCheck['role']['name'] ?? '';

        $existingRoleId = $this->api->getRoleid($newName);
        if ($existingRoleId !== -1 && $existingRoleId != $roleId) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: 'This name is already taken by another character.', status: 400);
        }

        $result = $this->api->renameRole($roleId, $oldName, $newName);
        if ($result === false) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: 'Rename failed. Character might be online or name is invalid.', status: 400);
        }

        sleep(1);
        $roleBase = $this->api->getRoleBase($roleId);
        if ((($roleBase ?? [])['name'] ?? '') !== $newName) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: 'Rename failed. Please try again or contact support.', status: 400);
        }

        $this->ingameService->deductGold($user->ID, $price);
        Cache::forget("role_name:{$roleId}");
        Cache::forget("pvp_role_profile:{$roleId}");

        return BaseResource::makeEnvelope(resource: [
            'message' => "Successfully renamed from '{$oldName}' to '{$newName}'!",
        ]);
    }

    public function resetCultivation(ServiceRequest $request): JsonResponse
    {
        $cultivationHex = IngameServiceSetting::get('cultivation_reset_hex', '060000009f000000000000000a000000a700000000000000010000007a050000000000000a000000a1000000000000000a0000009e000000000000000a000000a0000000000000000a000000');

        $result = $this->ingameService->execute(
            serviceName: 'cultivation_reset',
            roleId: $request->getRoleId(),
            serviceCallback: fn (int $roleId): array => $this->api->resetCultivation($roleId, $cultivationHex),
        );

        return BaseResource::makeEnvelope(
            resource: $result,
            success: $result['success'],
            error: $result['error'] ?? null,
            status: $result['success'] ? 200 : 400,
        );
    }

    public function exchangeItemToGold(ExchangeItemRequest $request): JsonResponse
    {
        $error = $this->ingameService->checkServiceEnabled('item_exchange');
        if ($error) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $error['error'], status: 400);
        }

        $user = Auth::user();
        $roleId = $request->getRoleId();
        $itemCount = $request->getItemCount();
        $goldPerItem = (int) IngameServiceSetting::getPrice('item_exchange');
        $itemId = (int) IngameServiceSetting::get('item_exchange_item_id', 11208);

        $roleCheck = $this->ingameService->verifyRoleOwnership($user->ID, $roleId);
        if (! $roleCheck['found']) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $roleCheck['error']['error'], status: 400);
        }

        $offlineCheck = $this->ingameService->checkRoleOffline($roleId);
        if ($offlineCheck) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: $offlineCheck['error'], status: 400);
        }

        $result = $this->api->exchangeItemToGold($roleId, $itemId, $itemCount);
        if (! $result['success']) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: 'Exchange failed: '.$result['message'], status: 400);
        }

        $exchangedCount = $result['count'] ?? 0;
        if ($exchangedCount <= 0) {
            return BaseResource::makeEnvelope(resource: null, success: false, error: 'No items exchanged.', status: 400);
        }

        $goldToAdd = $exchangedCount * $goldPerItem;

        DB::table('users')->where('ID', $user->ID)->increment('gold', $goldToAdd);

        DB::table('item_exchange_log')->insert([
            'user_id' => $user->ID,
            'role_id' => $roleId,
            'role_name' => $roleCheck['role']['name'] ?? '',
            'item_id' => $itemId,
            'item_count' => $exchangedCount,
            'gold_per_item' => $goldPerItem,
            'gold_received' => $goldToAdd,
            'created_at' => now(),
        ]);

        return BaseResource::makeEnvelope(resource: [
            'message' => "Successfully exchanged {$exchangedCount} items for {$goldToAdd} gold!",
            'data' => [
                'item_count' => $exchangedCount,
                'gold_received' => $goldToAdd,
                'gold_per_item' => $goldPerItem,
                'available' => $result['available'] ?? 0,
                'remaining' => $result['remaining'] ?? 0,
            ],
        ]);
    }

    public function exchangeGold(ExchangeGoldRequest $request)
    {
        $user = Auth::user();
        $goldAmount = $request->getGoldAmount();

        if ($user->gold < $goldAmount) {
            return back()->with('error', 'Insufficient gold balance.');
        }

        $goldBefore = $user->gold;
        $goldAfter = $goldBefore - $goldAmount;
        $goldAmountDB = $goldAmount * 100;

        try {
            $updated = DB::table('users')
                ->where('ID', $user->ID)
                ->where('gold', '>=', $goldAmount)
                ->decrement('gold', $goldAmount);

            if (! $updated) {
                return back()->with('error', 'Insufficient gold balance or update failed.');
            }

            DB::statement('CALL usecash(?, ?, ?, ?, ?, ?, ?, @error)', [
                $user->ID, 1, 0, 1, 0, $goldAmountDB, 1,
            ]);

            DB::table('pw_gold')->insert([
                'user_id' => $user->ID,
                'gold_amount' => $goldAmount,
                'gold_before' => $goldBefore,
                'gold_after' => $goldAfter,
                'status' => 'completed',
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            return back()->with('success', "Successfully exchanged {$goldAmount} gold to ingame!");
        } catch (\Exception $e) {
            Log::error('Gold exchange failed', ['error' => $e->getMessage()]);

            return back()->with('error', 'Failed to exchange gold: '.$e->getMessage());
        }
    }
}
