<?php

namespace App\Http\Controllers\Backoffice;

use App\Http\Controllers\Controller;
use App\Models\BankAccount;
use App\Models\FinanceGroup;
use App\Models\Site;
use App\Models\Transaction;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;

class CrmController extends Controller
{
    private const UUID_PATTERN = '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i';

    public function index(Request $request)
    {
        $search = trim((string) $request->query('q', ''));
        $profiles = collect();
        $profileDetails = null;

        if ($search !== '') {
            $matchingTransactions = Transaction::query()
                ->select([
                    'id',
                    'type',
                    'status',
                    'source',
                    'amount',
                    'currency',
                    'customer_name',
                    'customer_account_holder',
                    'customer_player_id',
                    'created_at',
                ])
                ->where(function (Builder $query) use ($search) {
                    $query->where('customer_name', 'like', '%' . $search . '%')
                        ->orWhere('customer_account_holder', 'like', '%' . $search . '%');
                })
                ->orderByDesc('created_at')
                ->limit(250)
                ->get();

            $profiles = $this->buildProfiles($matchingTransactions);

            $selectedCriteria = $this->extractSelectedProfileCriteria($request);
            if ($selectedCriteria !== null) {
                $profileDetails = $this->buildProfileDetails($selectedCriteria);
            }
        }

        return view('backoffice.crm.index', [
            'search' => $search,
            'profiles' => $profiles,
            'profileDetails' => $profileDetails,
        ]);
    }

    private function buildProfiles(Collection $transactions): Collection
    {
        return $transactions
            ->groupBy(function (Transaction $transaction) {
                return $this->profileKeyForTransaction($transaction);
            })
            ->map(function (Collection $group) {
                /** @var Transaction $first */
                $first = $group->first();
                $selectorType = 'identity';
                $selectorValue = $this->resolvePrimaryIdentity($first);

                $displayName = trim((string) ($first->customer_name ?: $first->customer_account_holder ?: '-'));
                $accountHolders = $group->pluck('customer_account_holder')->filter()->unique()->values()->all();
                $names = $group->pluck('customer_name')->filter()->unique()->values()->all();

                return [
                    'selector_type' => $selectorType,
                    'selector_value' => $selectorValue,
                    'display_name' => $displayName,
                    'account_holders' => $accountHolders,
                    'names' => $names,
                    'transactions_count' => $group->count(),
                    'auto_transactions_count' => $group->where('source', 'auto')->count(),
                    'deposit_total' => (float) $group->where('type', 'deposit')->sum('amount'),
                    'withdrawal_total' => (float) $group->where('type', 'withdrawal')->sum('amount'),
                    'last_transaction_at' => optional($group->max('created_at')),
                ];
            })
            ->sortByDesc('transactions_count')
            ->values();
    }

