<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\CallbackLog;
use App\Models\Campaign;
use App\Models\FaceVerification;
use App\Models\OfferwallClick;
use App\Models\ProviderOffer;
use App\Models\SupportTicket;
use App\Models\User;
use App\Models\Withdrawal;
use App\Support\CsvExport;
use Illuminate\Http\Request;

/**
 * Centralized CSV export for every admin bulk-action list. Each export honors
 * an optional ?ids=1,2,3 (the rows the admin selected) and, failing that, a
 * ?search= filter so the download matches what the admin is looking at.
 */
class ExportController extends Controller
{
    public function users(Request $request)
    {
        $rows = $this->scope(User::query(), $request, ['username', 'email'])
            ->latest()->get();

        return CsvExport::stream($this->name('users'),
            ['ID', 'Username', 'Email', 'Verified', 'Admin', 'Banned', 'Current Points', 'Total Points', 'Referral Code', 'Registered IP', 'Last Login IP', 'Created'],
            $rows->map(fn (User $u) => [
                $u->id, $u->username, $u->email,
                $u->email_verified_at ? 'yes' : 'no',
                $u->is_admin ? 'yes' : 'no',
                $u->is_banned ? 'yes' : 'no',
                $u->current_points, $u->total_points, $u->referral_code,
                $u->registered_ip, $u->last_login_ip, $u->created_at,
            ])
        );
    }

    public function withdrawals(Request $request)
    {
        $rows = $this->scope(Withdrawal::with('user'), $request)
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->when($request->filled('search'), function ($q) use ($request) {
                $q->whereHas('user', fn ($u) => $u->where('username', 'like', "%{$request->search}%")->orWhere('email', 'like', "%{$request->search}%"));
            })
            ->latest()->get();

        return CsvExport::stream($this->name('withdrawals'),
            ['ID', 'User', 'Email', 'Method', 'Amount', 'Account', 'Status', 'IP', 'Created'],
            $rows->map(fn (Withdrawal $w) => [
                $w->id, optional($w->user)->username, optional($w->user)->email,
                $w->method, $w->amount, $w->account, $w->status, $w->ip, $w->created_at,
            ])
        );
    }

    public function activity(Request $request)
    {
        $rows = $this->scope(OfferwallClick::with('user'), $request)->latest()->get();

        return CsvExport::stream($this->name('activity'),
            ['ID', 'User', 'Provider', 'Offer', 'Launch Mode', 'IP', 'Created'],
            $rows->map(fn (OfferwallClick $c) => [
                $c->id, optional($c->user)->username, $c->provider_name,
                html_entity_decode((string) $c->offer_name), $c->launch_mode, $c->ip, $c->created_at,
            ])
        );
    }

    public function logs(Request $request)
    {
        $rows = $this->scope(CallbackLog::with('user'), $request)
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->latest()->get();

        return CsvExport::stream($this->name('callback-logs'),
            ['ID', 'User', 'Provider', 'Status', 'Endpoint', 'Method', 'IP', 'Message', 'Created'],
            $rows->map(fn (CallbackLog $l) => [
                $l->id, optional($l->user)->username, $l->provider, $l->status,
                $l->endpoint, $l->method, $l->ip, $l->message, $l->created_at,
            ])
        );
    }

    public function campaigns(Request $request)
    {
        $rows = $this->scope(Campaign::with('offerwall'), $request, ['name'])
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->latest()->get();

        return CsvExport::stream($this->name('campaigns'),
            ['ID', 'Name', 'Provider', 'Status', 'Reward', 'Category', 'Device', 'Countries', 'Featured', 'Created'],
            $rows->map(fn (Campaign $c) => [
                $c->id, $c->name, optional($c->offerwall)->name, $c->status, $c->reward_points,
                $c->category, $c->device, $c->countries, $c->featured ? 'yes' : 'no', $c->created_at,
            ])
        );
    }

    public function providerOffers(Request $request)
    {
        $rows = $this->scope(ProviderOffer::with('offerwall'), $request, ['name'])
            ->latest()->get();

        return CsvExport::stream($this->name('provider-offers'),
            ['ID', 'Name', 'Provider', 'Reward', 'Category', 'Countries', 'Active', 'Hot', 'Featured', 'Last Synced'],
            $rows->map(fn (ProviderOffer $o) => [
                $o->id, $o->name, optional($o->offerwall)->name, $o->reward_points, $o->category,
                $o->countries, $o->is_active ? 'yes' : 'no', $o->is_hot ? 'yes' : 'no',
                $o->is_featured ? 'yes' : 'no', $o->last_synced_at,
            ])
        );
    }

