<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\Site;
use App\Models\Transaction;
use App\Services\PayGarantiService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class PayGarantiWithdrawNotifyController extends Controller
{
    public function store(Request $request, PayGarantiService $service)
    {
        if (!$this->isIpAllowed($request->ip())) {
            return response()->json([
                'state' => false,
                'message' => 'IP not allowed.',
            ], 403);
        }

        $request->merge([
            'sid' => trim((string) $request->input('sid')),
            'key' => trim((string) $request->input('key')),
            'amount' => $this->normalizeAmount($request->input('amount')),
        ]);

        $data = $request->validate([
            'sid' => 'required|string|max:255',
            'key' => 'required|string|max:255',
            'amount' => 'required|numeric|min:0.01',
            'player_id' => 'required|string|max:255',
            'player_name' => 'required|string|max:255',
            'name' => 'nullable|string|max:255',
            'iban' => 'nullable|string|max:255',
            'bank_name' => 'nullable|string|max:255',
            'tc' => 'nullable|string|max:255',
            'trx' => 'required|string|max:255',
            'transaction_id' => 'required|string|max:255',
            'message' => 'nullable|string',
            'hash' => 'nullable|string',
        ]);

        $currency = strtoupper(substr(trim((string) $request->input('currency', 'TRY')), 0, 10));
        if ($currency === '') {
            $currency = 'TRY';
        }

        $site = Site::where('sid', $data['sid'])
            ->where('api_key', $data['key'])
            ->first();

        if (!$site) {
            return response()->json([
                'state' => false,
                'message' => 'Invalid site credentials.',
            ], 401);
        }

        if (!$site->is_active) {
            return response()->json([
                'state' => false,
                'message' => 'Site is inactive.',
            ], 403);
        }

        $secret = (string) ($site->secret_key ?? '');
        if ($secret === '') {
            return response()->json([
                'state' => false,
                'message' => 'Site secret is missing.',
            ], 400);
        }

        $hashValid = true;
        if (!empty($data['hash'])) {
            $hashValid = $service->verifyWithdrawHash($data, $secret);
        }

        $accountHolderFromApi = trim((string) ($data['name'] ?? ''));
        if ($accountHolderFromApi === '') {
            $accountHolderFromApi = trim((string) ($data['player_name'] ?? ''));
        }

        DB::beginTransaction();
        try {
            $withdrawal = Transaction::withdrawals()
                ->where('site_id', $site->id)
                ->where(function ($query) use ($data) {
                    $query->where('merchant_trx_id', $data['trx'])
                        ->orWhere('transaction_id', $data['trx'])
                        ->orWhere('external_transaction_id', $data['transaction_id']);
                })
                ->orderByDesc('id')
                ->first();

            $externalTransactionId = $this->resolveExternalTransactionId(
                $site,
                (string) $data['transaction_id'],
                $withdrawal?->id
            );

            $isNew = false;
            if (!$withdrawal) {
                $withdrawalId = Transaction::generateUniqueTransactionId('W');

                $withdrawal = Transaction::create([
                    'transaction_id' => $withdrawalId,
                    'external_transaction_id' => $externalTransactionId,
                    'merchant_trx_id' => $data['trx'],
                    'type' => 'withdrawal',
                    'source' => 'api',
                    'status' => 'pending',
                    'amount' => (float) $data['amount'],
                    'currency' => $currency,
                    'customer_name' => $data['player_name'],
                    'customer_player_id' => $data['player_id'],
                    'customer_account_holder' => $accountHolderFromApi !== '' ? $accountHolderFromApi : null,
                    'customer_iban' => $data['iban'] ?? null,
                    'customer_bank_name' => $data['bank_name'] ?? null,
                    'customer_tc' => $data['tc'] ?? null,
                    'sid' => $data['sid'],
                    'api_key' => $data['key'],
                    'hash' => $data['hash'] ?? null,
                    'callback_response' => $data,
                    'ip_address' => $request->ip(),
                    'created_by_name' => 'API',
                    'site_id' => $site ? $site->id : null,
                ]);
                $isNew = true;
            }

            $updateData = [
                'external_transaction_id' => $externalTransactionId ?? $withdrawal->external_transaction_id,
                'customer_name' => $data['player_name'],
                'customer_player_id' => $data['player_id'],
                'customer_account_holder' => $accountHolderFromApi !== '' ? $accountHolderFromApi : $withdrawal->customer_account_holder,
                'customer_iban' => $data['iban'] ?? $withdrawal->customer_iban,
                'customer_bank_name' => $data['bank_name'] ?? $withdrawal->customer_bank_name,
                'customer_tc' => $data['tc'] ?? $withdrawal->customer_tc,
                'hash' => $data['hash'] ?? $withdrawal->hash,
                'callback_response' => $data,
                'notes' => $data['message'] ?? $withdrawal->notes,
                'site_id' => $site ? $site->id : $withdrawal->site_id,
            ];

            $withdrawal->update($updateData);

            if (!$hashValid) {
                ActivityLog::log(
                    'withdraw_callback_invalid_hash',
                    'withdrawals',
                    "Withdraw callback invalid hash: {$withdrawal->transaction_id}",
                    null,
                    $data
                );
            }

            ActivityLog::log(
                'withdraw_callback',
                'withdrawals',
                "PayGaranti withdraw callback: {$withdrawal->transaction_id}",
                null,
                $withdrawal->toArray()
            );

            DB::commit();

            return response()->json([
                'state' => true,
                'message' => 'islem basarili',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'state' => false,
                'message' => $e->getMessage(),
            ], 500);
        }
    }

    private function isIpAllowed(?string $ip): bool
    {
        $whitelist = trim((string) setting('api_ip_whitelist'));
        if ($whitelist === '') {
            return true;
        }

        $allowed = preg_split('/\s+/', $whitelist);
        return $ip && in_array($ip, $allowed, true);
    }

    private function normalizeAmount($value): ?string
    {
        if ($value === null) {
            return null;
        }

        $raw = trim((string) $value);
        if ($raw === '') {
            return null;
        }

        // Keep only digits and decimal/thousand separator candidates.
        $raw = preg_replace('/[^\d,.\-]/', '', $raw);
        if ($raw === '' || $raw === null) {
            return null;
        }

        $hasComma = str_contains($raw, ',');
        $hasDot = str_contains($raw, '.');

        if ($hasComma && $hasDot) {
            if (strrpos($raw, ',') > strrpos($raw, '.')) {
                // 1.234,56 -> 1234.56
                $raw = str_replace('.', '', $raw);
                $raw = str_replace(',', '.', $raw);
            } else {
                // 1,234.56 -> 1234.56
                $raw = str_replace(',', '', $raw);
            }
        } elseif ($hasComma) {
            if (substr_count($raw, ',') === 1) {
                $decimals = (string) substr(strrchr($raw, ','), 1);
                if (strlen($decimals) <= 2) {
                    // 1234,56 -> 1234.56
                    $raw = str_replace(',', '.', $raw);
                } else {
                    // 1,234 -> 1234
                    $raw = str_replace(',', '', $raw);
                }
            } else {
                // 1,234,567 -> 1234567
                $raw = str_replace(',', '', $raw);
            }
        } elseif ($hasDot && substr_count($raw, '.') > 1) {
            $parts = explode('.', $raw);
            $last = array_pop($parts);
            if (strlen($last) <= 2) {
                // 1.234.56 -> 1234.56
                $raw = implode('', $parts) . '.' . $last;
            } else {
                // 1.234.567 -> 1234567
                $raw = implode('', $parts) . $last;
            }
        }

        return $raw;
    }

    private function resolveExternalTransactionId(Site $site, string $incomingExternalId, ?int $currentTransactionId = null): ?string
    {
        $incomingExternalId = trim($incomingExternalId);
        if ($incomingExternalId === '') {
            return null;
        }

        $isTaken = Transaction::query()
            ->where('external_transaction_id', $incomingExternalId)
            ->when($currentTransactionId, function ($query) use ($currentTransactionId) {
                $query->where('id', '!=', $currentTransactionId);
            })
            ->exists();

        if (!$isTaken) {
            return $incomingExternalId;
        }

        $siteScoped = "{$site->sid}:{$incomingExternalId}";
        $isSiteScopedTaken = Transaction::query()
            ->where('external_transaction_id', $siteScoped)
            ->when($currentTransactionId, function ($query) use ($currentTransactionId) {
                $query->where('id', '!=', $currentTransactionId);
            })
            ->exists();

        if (!$isSiteScopedTaken) {
            return $siteScoped;
        }

        return null;
    }
}
