<?php

namespace App\Http\Controllers;

use App\Models\SupportReply;
use App\Models\SupportTicket;
use App\Models\LiveSupportAccess;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Str;

class SupportController extends Controller
{
    private $departments = [
        'Customer Services Department',
        'Shipment Department',
        'Payment Department',
        'Account Department',
        'General Enquiry',
    ];

    public function adminIndex()
    {
        $tickets = SupportTicket::with('user')
            ->orderByDesc('id')
            ->paginate(30);

        return view('admin.support', [
            'title' => 'Live Support',
            'tickets' => $tickets,
            'departments' => $this->departments,
            'supportAvatarUrl' => $this->supportAvatarUrl(),
        ]);
    }

    public function userIndex()
    {
        $tickets = SupportTicket::where('userid', Auth::id())
            ->orderByDesc('id')
            ->get();

        return view('user.support', [
            'tickets' => $tickets,
            'departments' => $this->departments,
            'supportAvatarUrl' => $this->supportAvatarUrl(),
        ]);
    }

    public function visitorCreate(Request $request)
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:150'],
            'email' => ['required', 'email', 'max:150'],
            'department' => ['nullable', 'string', 'max:150'],
            'message' => ['required', 'string', 'max:1000'],
            'website' => ['nullable', 'string', 'max:1'],
        ]);

        if (! empty($data['website'])) {
            return response()->json(['success' => false, 'error' => 'Unable to create ticket.'], 422);
        }

        $ticket = SupportTicket::create([
            'userid' => 0,
            'ticketid' => $this->makeTicketId(),
            'department' => $data['department'] ?: 'General Enquiry',
            'message' => trim($data['message']),
            'status' => 'active',
            'datecreated' => $this->dateCreated(),
            'guest_name' => trim($data['name']),
            'guest_email' => trim($data['email']),
            'needs_admin_attention' => 1,
        ]);

        return response()->json([
            'success' => true,
            'ticket_id' => $ticket->ticketid,
            'thread' => $this->threadPayload($ticket),
        ]);
    }

    public function visitorSend(Request $request)
    {
        $data = $request->validate([
            'ticket_id' => ['required', 'string', 'max:150'],
            'message' => ['nullable', 'string', 'max:1000'],
            'attachment' => ['nullable', 'file', 'mimes:pdf,png,jpg,jpeg,gif,webp,txt,doc,docx,xls,xlsx,csv,zip', 'max:8192'],
        ]);

        $ticket = SupportTicket::where('ticketid', $data['ticket_id'])->firstOrFail();

        return $this->storeReply($request, $ticket, 0, true);
    }

    public function userCreate(Request $request)
    {
        $data = $request->validate([
            'department' => ['required', 'string', 'max:150'],
            'message' => ['required', 'string', 'max:1000'],
        ]);

        $ticket = SupportTicket::create([
            'userid' => Auth::id(),
            'ticketid' => $this->makeTicketId(),
            'department' => $data['department'],
            'message' => trim($data['message']),
            'status' => 'active',
            'datecreated' => $this->dateCreated(),
            'needs_admin_attention' => 1,
        ]);

        return redirect()->route('support')->with('success', 'Support ticket created.');
    }

    public function userThread(Request $request)
    {
        $ticket = SupportTicket::where('ticketid', $request->query('ticket_id'))
            ->where('userid', Auth::id())
            ->firstOrFail();

        return response()->json($this->threadPayload($ticket));
    }

    public function userSend(Request $request)
    {
        $data = $request->validate([
            'ticket_id' => ['required', 'string', 'max:150'],
            'message' => ['nullable', 'string', 'max:1000'],
            'attachment' => ['nullable', 'file', 'mimes:pdf,png,jpg,jpeg,gif,webp,txt,doc,docx,xls,xlsx,csv,zip', 'max:8192'],
        ]);

        $ticket = SupportTicket::where('ticketid', $data['ticket_id'])
            ->where('userid', Auth::id())
            ->firstOrFail();

        return $this->storeReply($request, $ticket, Auth::id(), true);
    }

    public function adminThread(Request $request)
    {
        $ticket = SupportTicket::where('ticketid', $request->query('ticket_id'))->firstOrFail();

        return response()->json($this->threadPayload($ticket));
    }

    public function adminSend(Request $request)
    {
        $data = $request->validate([
            'ticket_id' => ['required', 'string', 'max:150'],
            'message' => ['nullable', 'string', 'max:1000'],
            'attachment' => ['nullable', 'file', 'mimes:pdf,png,jpg,jpeg,gif,webp,txt,doc,docx,xls,xlsx,csv,zip', 'max:8192'],
        ]);

        $ticket = SupportTicket::where('ticketid', $data['ticket_id'])->firstOrFail();

        if (! $this->adminSupportPlanActive()) {
            return response()->json([
                'success' => false,
                'error' => 'Live support replies are locked. Start the free trial or choose a paid plan to reply.',
                'subscription_url' => route('admin.support.payments'),
            ], 403);
        }

        $response = $this->storeReply($request, $ticket, 1, false);
        $ticket->update(['needs_admin_attention' => 0]);

        return $response;
    }

    public function adminPoll()
    {
        $tickets = SupportTicket::where('needs_admin_attention', 1)
            ->orderByDesc('id')
            ->limit(6)
            ->get()
            ->map(function ($ticket) {
                return [
                    'ticket_id' => $ticket->ticketid,
                    'title' => $ticket->userid ? $this->userLabel($ticket) : 'Website visitor',
                    'source' => $ticket->userid ? 'Account dashboard' : 'Front website',
                    'department' => $ticket->department,
                    'message' => Str::limit((string) $ticket->message, 90),
                    'datecreated' => $ticket->datecreated,
                ];
            });

        return response()->json([
            'count' => SupportTicket::where('needs_admin_attention', 1)->count(),
            'tickets' => $tickets,
        ]);
    }

    public function updateStatus(Request $request, SupportTicket $ticket)
    {
        $data = $request->validate([
            'status' => ['required', 'in:active,closed'],
        ]);

        $ticket->update(['status' => $data['status']]);

        return back()->with('success', 'Ticket status updated.');
    }

    public function destroy(SupportTicket $ticket)
    {
        SupportReply::where('ticketid', $ticket->ticketid)->delete();
        $ticket->delete();

        return back()->with('success', 'Ticket deleted.');
    }

    public function uploadAvatar(Request $request)
    {
        $request->validate([
            'avatar' => ['required', 'image', 'mimes:jpg,jpeg,png,webp,gif', 'max:8192'],
        ]);

        $dir = $this->supportAvatarDirectory();
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        foreach ($this->supportAvatarDirectories() as $avatarDir) {
            foreach (glob($avatarDir . DIRECTORY_SEPARATOR . 'support-avatar.*') ?: [] as $oldFile) {
                @unlink($oldFile);
            }
        }

        $file = $request->file('avatar');
        $name = 'support-avatar.' . strtolower($file->getClientOriginalExtension());
        $file->move($dir, $name);
        @chmod($dir . DIRECTORY_SEPARATOR . $name, 0644);

        return back()->with('success', 'Support avatar updated.');
    }

    public function paymentIndex(Request $request)
    {
        $this->ensureLiveSupportAccessTable();

        $config = config('live_support_paystack');

        return view('admin.live-support-subscriptions', [
            'title' => 'Live Support Subscriptions',
            'config' => $config,
            'adminEmail' => $this->adminEmail(),
            'planActive' => $this->adminSupportPlanActive(),
            'activeAccess' => $this->activeLiveSupportAccess(),
            'trialUsed' => $this->freeTrialUsed(),
            'trialEnabled' => $this->freeTrialEnabled(),
            'paymentStatus' => $request->query('payment', ''),
        ]);
    }

    public function subscriptionControl(Request $request)
    {
        $this->ensureLiveSupportAccessTable();
        $this->ensureLiveSupportControlTable();

        if (! $this->liveSupportControlUnlocked()) {
            return view('admin.live-support-control-login', [
                'title' => 'Live Support Access Control',
                'passwordConfigured' => $this->liveSupportControlPassword() !== '',
            ]);
        }

        $config = config('live_support_paystack');
        $rows = LiveSupportAccess::orderByDesc('id')->limit(100)->get();

        return view('admin.live-support-subscription-control', [
            'title' => 'Live Support Access Control',
            'config' => $config,
            'rows' => $rows,
            'adminEmail' => $this->adminEmail(),
            'planActive' => $this->adminSupportPlanActive(),
            'activeAccess' => $this->activeLiveSupportAccess(),
            'trialUsed' => $this->freeTrialUsed(),
            'trialEnabled' => $this->freeTrialEnabled(),
        ]);
    }

    public function unlockSubscriptionControl(Request $request)
    {
        $this->ensureLiveSupportControlTable();

        $request->validate([
            'control_password' => ['required', 'string', 'max:255'],
        ]);

        $stored = $this->liveSupportControlPassword();
        if ($stored === '') {
            return back()->with('error', 'No control password has been set in phpMyAdmin yet.');
        }

        $plainMatch = hash_equals($stored, (string) $request->input('control_password'));
        $hashMatch = Str::startsWith($stored, ['$2y$', '$2a$', '$2b$', '$argon2i$', '$argon2id$'])
            && Hash::check((string) $request->input('control_password'), $stored);

        if (! $plainMatch && ! $hashMatch) {
            return back()->with('error', 'Invalid live support control password.');
        }

        $request->session()->put('live_support_control_unlocked', true);

        return redirect()->route('admin.support.payments.control');
    }

    public function lockSubscriptionControl(Request $request)
    {
        $request->session()->forget('live_support_control_unlocked');

        return redirect()->route('admin.support.payments.control')->with('success', 'Live support control page has been locked.');
    }

    public function startFreeTrial()
    {
        $this->ensureLiveSupportAccessTable();

        if (! $this->freeTrialEnabled()) {
            return back()->with('error', 'Free trial is currently turned off in config/live_support_paystack.php.');
        }

        if ($this->freeTrialUsed()) {
            return back()->with('error', 'The one-month free trial has already been activated for this admin account.');
        }

        $this->recordLiveSupportAccess(
            $this->adminEmail(),
            'free_trial',
            'free_trial_' . optional(Auth::guard('admin')->user())->id . '_' . Str::random(16),
            0,
            config('live_support_paystack.currency', 'NGN')
        );

        return back()->with('success', 'Free trial activated. Admin replies are unlocked for one month.');
    }

    public function manualRenew(Request $request)
    {
        if (! $this->liveSupportControlUnlocked()) {
            return redirect()->route('admin.support.payments.control')->with('error', 'Enter the live support control password first.');
        }

        $data = $request->validate([
            'email' => ['required', 'email', 'max:255'],
            'plan' => ['required', 'in:monthly,three_month'],
        ]);

        $this->recordLiveSupportAccess(
            strtolower($data['email']),
            $data['plan'],
            'admin_ls_' . optional(Auth::guard('admin')->user())->id . '_' . Str::random(12),
            0,
            config('live_support_paystack.currency', 'NGN')
        );

        return back()->with('success', 'Manual live support access has been added.');
    }

    public function endSubscription(Request $request)
    {
        if (! $this->liveSupportControlUnlocked()) {
            return redirect()->route('admin.support.payments.control')->with('error', 'Enter the live support control password first.');
        }

        $this->ensureLiveSupportAccessTable();

        $data = $request->validate([
            'email' => ['nullable', 'email', 'max:255'],
            'access_id' => ['nullable', 'integer'],
        ]);

        $endedAt = now()->subMinute()->format('Y-m-d H:i:s');

        if (! empty($data['access_id'])) {
            $row = LiveSupportAccess::where('id', $data['access_id'])->firstOrFail();
            $row->update(['paid_until' => $endedAt]);

            return back()->with('success', 'Selected live support subscription has been ended.');
        }

        $email = strtolower($data['email'] ?? $this->adminEmail());
        $updated = LiveSupportAccess::where('email', $email)
            ->where('paid_until', '>=', now())
            ->update(['paid_until' => $endedAt]);

        return back()->with($updated ? 'success' : 'error', $updated
            ? 'Active live support subscription has been ended.'
            : 'No active live support subscription was found for that email.');
    }

    public function paystackStart(Request $request)
    {
        $data = $request->validate([
            'email' => ['required', 'email', 'max:255'],
            'plan' => ['required', 'in:monthly,three_month'],
        ]);

        if (! $this->paystackEnabled()) {
            return back()->with('error', 'Paystack is disabled or missing keys in config/live_support_paystack.php.');
        }

        $response = Http::withToken(config('live_support_paystack.secret_key'))
            ->acceptJson()
            ->post('https://api.paystack.co/transaction/initialize', [
                'email' => strtolower($data['email']),
                'amount' => $this->planAmountSmallest($data['plan']),
                'currency' => config('live_support_paystack.currency', 'NGN'),
                'callback_url' => route('admin.support.paystack.callback'),
                'metadata' => [
                    'plan' => $data['plan'],
                    'months' => $this->planMonths($data['plan']),
                    'source' => 'live_support',
                    'email' => strtolower($data['email']),
                    'return_to' => 'admin_live_support',
                ],
            ]);

        $body = $response->json();
        $url = $body['data']['authorization_url'] ?? '';

        if (! $response->successful() || empty($body['status']) || $url === '') {
            return back()->with('error', $body['message'] ?? 'Payment could not start. Check the Paystack configuration.');
        }

        return redirect()->away($url);
    }

    public function paystackCallback(Request $request)
    {
        $reference = (string) $request->query('reference', '');

        if ($reference === '' || ! $this->paystackEnabled()) {
            return redirect()->route('admin.support.payments', ['payment' => 'invalid']);
        }

        $response = Http::withToken(config('live_support_paystack.secret_key'))
            ->acceptJson()
            ->get('https://api.paystack.co/transaction/verify/' . rawurlencode($reference));

        $body = $response->json();
        $data = $body['data'] ?? [];

        if (! $response->successful() || empty($body['status']) || ($data['status'] ?? '') !== 'success') {
            return redirect()->route('admin.support.payments', ['payment' => 'failed']);
        }

        $metadata = is_array($data['metadata'] ?? null) ? $data['metadata'] : [];
        $email = strtolower($data['customer']['email'] ?? ($metadata['email'] ?? $this->adminEmail()));
        $plan = $metadata['plan'] ?? 'monthly';
        $amount = (int) ($data['amount'] ?? 0);
        $currency = $data['currency'] ?? config('live_support_paystack.currency', 'NGN');

        $this->recordLiveSupportAccess($email, $plan, $reference, $amount, $currency, true);

        return redirect()->route('admin.support.payments', ['payment' => 'success']);
    }

    private function storeReply(Request $request, SupportTicket $ticket, int $userId, bool $needsAdminAttention)
    {
        $message = trim((string) $request->input('message', ''));
        $hasAttachment = $request->hasFile('attachment');

        if ($message === '' && ! $hasAttachment) {
            return response()->json(['success' => false, 'error' => 'Type a message or attach a file.'], 422);
        }

        if ($ticket->status === 'closed') {
            return response()->json(['success' => false, 'error' => 'This ticket is closed.'], 422);
        }

        $reply = SupportReply::create([
            'userid' => $userId,
            'ticketid' => $ticket->ticketid,
            'message' => $message,
            'datecreated' => $this->dateCreated(),
        ]);

        if ($hasAttachment) {
            $reply->update(['attachment' => $this->storeAttachment($request, $reply)]);
        }

        if ($needsAdminAttention) {
            $ticket->update(['needs_admin_attention' => 1]);
        }

        return response()->json([
            'success' => true,
            'thread' => $this->threadPayload($ticket->fresh()),
        ]);
    }

    private function threadPayload(SupportTicket $ticket): array
    {
        $rows = [[
            'id' => 'ticket-' . $ticket->id,
            'side' => 'user',
            'author' => $ticket->userid ? $this->userLabel($ticket) : ($ticket->guest_name ?: 'Website visitor'),
            'message' => (string) $ticket->message,
            'datecreated' => (string) $ticket->datecreated,
            'attachment_url' => '',
            'attachment_ext' => '',
        ]];

        foreach ($ticket->replies as $reply) {
            $isAdmin = (int) $reply->userid === 1;
            $attachment = $reply->attachment ? asset($reply->attachment) : '';
            $rows[] = [
                'id' => $reply->id,
                'side' => $isAdmin ? 'support' : 'user',
                'author' => $isAdmin ? 'Support' : 'You',
                'message' => (string) $reply->message,
                'datecreated' => (string) $reply->datecreated,
                'attachment_url' => $attachment,
                'attachment_ext' => $attachment ? strtolower(pathinfo($attachment, PATHINFO_EXTENSION)) : '',
            ];
        }

        return [
            'success' => true,
            'ticket' => [
                'ticket_id' => $ticket->ticketid,
                'department' => $ticket->department,
                'status' => $ticket->status,
                'source' => $ticket->userid ? 'Account dashboard' : 'Front website',
                'title' => $ticket->userid ? $this->userLabel($ticket) : ($ticket->guest_name ?: 'Website visitor'),
            ],
            'support_avatar_url' => $this->supportAvatarUrl(),
            'can_admin_reply' => ! Auth::guard('admin')->check() || $this->adminSupportPlanActive(),
            'access_message' => 'Start the one-month free trial or choose a paid plan to reply to live support messages.',
            'subscription_url' => Auth::guard('admin')->check() ? route('admin.support.payments') : '',
            'rows' => $rows,
        ];
    }

    private function storeAttachment(Request $request, SupportReply $reply): string
    {
        $file = $request->file('attachment');
        $allowed = ['pdf', 'png', 'jpg', 'jpeg', 'gif', 'webp', 'txt', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'zip'];
        $extension = strtolower($file->getClientOriginalExtension());

        abort_unless(in_array($extension, $allowed, true), 422, 'Unsupported file type.');

        $dir = public_path('support-attachments');
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        $safeTicket = preg_replace('/[^A-Za-z0-9_-]/', '-', (string) $reply->ticketid);
        $name = $safeTicket . '-' . $reply->id . '-' . Str::random(8) . '.' . $extension;
        $file->move($dir, $name);

        return 'support-attachments/' . $name;
    }

    private function makeTicketId(): string
    {
        return strtoupper(Str::random(7)) . '/' . random_int(1000, 9999) . '/' . date('m-Y');
    }

    private function dateCreated(): string
    {
        return now()->format('d M Y H:i a');
    }

    private function supportAvatarUrl(): string
    {
        $files = [];

        foreach ($this->supportAvatarDirectories() as $dir) {
            $matches = glob($dir . DIRECTORY_SEPARATOR . 'support-avatar.*') ?: [];
            if (count($matches)) {
                $files = $matches;
                break;
            }
        }

        if (! count($files)) {
            return '';
        }

        return asset('support-avatar/' . basename($files[0])) . '?v=' . filemtime($files[0]);
    }

    private function supportAvatarDirectory(): string
    {
        return file_exists(base_path('index.php'))
            ? base_path('support-avatar')
            : public_path('support-avatar');
    }

    private function supportAvatarDirectories(): array
    {
        return array_values(array_unique([
            $this->supportAvatarDirectory(),
            public_path('support-avatar'),
            base_path('support-avatar'),
        ]));
    }

    private function paystackEnabled(): bool
    {
        return (bool) config('live_support_paystack.enabled')
            && config('live_support_paystack.public_key')
            && config('live_support_paystack.secret_key');
    }

    private function planMonths(string $plan): int
    {
        return in_array($plan, ['three_month', '3_month', 'quarterly'], true) ? 3 : 1;
    }

    private function planAmountSmallest(string $plan): int
    {
        $price = $this->planMonths($plan) === 3
            ? (float) config('live_support_paystack.three_month_price', 9000)
            : (float) config('live_support_paystack.monthly_price', 3500);

        return (int) round($price * (int) config('live_support_paystack.amount_multiplier', 100));
    }

    private function recordLiveSupportAccess(string $email, string $plan, string $reference, int $amountSmallest, string $currency, bool $fromPaystack = false): void
    {
        $this->ensureLiveSupportAccessTable();

        if (LiveSupportAccess::where('paystack_reference', $reference)->exists()) {
            return;
        }

        $active = LiveSupportAccess::where('email', $email)
            ->where('paid_until', '>=', now())
            ->orderByDesc('paid_until')
            ->first();

        $base = $active ? \Carbon\Carbon::parse($active->paid_until) : now();

        LiveSupportAccess::create([
            'email' => $email,
            'plan_key' => $plan,
            'paystack_reference' => $reference,
            'currency' => $currency,
            'amount_paid_smallest' => $fromPaystack ? $amountSmallest : 0,
            'paid_until' => $base->copy()->addMonths($this->planMonths($plan))->format('Y-m-d H:i:s'),
            'created_at' => now()->format('Y-m-d H:i:s'),
        ]);
    }

    private function adminSupportPlanActive(): bool
    {
        $this->ensureLiveSupportAccessTable();

        return (bool) $this->activeLiveSupportAccess();
    }

    private function activeLiveSupportAccess()
    {
        $this->ensureLiveSupportAccessTable();

        return LiveSupportAccess::where('email', $this->adminEmail())
            ->where('paid_until', '>=', now())
            ->orderByDesc('paid_until')
            ->first();
    }

    private function freeTrialUsed(): bool
    {
        $this->ensureLiveSupportAccessTable();

        return LiveSupportAccess::where('email', $this->adminEmail())
            ->where('plan_key', 'free_trial')
            ->exists();
    }

    private function freeTrialEnabled(): bool
    {
        return (bool) config('live_support_paystack.free_trial_enabled', true);
    }

    private function liveSupportControlUnlocked(): bool
    {
        return (bool) session('live_support_control_unlocked', false);
    }

    private function liveSupportControlPassword(): string
    {
        $this->ensureLiveSupportControlTable();

        return (string) (DB::table('fc_live_support_control')
            ->where('setting_key', 'control_password')
            ->value('setting_value') ?? '');
    }

    private function ensureLiveSupportAccessTable(): void
    {
        if (Schema::hasTable('fc_live_support_access')) {
            return;
        }

        Schema::create('fc_live_support_access', function (Blueprint $table) {
            $table->increments('id');
            $table->string('email', 255);
            $table->string('plan_key', 16);
            $table->string('paystack_reference', 128)->unique();
            $table->string('currency', 16)->default('NGN');
            $table->unsignedInteger('amount_paid_smallest')->default(0);
            $table->dateTime('paid_until');
            $table->dateTime('created_at');
            $table->index(['email', 'paid_until'], 'idx_email_paid');
        });
    }

    private function ensureLiveSupportControlTable(): void
    {
        if (! Schema::hasTable('fc_live_support_control')) {
            Schema::create('fc_live_support_control', function (Blueprint $table) {
                $table->increments('id');
                $table->string('setting_key', 100)->unique();
                $table->text('setting_value')->nullable();
                $table->dateTime('updated_at')->nullable();
            });
        }

        if (! DB::table('fc_live_support_control')->where('setting_key', 'control_password')->exists()) {
            DB::table('fc_live_support_control')->insert([
                'setting_key' => 'control_password',
                'setting_value' => '',
                'updated_at' => now()->format('Y-m-d H:i:s'),
            ]);
        }
    }

    private function adminEmail(): string
    {
        $admin = Auth::guard('admin')->user();

        return strtolower(trim((string) ($admin->email ?? config('mail.from.address', ''))));
    }

    private function userLabel(SupportTicket $ticket): string
    {
        $user = $ticket->relationLoaded('user') ? $ticket->user : $ticket->user()->first();

        if (! $user) {
            return 'Account user';
        }

        $name = trim(($user->name ?? '') . ' ' . ($user->l_name ?? ''));

        return $name !== '' ? $name : ($user->email ?? 'Account user');
    }
}