    private function buildProfileDetails(array $criteria): array
    {
        $baseQuery = Transaction::query();
        $this->applyProfileCriteria($baseQuery, $criteria);

        $allTransactions = (clone $baseQuery)->get([
            'id',
            'type',
            'status',
            'source',
            'amount',
            'currency',
            'customer_name',
            'customer_account_holder',
            'customer_player_id',
            'ip_address',
            'site_id',
            'finance_group_id',
            'bank_account_id',
            'created_at',
        ]);

        if ($allTransactions->isEmpty()) {
            return [];
        }

        $recentAutoTransactions = (clone $baseQuery)
            ->with([
                'site:id,name',
                'financeGroup:id,name,badge_color',
                'bankAccount:id,account_name,iban',
            ])
            ->where('source', 'auto')
            ->orderByDesc('created_at')
            ->limit(10)
            ->get();

        $sites = Site::query()
            ->whereIn('id', $allTransactions->pluck('site_id')->filter()->unique()->values())
            ->get(['id', 'name'])
            ->keyBy('id');

        $financeGroups = FinanceGroup::query()
            ->whereIn('id', $allTransactions->pluck('finance_group_id')->filter()->unique()->values())
            ->get(['id', 'name', 'badge_color'])
            ->keyBy('id');

        $bankAccounts = BankAccount::query()
            ->whereIn('id', $allTransactions->pluck('bank_account_id')->filter()->unique()->values())
            ->get(['id', 'account_name', 'iban'])
            ->keyBy('id');

        $statusBreakdown = $allTransactions
            ->groupBy('status')
            ->map(fn (Collection $group) => $group->count())
            ->sortKeys();

        $siteBreakdown = $allTransactions
            ->filter(fn (Transaction $transaction) => !empty($transaction->site_id))
            ->groupBy('site_id')
            ->map(function (Collection $group, $siteId) use ($sites) {
                return [
                    'name' => $sites[(int) $siteId]->name ?? ('Site #' . $siteId),
                    'count' => $group->count(),
                    'amount' => (float) $group->sum('amount'),
                ];
            })
            ->sortByDesc('count')
            ->values();

        $financeGroupBreakdown = $allTransactions
            ->filter(fn (Transaction $transaction) => !empty($transaction->finance_group_id))
            ->groupBy('finance_group_id')
            ->map(function (Collection $group, $financeGroupId) use ($financeGroups) {
                $financeGroup = $financeGroups[(int) $financeGroupId] ?? null;

                return [
                    'name' => $financeGroup?->name ?? ('Finans Grup #' . $financeGroupId),
                    'badge_color' => $financeGroup?->badge_color,
                    'count' => $group->count(),
                    'amount' => (float) $group->sum('amount'),
                ];
            })
            ->sortByDesc('count')
            ->values();

        $bankAccountBreakdown = $allTransactions
            ->filter(fn (Transaction $transaction) => !empty($transaction->bank_account_id))
            ->groupBy('bank_account_id')
            ->map(function (Collection $group, $bankAccountId) use ($bankAccounts) {
                $bankAccount = $bankAccounts[(int) $bankAccountId] ?? null;

                return [
                    'name' => $bankAccount?->account_name ?? ('Hesap #' . $bankAccountId),
                    'iban' => $bankAccount?->iban,
                    'count' => $group->count(),
                ];
            })
            ->sortByDesc('count')
            ->values();

        $ipBreakdown = $allTransactions
            ->filter(fn (Transaction $transaction) => trim((string) $transaction->ip_address) !== '')
            ->groupBy('ip_address')
            ->map(function (Collection $group, $ipAddress) {
                return [
                    'ip_address' => $ipAddress,
                    'count' => $group->count(),
                ];
            })
            ->sortByDesc('count')
            ->values();

        return [
            'selector_type' => $criteria['type'],
            'selector_value' => $criteria['value'],
            'display_name' => trim((string) ($allTransactions->pluck('customer_account_holder')->filter()->first()
                ?: $allTransactions->pluck('customer_name')->filter()->first()
                ?: $allTransactions->pluck('customer_player_id')->filter()->first()
                ?: '-')),
            'customer_player_ids' => $allTransactions->pluck('customer_player_id')
                ->filter(fn ($value) => $this->isUuidPlayerId($value))
                ->unique()
                ->values(),
            'names' => $allTransactions->pluck('customer_name')->filter()->unique()->values(),
            'account_holders' => $allTransactions->pluck('customer_account_holder')->filter()->unique()->values(),
            'currency' => (string) ($allTransactions->pluck('currency')->filter()->first() ?: 'TRY'),
            'total_transactions' => $allTransactions->count(),
            'total_auto_transactions' => $allTransactions->where('source', 'auto')->count(),
            'deposit_count' => $allTransactions->where('type', 'deposit')->count(),
            'deposit_total' => (float) $allTransactions->where('type', 'deposit')->sum('amount'),
            'withdrawal_count' => $allTransactions->where('type', 'withdrawal')->count(),
            'withdrawal_total' => (float) $allTransactions->where('type', 'withdrawal')->sum('amount'),
            'approved_total' => (float) $allTransactions->whereIn('status', ['approved', 'completed'])->sum('amount'),
            'pending_count' => $allTransactions->where('status', 'pending')->count(),
            'first_transaction_at' => $allTransactions->min('created_at'),
            'last_transaction_at' => $allTransactions->max('created_at'),
            'status_breakdown' => $statusBreakdown,
            'site_breakdown' => $siteBreakdown,
            'finance_group_breakdown' => $financeGroupBreakdown,
            'bank_account_breakdown' => $bankAccountBreakdown,
            'ip_breakdown' => $ipBreakdown,
            'recent_auto_transactions' => $recentAutoTransactions,
        ];
    }

    private function extractSelectedProfileCriteria(Request $request): ?array
    {
        $type = trim((string) $request->query('profile_type', ''));
        $value = trim((string) $request->query('profile_value', ''));

        if ($type === '' || $value === '') {
            return null;
        }

        if ($type !== 'identity') {
            return null;
        }

        return [
            'type' => $type,
            'value' => $value,
        ];
    }

    private function applyProfileCriteria(Builder $query, array $criteria): void
    {
        $normalizedValue = $this->normalizeIdentityValue($criteria['value']);

        $query->where(function (Builder $innerQuery) use ($normalizedValue) {
            $innerQuery->whereRaw('LOWER(TRIM(customer_account_holder)) = ?', [$normalizedValue])
                ->orWhereRaw('LOWER(TRIM(customer_name)) = ?', [$normalizedValue]);
        });
    }

    private function profileKeyForTransaction(Transaction $transaction): string
    {
        return 'identity:' . $this->normalizeIdentityValue($this->resolvePrimaryIdentity($transaction));
    }

    private function resolvePrimaryIdentity(Transaction $transaction): string
    {
        $accountHolder = trim((string) $transaction->customer_account_holder);
        if ($accountHolder !== '') {
            return $accountHolder;
        }

        return trim((string) $transaction->customer_name);
    }

    private function normalizeIdentityValue(?string $value): string
    {
        $value = mb_strtolower(trim((string) $value));
        return preg_replace('/\s+/u', ' ', $value) ?? $value;
    }

    private function isUuidPlayerId($value): bool
    {
        return preg_match(self::UUID_PATTERN, trim((string) $value)) === 1;
    }
}
