<?php

namespace App\Http\Controllers\Backoffice;

use App\Http\Controllers\Controller;
use App\Models\FinanceGroup;
use App\Models\Site;
use App\Models\Transaction;
use App\Support\SiteCredentialResolver;
use Carbon\Carbon;
use Illuminate\Http\Request;

class TransactionLogController extends Controller
{
    public function index(Request $request)
    {
        $query = Transaction::with(['financeGroup', 'bankAccount', 'site']);

        if ($request->filled('type')) {
            $query->where('type', $request->type);
        }

        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('source')) {
            $query->where('source', $request->source);
        }

        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);
        }

        $this->applyDynamicTextFilters($query, $this->getDynamicTextFilters($request));

        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;
            $dateFrom = Carbon::parse($fromInput);
            $dateTo = Carbon::parse($toInput);
        } else {
            $dateTo = now('Europe/Istanbul');
            $dateFrom = $dateTo->copy()->subHours(24);
        }

        $query->whereBetween('created_at', [$dateFrom, $dateTo]);

        $search = $request->input('search.value');
        if (!is_string($search)) {
            $search = $request->input('search');
        }
        $search = is_string($search) ? trim($search) : '';

        if ($search !== '') {
            $matchingSites = Site::query()
                ->where('name', 'like', "%{$search}%")
                ->get(['id', 'sid', 'api_key']);

            $matchingSiteIds = $matchingSites->pluck('id')->filter()->values()->all();
            $matchingSids = $matchingSites->pluck('sid')->filter()->values()->all();
            $matchingApiKeys = $matchingSites->pluck('api_key')->filter()->values()->all();

            $query->where(function ($q) use ($search, $matchingSiteIds, $matchingSids, $matchingApiKeys) {
                $q->where('transaction_id', 'like', "%{$search}%")
                    ->orWhere('external_transaction_id', 'like', "%{$search}%")
                    ->orWhere('customer_name', 'like', "%{$search}%")
                    ->orWhere('customer_player_id', 'like', "%{$search}%")
                    ->orWhere('customer_iban', 'like', "%{$search}%")
                    ->orWhere('customer_account_holder', 'like', "%{$search}%")
                    ->orWhere('merchant_trx_id', 'like', "%{$search}%")
                    ->orWhere('ip_address', 'like', "%{$search}%")
                    ->orWhere('created_by_name', 'like', "%{$search}%")
                    ->orWhere('approved_by_name', 'like', "%{$search}%")
                    ->orWhere('sid', 'like', "%{$search}%")
                    ->orWhere('api_key', 'like', "%{$search}%")
                    ->orWhereHas('bankAccount', function ($bankQuery) use ($search) {
                        $bankQuery->where('account_name', 'like', "%{$search}%")
                            ->orWhere('iban', 'like', "%{$search}%");
                    });
                if (!empty($matchingSiteIds)) {
                    $q->orWhereIn('site_id', $matchingSiteIds);
                }
                if (!empty($matchingSids)) {
                    $q->orWhereIn('sid', $matchingSids);
                }
                if (!empty($matchingApiKeys)) {
                    $q->orWhereIn('api_key', $matchingApiKeys);
                }
            });
        }

        if ($this->isDataTableRequest($request)) {
            $logs = $query->orderBy('created_at', 'desc')->get();
            $sites = Site::all();

            return response()->json([
                'data' => $logs->map(function ($transaction) use ($sites) {
                    $resolvedSite = SiteCredentialResolver::resolveForTransaction($transaction, $sites);

                    return [
                        'id' => $transaction->id,
                        'transaction_id' => $transaction->transaction_id,
                        'external_transaction_id' => $transaction->external_transaction_id,
                        'type' => $transaction->type,
                        'status' => $transaction->status,
                        'source' => $transaction->source ?? 'auto',
                        'site_name' => $resolvedSite ? $resolvedSite->name : '-',
                        '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,
                        'merchant_trx_id' => $transaction->merchant_trx_id,
                        'ip_address' => $transaction->ip_address,
                        'finance_group' => $transaction->financeGroup ? $transaction->financeGroup->name : '-',
                        'finance_group_id' => $transaction->finance_group_id,
                        '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_by_name' => $transaction->created_by_name,
                        'approved_by_name' => $transaction->approved_by_name,
                        'created_at' => $transaction->created_at->format('d.m.Y H:i'),
                        'created_at_timestamp' => $transaction->created_at->timestamp,
                    ];
                })
            ]);
        }

        $financeGroups = FinanceGroup::all();
        $sites = Site::orderBy('name')->get();
        $dateFromDisplay = $dateFrom->copy();
        $dateToDisplay = $dateTo->copy();

        return view('backoffice.transaction-logs.index', compact('financeGroups', 'sites', 'dateFromDisplay', 'dateToDisplay'));
    }

    private function isDataTableRequest(Request $request): bool
    {
        return $request->ajax()
            || $request->expectsJson()
            || $request->has('draw')
            || $request->has('columns')
            || $request->has('order');
    }

    private function getDynamicTextFilters(Request $request): array
    {
        $supportedKeys = [
            'transaction_id',
            'external_transaction_id',
            'merchant_trx_id',
            'customer_name',
            'customer_player_id',
            'customer_iban',
            'customer_account_holder',
            'currency',
            'bank_account',
            'created_by_name',
            'approved_by_name',
            'ip_address',
            'min_amount',
            'max_amount',
        ];

        $filters = (array) $request->input('text_filters', []);

        foreach ($supportedKeys as $key) {
            if (!array_key_exists($key, $filters) && $request->filled($key)) {
                $filters[$key] = $request->input($key);
            }
        }

        $normalized = [];
        foreach ($filters as $key => $value) {
            $key = (string) $key;
            if (!in_array($key, $supportedKeys, true)) {
                continue;
            }

            $value = trim((string) $value);
            if ($value === '') {
                continue;
            }

            $normalized[$key] = $value;
        }

        return $normalized;
    }

    private function applyDynamicTextFilters($query, array $filters): void
    {
        foreach ($filters as $key => $value) {
            switch ($key) {
                case 'transaction_id':
                    $query->where('transaction_id', 'like', '%' . $value . '%');
                    break;

                case 'external_transaction_id':
                    $query->where('external_transaction_id', 'like', '%' . $value . '%');
                    break;

                case 'merchant_trx_id':
                    $query->where('merchant_trx_id', 'like', '%' . $value . '%');
                    break;

                case 'customer_name':
                    $query->where(function ($q) use ($value) {
                        $q->where('customer_name', 'like', '%' . $value . '%')
                            ->orWhere('customer_account_holder', 'like', '%' . $value . '%')
                            ->orWhereHas('bankAccount', function ($bankQuery) use ($value) {
                                $bankQuery->where('account_name', 'like', '%' . $value . '%');
                            });
                    });
                    break;

                case 'customer_player_id':
                    $query->where('customer_player_id', 'like', '%' . $value . '%');
                    break;

                case 'customer_iban':
                    $query->where('customer_iban', 'like', '%' . $value . '%');
                    break;

                case 'customer_account_holder':
                    $query->where('customer_account_holder', 'like', '%' . $value . '%');
                    break;

                case 'currency':
                    $query->where('currency', $value);
                    break;

                case 'bank_account':
                    $query->whereHas('bankAccount', function ($bankQuery) use ($value) {
                        $bankQuery->where('account_name', 'like', '%' . $value . '%')
                            ->orWhere('iban', 'like', '%' . $value . '%');
                    });
                    break;

                case 'created_by_name':
                    $query->where('created_by_name', 'like', '%' . $value . '%');
                    break;

                case 'approved_by_name':
                    $query->where('approved_by_name', 'like', '%' . $value . '%');
                    break;

                case 'ip_address':
                    $query->where('ip_address', 'like', '%' . $value . '%');
                    break;

                case 'min_amount':
                    if (is_numeric($value)) {
                        $query->where('amount', '>=', $value);
                    }
                    break;

                case 'max_amount':
                    if (is_numeric($value)) {
                        $query->where('amount', '<=', $value);
                    }
                    break;
            }
        }
    }
}