    public function tickets(Request $request)
    {
        $rows = $this->scope(SupportTicket::with('user'), $request, ['subject'])
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->latest()->get();

        return CsvExport::stream($this->name('support-tickets'),
            ['ID', 'User', 'Subject', 'Category', 'Priority', 'Status', 'Last Reply', 'Created'],
            $rows->map(fn (SupportTicket $t) => [
                $t->id, optional($t->user)->username, $t->subject, $t->category,
                $t->priority, $t->status, $t->last_reply_at, $t->created_at,
            ])
        );
    }

    public function faceVerifications(Request $request)
    {
        $rows = $this->scope(FaceVerification::with('user'), $request)
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->latest()->get();

        return CsvExport::stream($this->name('face-verifications'),
            ['ID', 'User', 'Context', 'Status', 'Duplicate Of User', 'IP', 'Reviewed At', 'Created'],
            $rows->map(fn (FaceVerification $f) => [
                $f->id, optional($f->user)->username, $f->context, $f->status,
                $f->duplicate_of_user_id, $f->ip, $f->reviewed_at, $f->created_at,
            ])
        );
    }

    /**
     * Lifetime export of the whole site: one ZIP containing a CSV per table,
     * every row since day one. Auth secrets (password hashes, tokens, 2FA
     * secrets) are never included.
     */
    public function all()
    {
        $tables = [
            'users', 'leads', 'withdrawals', 'payments', 'offerwalls', 'provider_offers',
            'campaigns', 'callback_logs', 'offerwall_clicks', 'support_tickets', 'ticket_messages',
            'face_verifications', 'referral_events', 'bonuses', 'bonus_histories',
            'notifications', 'lead_rules', 'leaderboard_awards',
        ];

        $hiddenColumns = ['password', 'remember_token', 'two_factor_secret', 'two_factor_recovery_codes'];

        $path = tempnam(sys_get_temp_dir(), 'siteexport');
        $zip = new \ZipArchive();
        $zip->open($path, \ZipArchive::OVERWRITE);

        foreach ($tables as $table) {
            if (!\Illuminate\Support\Facades\Schema::hasTable($table)) {
                continue;
            }

            $columns = array_values(array_diff(
                \Illuminate\Support\Facades\Schema::getColumnListing($table),
                $hiddenColumns
            ));

            $handle = fopen('php://temp', 'r+');
            fwrite($handle, "\xEF\xBB\xBF");
            fputcsv($handle, $columns);

            \Illuminate\Support\Facades\DB::table($table)->orderBy('id')->chunk(500, function ($rows) use ($handle, $columns) {
                foreach ($rows as $row) {
                    fputcsv($handle, array_map(
                        fn ($col) => is_array($v = $row->{$col} ?? null) ? json_encode($v) : $v,
                        $columns
                    ));
                }
            });

            rewind($handle);
            $zip->addFromString($table.'.csv', stream_get_contents($handle));
            fclose($handle);
        }

        $zip->close();

        return response()->download(
            $path,
            'basketloot-full-export-'.now()->format('Ymd_His').'.zip',
            ['Content-Type' => 'application/zip']
        )->deleteFileAfterSend(true);
    }

    /**
     * Apply the optional selected-ids filter, then an optional search filter
     * over the given columns when no explicit ids were chosen.
     */
    private function scope($query, Request $request, array $searchColumns = [])
    {
        $ids = array_filter(explode(',', (string) $request->query('ids', '')));

        if ($ids) {
            return $query->whereIn('id', $ids);
        }

        $search = trim((string) $request->query('search', ''));

        if ($search !== '' && $searchColumns) {
            $query->where(function ($q) use ($search, $searchColumns) {
                foreach ($searchColumns as $column) {
                    $q->orWhere($column, 'like', "%{$search}%");
                }
            });
        }

        return $query;
    }

    private function name(string $entity): string
    {
        return 'basketloot-'.$entity.'-'.now()->format('Ymd_His').'.csv';
    }
}
