<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\WelcomeOfferClaim;
use App\Services\WelcomeOfferClaimService;
use App\Services\WelcomeOfferService;
use App\Support\WelcomeOfferSettings;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Schema;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;

class WelcomeOfferAdminController extends Controller
{
    public function __construct(
        private WelcomeOfferService $welcomeOfferService,
        private WelcomeOfferClaimService $welcomeOfferClaimService
    ) {}

    public function edit(Request $request): View
    {
        $grantQuery = trim((string) $request->query('grant_query', ''));
        $historySearch = trim((string) $request->query('history_search', ''));
        $claimTableAvailable = $this->claimTableAvailable();

        $grantResults = $this->grantSearchResults($grantQuery);
        $claims = $claimTableAvailable
            ? $this->claimHistoryQuery($historySearch)
                ->latest('claimed_at')
                ->paginate(20, ['*'], 'history_page')
                ->withQueryString()
            : $this->emptyClaimPaginator($request);

        $summary = $claimTableAvailable
            ? [
                'total_claims' => WelcomeOfferClaim::query()->count(),
                'user_claims' => WelcomeOfferClaim::query()->where('claim_source', 'user_claim')->count(),
                'manual_claims' => WelcomeOfferClaim::query()->where('claim_source', 'admin_manual_grant')->count(),
            ]
            : [
                'total_claims' => 0,
                'user_claims' => 0,
                'manual_claims' => 0,
            ];

        return view('admin.welcome_offer.edit', [
            'definitions' => WelcomeOfferSettings::definitions(),
            'values' => WelcomeOfferSettings::inputValues(),
            'contentPreview' => WelcomeOfferSettings::content(),
            'targets' => WelcomeOfferSettings::targets(),
            'claimTableAvailable' => $claimTableAvailable,
            'grantQuery' => $grantQuery,
            'grantResults' => $grantResults,
            'claims' => $claims,
            'historySearch' => $historySearch,
            'summary' => $summary,
        ]);
    }

    public function update(Request $request): RedirectResponse
    {
        $data = $request->validate(WelcomeOfferSettings::validationRules());
        WelcomeOfferSettings::saveInputValues($data);

        return back()->with('success', 'Welcome Offer settings updated successfully.');
    }

    public function grant(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'user_id' => ['required', 'integer', 'exists:users,id'],
            'note' => ['nullable', 'string', 'max:1000'],
        ]);
        $redirectParameters = $this->editRouteParameters($request);

        $user = User::query()->findOrFail((int) $data['user_id']);

        try {
            $this->welcomeOfferClaimService->claimForUser(
                $user,
                $request->user('admin'),
                'admin_manual_grant',
                (string) ($data['note'] ?? '')
            );
        } catch (ValidationException $exception) {
            return redirect()
                ->route('admin.welcome-offer.edit', $redirectParameters)
                ->with('error', $exception->validator->errors()->first());
        }

        return redirect()
            ->route('admin.welcome-offer.edit', $redirectParameters)
            ->with('success', $user->name . ' কে Welcome Offer সফলভাবে দেওয়া হয়েছে।');
    }

    private function claimHistoryQuery(string $historySearch)
    {
        return WelcomeOfferClaim::query()
            ->with([
                'user:id,name,email,mobile,referral_code,profile_photo',
                'admin:id,name,email',
            ])
            ->when($historySearch !== '', function ($query) use ($historySearch) {
                $query->whereHas('user', function ($userQuery) use ($historySearch) {
                    $userQuery->where('name', 'like', '%' . $historySearch . '%')
                        ->orWhere('email', 'like', '%' . $historySearch . '%')
                        ->orWhere('mobile', 'like', '%' . $historySearch . '%')
                        ->orWhere('referral_code', 'like', '%' . $historySearch . '%');
                });
            });
    }

    private function grantSearchResults(string $grantQuery): Collection
    {
        if ($grantQuery === '') {
            return collect();
        }

        $users = User::query()
            ->where(function ($query) use ($grantQuery) {
                $query->where('name', 'like', '%' . $grantQuery . '%')
                    ->orWhere('email', 'like', '%' . $grantQuery . '%')
                    ->orWhere('mobile', 'like', '%' . $grantQuery . '%')
                    ->orWhere('referral_code', 'like', '%' . $grantQuery . '%');
            })
            ->latest('id')
            ->limit(10)
            ->get(['id', 'name', 'email', 'mobile', 'referral_code', 'profile_photo', 'balance', 'is_active']);

        $claimMap = $this->claimTableAvailable()
            ? WelcomeOfferClaim::query()
                ->whereIn('user_id', $users->pluck('id')->all())
                ->get()
                ->keyBy('user_id')
            : collect();

        return $users->map(function (User $user) use ($claimMap) {
            $cards = $this->welcomeOfferService->progressForUser($user);
            $user->welcome_offer_level_cards = $cards;
            $user->welcome_offer_claim = $claimMap->get($user->id);

            return $user;
        });
    }

    private function claimTableAvailable(): bool
    {
        return Schema::hasTable('welcome_offer_claims');
    }

    private function emptyClaimPaginator(Request $request): LengthAwarePaginator
    {
        return new LengthAwarePaginator(
            [],
            0,
            20,
            max(1, (int) $request->query('history_page', 1)),
            [
                'path' => $request->url(),
                'query' => $request->query(),
            ]
        );
    }

    /**
     * @return array<string, string|int>
     */
    private function editRouteParameters(Request $request): array
    {
        $parameters = [];

        foreach (['grant_query', 'history_search'] as $key) {
            $value = trim((string) $request->input($key, ''));
            if ($value !== '') {
                $parameters[$key] = $value;
            }
        }

        $historyPage = (int) $request->input('history_page', 0);
        if ($historyPage > 1) {
            $parameters['history_page'] = $historyPage;
        }

        return $parameters;
    }
}
