<?php

namespace App\Http\Controllers\Backoffice;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Transaction;
use App\Models\FinanceGroup;
use App\Models\CannedResponse;
use App\Models\ActivityLog;
use App\Models\Site;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use App\Services\PayGarantiService;
use App\Support\BusinessTime;
use App\Support\SiteCredentialResolver;

class WithdrawalController extends Controller
{
    public function index(Request $request)
    {
        $query = Transaction::withdrawals()->with(['financeGroup', 'bankAccount', 'approvedBy', 'site']);
        $forcedSite = null;
        $routeSite = $request->route('site');
        if ($routeSite === null && $request->segment(2) === 'sites' && $request->segment(4) === 'withdrawals') {
            $routeSite = $request->segment(3);
        }
        if ($routeSite !== null) {
            if ($routeSite instanceof Site) {
                $forcedSite = $routeSite;
            } elseif (is_numeric($routeSite)) {
                $forcedSite = Site::find((int) $routeSite);
            } else {
                $forcedSite = Site::where('sid', (string) $routeSite)->first();
            }

            if (!$forcedSite) {
                abort(404);
            }
        }

        $isSiteScoped = $forcedSite !== null;
        $forcedSiteId = $forcedSite ? (int) $forcedSite->id : null;

        $siteFilterId = $forcedSite
            ? (int) $forcedSite->id
            : ($request->filled('site_id') ? (int) $request->site_id : null);

        // Apply filters
        if ($request->filled('status')) {
            if ($request->status === 'approved') {
                $query->whereIn('status', ['approved', 'completed']);
            } elseif ($request->status === 'declined') {
                $query->whereIn('status', ['declined', 'failed']);
            } else {
                $query->where('status', $request->status);
            }
        }

        if ($request->filled('finance_group_id')) {
            $query->where('finance_group_id', $request->finance_group_id);
        }
        if ($siteFilterId) {
            SiteCredentialResolver::applySiteFilter($query, $siteFilterId);
        }
        $dateMode = $request->input('date_mode', 'gaming');
        if ($request->filled('date_from') || $request->filled('date_to')) {
            $fromInput = $request->filled('date_from') ? $request->date_from : $request->date_to;
            $toInput = $request->filled('date_to') ? $request->date_to : $request->date_from;
            $fromHasTime = is_string($fromInput) && preg_match('/\d{2}:\d{2}/', $fromInput);
            $toHasTime = is_string($toInput) && preg_match('/\d{2}:\d{2}/', $toInput);
            if ($dateMode === 'actual') {
                $from = $fromHasTime
                    ? Carbon::parse($fromInput, BusinessTime::timezone())
                    : Carbon::parse($fromInput, BusinessTime::timezone())->startOfDay();
                $to = $toHasTime
                    ? Carbon::parse($toInput, BusinessTime::timezone())
                    : Carbon::parse($toInput, BusinessTime::timezone())->endOfDay();
            } else {
                $from = $fromHasTime
                    ? Carbon::parse($fromInput, BusinessTime::timezone())
                    : BusinessTime::startOfBusinessDay(Carbon::parse($fromInput, BusinessTime::timezone())->format('Y-m-d'));
                $to = $toHasTime
                    ? Carbon::parse($toInput, BusinessTime::timezone())
                    : BusinessTime::endOfBusinessDay(Carbon::parse($toInput, BusinessTime::timezone())->format('Y-m-d'));
            }
        } else {
            if ($dateMode === 'actual') {
                $to = Carbon::now(BusinessTime::timezone());
                $from = (clone $to)->subHours(24);
            } else {
                $businessDate = BusinessTime::currentBusinessDate()->format('Y-m-d');
                $from = BusinessTime::startOfBusinessDay($businessDate);
                $to = BusinessTime::endOfBusinessDay($businessDate);
            }
        }
        $query->whereBetween('created_at', [$from, $to]);

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('transaction_id', 'like', "%{$search}%")
                    ->orWhere('customer_name', 'like', "%{$search}%")
                    ->orWhere('customer_player_id', 'like', "%{$search}%")
                    ->orWhere('customer_tc', 'like', "%{$search}%")
                    ->orWhere('customer_iban', 'like', "%{$search}%")
                    ->orWhere('sid', 'like', "%{$search}%")
                    ->orWhere('api_key', 'like', "%{$search}%");
            });
        }

        // For DataTables AJAX request
        if ($request->ajax()) {
            $withdrawals = $query->orderBy('created_at', 'desc')->get();
            $sites = Site::all();

            return response()->json([
                'data' => $withdrawals->map(function ($transaction) use ($sites) {
                    $resolvedSite = SiteCredentialResolver::resolveForTransaction($transaction, $sites);
                    return [
                        'id' => $transaction->id,
                        'transaction_id' => $transaction->transaction_id,
                        'status' => $transaction->status,
                        'amount' => number_format($transaction->amount, 2),
                        'currency' => $transaction->currency,
                        'customer_name' => $transaction->customer_name,
                        'customer_player_id' => $transaction->customer_player_id,
                        'customer_iban' => $transaction->customer_iban,
                        'customer_account_holder' => $transaction->customer_account_holder,
                        'customer_bank_name' => $transaction->customer_bank_name,
                        'source' => $transaction->source ?? 'auto',
                        'created_by_name' => $transaction->created_by_name,
                        'site_id' => $resolvedSite ? $resolvedSite->id : null,
                        'site_name' => $resolvedSite ? $resolvedSite->name : '-',
                        'description' => $transaction->description,
                        'finance_group_id' => $transaction->finance_group_id,
                        'finance_group' => $transaction->financeGroup ? $transaction->financeGroup->name : '-',
                        'finance_group_color' => $transaction->financeGroup ? $transaction->financeGroup->badge_color : null,
                        'bank_account' => $transaction->bankAccount ? $transaction->bankAccount->account_name : '-',
                        'bank_account_iban' => $transaction->bankAccount ? $transaction->bankAccount->iban : null,
                        'created_at' => $transaction->created_at->format('d.m.Y H:i'),
                        'created_at_timestamp' => $transaction->created_at->timestamp,
                        'actions' => true,
                    ];
                })
            ]);
        }

        // Get finance groups for filter
        $financeGroups = FinanceGroup::all();
        $sites = Site::orderBy('name')->get();

        // Get statistics for withdrawals only
        $confirmedStatuses = ['approved', 'completed'];
        $declinedStatuses = ['declined', 'failed'];

        $statsBase = Transaction::withdrawals()->whereBetween('created_at', [$from, $to]);
        if ($siteFilterId) {
            SiteCredentialResolver::applySiteFilter($statsBase, $siteFilterId);
        }
        $stats = [
            'total' => (clone $statsBase)->count(),
            'pending' => (clone $statsBase)->pending()->count(),
            'approved' => (clone $statsBase)->whereIn('status', $confirmedStatuses)->count(),
            'declined' => (clone $statsBase)->whereIn('status', $declinedStatuses)->count(),
            'total_amount' => (clone $statsBase)->whereIn('status', $confirmedStatuses)->sum('amount'),
        ];

        $cannedResponses = CannedResponse::orderBy('id', 'desc')->get();

        return view('backoffice.withdrawals.index', compact('financeGroups', 'sites', 'stats', 'cannedResponses', 'forcedSite', 'isSiteScoped', 'forcedSiteId'));
    }

    public function store(Request $request)
    {
        $request->validate([
            'customer_player_id' => 'nullable|string|max:255',
            'customer_name' => 'nullable|string|max:255',
            'amount' => 'required|numeric|min:1',
            'site_id' => 'required|exists:sites,id',
            'finance_group_id' => 'required|exists:finance_groups,id',
            'customer_account_holder' => 'required|string|max:255',
            'iban' => 'required|string|max:34',
            'notes' => 'nullable|string',
        ], [
            'amount.required' => 'Tutar gereklidir.',
            'amount.min' => 'Tutar 0 dan buyuk olmalidir.',
            'site_id.required' => 'Site secilmelidir.',
            'finance_group_id.required' => 'Finans grubu secilmelidir.',
            'finance_group_id.exists' => 'Gecersiz finans grubu.',
            'customer_account_holder.required' => 'Hesap adi gereklidir.',
            'iban.required' => 'IBAN gereklidir.',
        ]);

        DB::beginTransaction();
        try {
            $site = Site::findOrFail((int) $request->site_id);
            if (!$site->is_active) {
                throw new \RuntimeException('Secilen site pasif durumda.');
            }

            // Generate unique transaction ID
            $transactionId = Transaction::generateUniqueTransactionId('W');

            $playerId = $request->customer_player_id ?: $transactionId;
            $playerName = $request->customer_name ?: 'MANUAL';

            $transaction = Transaction::create([
                'transaction_id' => $transactionId,
                'type' => 'withdrawal',
                'source' => 'manual',
                'status' => 'pending',
                'amount' => $request->amount,
                'currency' => 'TRY',
                'site_id' => $site->id,
                'sid' => $site->sid,
                'api_key' => $site->api_key,
                'customer_player_id' => $playerId,
                'customer_name' => $playerName,
                'customer_iban' => $request->iban,
                'customer_account_holder' => $request->customer_account_holder,
                'finance_group_id' => $request->finance_group_id,
                'ip_address' => $request->ip(),
                'notes' => $request->notes,
                'created_by_name' => auth()->user()->full_name ?? auth()->user()->name ?? null,
            ]);

            ActivityLog::log(
                'create_withdrawal',
                'withdrawals',
                "Yeni çekim oluşturuldu: {$transaction->transaction_id} - {$transaction->customer_name} - " . number_format($transaction->amount, 2) . " TRY",
                null,
                $transaction->toArray()
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Çekim başarıyla oluşturuldu.',
                'transaction' => $transaction,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Çekim oluşturulurken bir hata oluştu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function assignDetails(Request $request, $id)
    {
        $withdrawal = Transaction::withdrawals()->findOrFail($id);
        $isApiSource = ($withdrawal->source ?? 'auto') === 'api';

        $rules = [
            'finance_group_id' => 'required|exists:finance_groups,id',
            'iban' => 'required|string|max:34',
        ];
        if (!$isApiSource) {
            $rules['customer_account_holder'] = 'required|string|max:255';
        }
        $request->validate($rules, [
            'finance_group_id.required' => 'Finans grubu secilmelidir.',
            'finance_group_id.exists' => 'Gecersiz finans grubu.',
            'customer_account_holder.required' => 'Hesap adi gereklidir.',
            'iban.required' => 'IBAN gereklidir.',
        ]);

        if ($withdrawal->status !== 'pending') {
            return response()->json([
                'success' => false,
                'message' => 'Bu cekim zaten isleme alinmis.',
            ], 400);
        }

        $accountHolder = trim((string) $request->input('customer_account_holder', ''));
        if ($accountHolder === '') {
            $accountHolder = trim((string) ($withdrawal->customer_account_holder ?: $withdrawal->customer_name));
        }
        if ($accountHolder === '') {
            return response()->json([
                'success' => false,
                'errors' => [
                    'customer_account_holder' => ['Hesap adi gereklidir.'],
                ],
            ], 422);
        }

        DB::beginTransaction();
        try {
            $withdrawal->update([
                'finance_group_id' => $request->finance_group_id,
                'customer_account_holder' => $accountHolder,
                'customer_iban' => $request->iban,
            ]);

            ActivityLog::log(
                'assign_withdrawal',
                'withdrawals',
                "Cekim finans grubuna atandi: {$withdrawal->transaction_id}",
                null,
                [
                    'finance_group_id' => $request->finance_group_id,
                    'customer_account_holder' => $accountHolder,
                    'customer_iban' => $request->iban,
                ]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Cekim finans grubuna atandi.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Cekim atanirken bir hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function show($id)
    {
        $withdrawal = Transaction::withdrawals()->with(['financeGroup', 'bankAccount', 'approvedBy', 'site'])->findOrFail($id);
        $withdrawal->setAttribute('created_at_display', $withdrawal->created_at->format('d.m.Y H:i'));
        $withdrawal->setAttribute('site_name', optional(SiteCredentialResolver::resolveForTransaction($withdrawal))->name);

        return response()->json([
            'success' => true,
            'transaction' => $withdrawal,
        ]);
    }

    public function approve(Request $request, $id)
    {
        $withdrawal = Transaction::withdrawals()->findOrFail($id);

        if ($withdrawal->status !== 'pending') {
            return response()->json([
                'success' => false,
                'message' => 'Bu çekim zaten işleme alınmış.',
            ], 400);
        }

        DB::beginTransaction();
        try {
            $oldStatus = $withdrawal->status;

            $paygaranti = app(PayGarantiService::class);
            $syncResult = null;
            // API-origin withdrawals are inbound requests, so approving them must not
            // trigger another outbound withdraw request (prevents notify/withdraw loops).
            $shouldSyncOnApprove = $withdrawal->source !== 'api'
                && empty($withdrawal->external_transaction_id);
            if ($shouldSyncOnApprove && $paygaranti->isConfigured($withdrawal)) {
                $syncResult = $paygaranti->sendWithdraw($withdrawal);
                if (!($syncResult['success'] ?? false)) {
                    throw new \RuntimeException($syncResult['message'] ?? 'PayGaranti withdraw request failed.');
                }
            }

            $withdrawal->update([
                'status' => 'approved',
                'approved_by' => auth()->id(),
                'approved_by_name' => auth()->user()->full_name ?? auth()->user()->name ?? null,
                'approved_at' => now(),
                'notes' => $request->notes,
                'sid' => $syncResult['payload']['sid'] ?? $withdrawal->sid,
                'api_key' => $syncResult['payload']['key'] ?? $withdrawal->api_key,
                'hash' => $syncResult['payload']['hash'] ?? $withdrawal->hash,
                'notify_url' => $syncResult['payload']['notify_url'] ?? $withdrawal->notify_url,
                'merchant_trx_id' => $syncResult['payload']['trx'] ?? $withdrawal->merchant_trx_id,
                'external_transaction_id' => $syncResult['response']['transaction_id'] ?? $withdrawal->external_transaction_id,
                'callback_response' => $syncResult['response'] ?? $withdrawal->callback_response,
            ]);

            ActivityLog::log(
                'approve_withdrawal',
                'withdrawals',
                "Çekim onaylandı: {$withdrawal->transaction_id}",
                ['status' => $oldStatus],
                ['status' => 'approved', 'notes' => $request->notes]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Çekim başarıyla onaylandı.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Çekim onaylanırken bir hata oluştu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function decline(Request $request, $id)
    {
        $request->validate([
            'notes' => 'required|string|min:3',
        ], [
            'notes.required' => 'Red nedeni gereklidir.',
            'notes.min' => 'Red nedeni en az 3 karakter olmalıdır.',
        ]);

        $withdrawal = Transaction::withdrawals()->findOrFail($id);

        if ($withdrawal->status !== 'pending') {
            return response()->json([
                'success' => false,
                'message' => 'Bu çekim zaten işleme alınmış.',
            ], 400);
        }

        DB::beginTransaction();
        try {
            $oldStatus = $withdrawal->status;

            $withdrawal->update([
                'status' => 'declined',
                'approved_by' => auth()->id(),
                'approved_by_name' => auth()->user()->full_name ?? auth()->user()->name ?? null,
                'approved_at' => now(),
                'notes' => $request->notes,
            ]);

            ActivityLog::log(
                'decline_withdrawal',
                'withdrawals',
                "Çekim reddedildi: {$withdrawal->transaction_id}",
                ['status' => $oldStatus],
                ['status' => 'declined', 'notes' => $request->notes]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Çekim başarıyla reddedildi.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Çekim reddedilirken bir hata oluştu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function complete(Request $request, $id)
    {
        $withdrawal = Transaction::withdrawals()->findOrFail($id);

        if ($withdrawal->status !== 'approved') {
            return response()->json([
                'success' => false,
                'message' => 'Sadece onaylanmış çekimler tamamlanabilir.',
            ], 400);
        }

        DB::beginTransaction();
        try {
            $oldStatus = $withdrawal->status;

            $withdrawal->update([
                'status' => 'completed',
                'notes' => $request->notes,
            ]);

            ActivityLog::log(
                'complete_withdrawal',
                'withdrawals',
                "Çekim tamamlandı: {$withdrawal->transaction_id}",
                ['status' => $oldStatus],
                ['status' => 'completed', 'notes' => $request->notes]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Çekim başarıyla tamamlandı.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Çekim tamamlanırken bir hata oluştu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function stats(Request $request)
    {
        $query = Transaction::withdrawals();

        if ($request->filled('finance_group_id')) {
            $query->where('finance_group_id', $request->finance_group_id);
        }
        if ($request->filled('site_id')) {
            SiteCredentialResolver::applySiteFilter($query, (int) $request->site_id);
        }
        $dateMode = $request->input('date_mode', 'gaming');
        if ($request->filled('date_from') || $request->filled('date_to')) {
            $fromInput = $request->filled('date_from') ? $request->date_from : $request->date_to;
            $toInput = $request->filled('date_to') ? $request->date_to : $request->date_from;
            $fromHasTime = is_string($fromInput) && preg_match('/\d{2}:\d{2}/', $fromInput);
            $toHasTime = is_string($toInput) && preg_match('/\d{2}:\d{2}/', $toInput);
            if ($dateMode === 'actual') {
                $from = $fromHasTime
                    ? Carbon::parse($fromInput, BusinessTime::timezone())
                    : Carbon::parse($fromInput, BusinessTime::timezone())->startOfDay();
                $to = $toHasTime
                    ? Carbon::parse($toInput, BusinessTime::timezone())
                    : Carbon::parse($toInput, BusinessTime::timezone())->endOfDay();
            } else {
                $from = $fromHasTime
                    ? Carbon::parse($fromInput, BusinessTime::timezone())
                    : BusinessTime::startOfBusinessDay(Carbon::parse($fromInput, BusinessTime::timezone())->format('Y-m-d'));
                $to = $toHasTime
                    ? Carbon::parse($toInput, BusinessTime::timezone())
                    : BusinessTime::endOfBusinessDay(Carbon::parse($toInput, BusinessTime::timezone())->format('Y-m-d'));
            }
        } else {
            if ($dateMode === 'actual') {
                $to = Carbon::now(BusinessTime::timezone());
                $from = (clone $to)->subHours(24);
            } else {
                $businessDate = BusinessTime::currentBusinessDate()->format('Y-m-d');
                $from = BusinessTime::startOfBusinessDay($businessDate);
                $to = BusinessTime::endOfBusinessDay($businessDate);
            }
        }
        $query->whereBetween('created_at', [$from, $to]);

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('transaction_id', 'like', "%{$search}%")
                    ->orWhere('customer_name', 'like', "%{$search}%")
                    ->orWhere('customer_player_id', 'like', "%{$search}%")
                    ->orWhere('customer_tc', 'like', "%{$search}%")
                    ->orWhere('customer_iban', 'like', "%{$search}%")
                    ->orWhere('sid', 'like', "%{$search}%")
                    ->orWhere('api_key', 'like', "%{$search}%");
            });
        }

        $confirmedStatuses = ['approved', 'completed'];
        $declinedStatuses = ['declined', 'failed'];

        return response()->json([
            'total' => (clone $query)->count(),
            'pending' => (clone $query)->where('status', 'pending')->count(),
            'approved' => (clone $query)->whereIn('status', $confirmedStatuses)->count(),
            'declined' => (clone $query)->whereIn('status', $declinedStatuses)->count(),
        ]);
    }

    public function checkNew(Request $request)
    {
        $since = $request->input('since');

        if (!$since || !is_numeric($since)) {
            return response()->json([
                'success' => false,
                'message' => 'Timestamp parametresi gerekli.',
            ], 400);
        }

        $sinceDate = Carbon::createFromTimestamp((int) $since);

        $baseQuery = Transaction::withdrawals()->with('site');
        if ($request->filled('site_id')) {
            SiteCredentialResolver::applySiteFilter($baseQuery, (int) $request->site_id);
        }

        $updatedCount = (clone $baseQuery)
            ->where('updated_at', '>', $sinceDate)
            ->count();

        $latestUpdate = (clone $baseQuery)->max('updated_at');
        $latestTimestamp = $latestUpdate ? Carbon::parse($latestUpdate)->timestamp : (int) $since;

        $newWithdrawals = (clone $baseQuery)
            ->pending()
            ->with(['financeGroup', 'bankAccount', 'approvedBy'])
            ->where('created_at', '>', $sinceDate)
            ->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($transaction) {
                $resolvedSite = SiteCredentialResolver::resolveForTransaction($transaction);
                return [
                    'id' => $transaction->id,
                    'transaction_id' => $transaction->transaction_id,
                    'status' => $transaction->status,
                    'amount' => number_format($transaction->amount, 2),
                    'currency' => $transaction->currency,
                    'customer_name' => $transaction->customer_name,
                    'site_name' => $resolvedSite ? $resolvedSite->name : '-',
                    'customer_player_id' => $transaction->customer_player_id,
                    'customer_iban' => $transaction->customer_iban,
                    'customer_account_holder' => $transaction->customer_account_holder,
                    'customer_bank_name' => $transaction->customer_bank_name,
                    'finance_group_id' => $transaction->finance_group_id,
                    'finance_group' => $transaction->financeGroup ? $transaction->financeGroup->name : '-',
                    'finance_group_color' => $transaction->financeGroup ? $transaction->financeGroup->badge_color : null,
                    'bank_account' => $transaction->bankAccount ? $transaction->bankAccount->account_name : '-',
                    'created_at' => $transaction->created_at->format('d.m.Y H:i'),
                    'created_at_timestamp' => $transaction->created_at->timestamp,
                    'actions' => true,
                ];
            });

        return response()->json([
            'success' => true,
            'count' => $newWithdrawals->count(),
            'data' => $newWithdrawals,
            'updated_count' => $updatedCount,
            'latest_timestamp' => $latestTimestamp,
        ]);
    }
}
