<?php

namespace App\Http\Controllers;

use App\Exceptions\TokenExpiredException;
use App\Http\Requests\StoreEmailSubscriberRequest;
use App\Models\EmailSubscriber;
use App\Services\EmailSubscriptionService;
use App\Mail\NewsletterMail;
use App\Http\Requests\SendNewsletterRequest;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;

class EmailSubscriptionController extends Controller
{
    public function __construct(
        protected EmailSubscriptionService $subscriptionService
    ) {}

    // =========================================================================
    // PUBLIC ROUTES (no auth required)
    // =========================================================================

    /**
     * Handle a new subscription form submission.
     * Rate-limited via throttle:5,1 middleware on the route.
     * Requirements: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6
     */
    public function store(StoreEmailSubscriberRequest $request)
    {
        $this->subscriptionService->subscribe(
            $request->validated(),
            $request->ip()
        );

        if ($request->expectsJson()) {
            return response()->json([
                'message' => 'Thank you! Please check your email to confirm your subscription.',
            ]);
        }

        return back()->with('success', 'Thank you! Please check your email to confirm your subscription.');
    }

    /**
     * Confirm a subscriber's email via their confirmation token.
     * Requirements: 7.7, 7.8, 7.9
     */
    public function confirm(string $token)
    {
        try {
            $subscriber = $this->subscriptionService->confirm($token);
        } catch (ModelNotFoundException) {
            return view('subscription.error', [
                'message' => 'Invalid confirmation link. Please subscribe again.',
            ]);
        } catch (TokenExpiredException) {
            return view('subscription.error', [
                'message' => 'This confirmation link has expired (valid for 48 hours). Please subscribe again.',
            ]);
        }

        return view('subscription.confirmed', compact('subscriber'));
    }

    /**
     * Unsubscribe a subscriber via their confirmation token.
     * Requirements: 7.10
     */
    public function unsubscribe(string $token)
    {
        try {
            $subscriber = $this->subscriptionService->unsubscribe($token);
        } catch (ModelNotFoundException) {
            return view('subscription.error', [
                'message' => 'Invalid unsubscribe link.',
            ]);
        }

        return view('subscription.unsubscribed', compact('subscriber'));
    }

    // =========================================================================
    // DASHBOARD ROUTES (auth + permission required)
    // =========================================================================

    /**
     * List all subscribers with pagination, search, and status filter.
     * Requirements: 9.1, 9.2, 9.7
     */
    public function index(Request $request)
    {
        abort_unless(auth()->user()->can('view email subscribers'), 403);

        $query = EmailSubscriber::latest('subscribed_at');

        if ($search = $request->input('search')) {
            $query->where(function ($q) use ($search) {
                $q->where('email', 'like', "%{$search}%")
                  ->orWhere('name', 'like', "%{$search}%");
            });
        }

        if ($status = $request->input('status')) {
            match ($status) {
                'active'        => $query->where('is_active', true)->whereNotNull('confirmed_at')->whereNull('unsubscribed_at'),
                'unconfirmed'   => $query->whereNull('confirmed_at')->whereNull('unsubscribed_at'),
                'unsubscribed'  => $query->whereNotNull('unsubscribed_at'),
                default         => null,
            };
        }

        $subscribers = $query->paginate(20)->withQueryString();

        return view('email-subscribers.index', compact('subscribers'));
    }

    /**
     * Show a single subscriber's details.
     * Requirements: 9.2
     */
    public function show(EmailSubscriber $emailSubscriber)
    {
        abort_unless(auth()->user()->can('view email subscribers'), 403);

        return view('email-subscribers.show', compact('emailSubscriber'));
    }

    /**
     * Stream a CSV export of all active confirmed subscribers.
     * Requirements: 9.3
     */
    public function export()
    {
        abort_unless(auth()->user()->can('export email subscribers'), 403);

        return $this->subscriptionService->exportCsv();
    }

    /**
     * Show the newsletter composition interface.
     * Only users with the `manage email subscribers` permission may access.
     */
    public function compose()
    {
        abort_unless(auth()->user()->can('manage email subscribers'), 403);

        // Provide a limited set of recent subscribers for manual selection in the UI.
        $subscribers = EmailSubscriber::latest('subscribed_at')->limit(200)->get();

        return view('email-subscribers.compose', compact('subscribers'));
    }

    /**
     * Send a newsletter to selected subscribers or to all active confirmed subscribers.
     */
    public function send(SendNewsletterRequest $request)
    {
        abort_unless(auth()->user()->can('manage email subscribers'), 403);

        $data = $request->validated();

        // Determine recipients
        if (!empty($data['recipient_ids'])) {
            $recipients = EmailSubscriber::whereIn('id', $data['recipient_ids'])->get();
        } elseif (!empty($data['send_to_all'])) {
            $recipients = $this->subscriptionService->getActiveSubscribers();
        } else {
            return back()->with('error', 'No recipients selected.');
        }

        foreach ($recipients as $recipient) {
            Mail::to($recipient->email)->queue(new NewsletterMail($data['subject'], $data['body']));
        }

        return back()->with('success', 'Newsletter queued for delivery to ' . $recipients->count() . ' recipient(s).');
    }
}
