<?php

namespace App\Http\Controllers;

use App\Models\Payment;
use App\Services\Billing\InvoiceService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\Response;

/**
 * User-side invoice access — list workspace payments + download PDFs.
 *
 * Authorization: every action verifies the payment belongs to the
 * authenticated user's active workspace. Admins (is_admin=true) can
 * download any invoice for support purposes.
 */
class InvoiceController extends Controller
{
    public function __construct(private readonly InvoiceService $invoices) {}

    /**
     * Return all invoiceable (succeeded) payments for the user's
     * active workspace, most recent first. Used by the billing page
     * to render the "Invoices" table.
     */
    public function index()
    {
        $workspace = Auth::user()->activeWorkspace;
        if (!$workspace) abort(404);

        $payments = Payment::where('workspace_id', $workspace->id)
            ->where('status', 'succeeded')
            ->orderByDesc('created_at')
            ->get();

        return view('settings.invoices', compact('payments'));
    }

    /**
     * Stream the invoice PDF for download. Generates on demand if the
     * file is missing (e.g. payment succeeded before this feature
     * shipped) so users always get a working file.
     */
    public function download(Payment $payment)
    {
        $this->authorizePayment($payment);

        $path = $this->invoices->ensurePdf($payment);

        if (!Storage::disk('local')->exists($path)) {
            abort(404, 'Invoice file missing.');
        }

        $filename = ($payment->invoice_number ?: 'INV-' . $payment->id) . '.pdf';

        return response()->streamDownload(
            fn () => print Storage::disk('local')->get($path),
            $filename,
            [
                'Content-Type' => 'application/pdf',
                'Cache-Control' => 'private, max-age=0, must-revalidate',
            ]
        );
    }

    /**
     * Render the PDF inline in the browser (preview-in-tab). Same auth
     * rules as download() but with Content-Disposition: inline.
     */
    public function view(Payment $payment): Response
    {
        $this->authorizePayment($payment);
        $path = $this->invoices->ensurePdf($payment);

        return response(Storage::disk('local')->get($path), 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="' . ($payment->invoice_number ?: 'invoice') . '.pdf"',
        ]);
    }

    /**
     * Beautiful HTML preview rendered inside the in-app iframe modal.
     *
     * Why a separate HTML render instead of iframing the PDF:
     * - Browser PDF viewers add their own chrome (thumbnail panel, zoom
     *   toolbar, page selector) that looks generic and clutters the modal.
     * - The HTML version uses the actual app theme tokens + body font, so
     *   the preview feels native to the platform.
     * - It's faster — no DomPDF rasterization. PDF generation only runs
     *   when the user actually clicks Download.
     */
    public function preview(Payment $payment): View
    {
        $this->authorizePayment($payment);

        // Make sure an invoice number is assigned even on first preview
        // so the header shows INV-... instead of #123.
        if (empty($payment->invoice_number)) {
            $this->invoices->assignNumber($payment);
            $payment->refresh();
        }

        return view('invoices.preview', [
            'payment' => $payment,
            'seller'  => $this->invoices->getSellerInfo(),
            'buyer'   => $this->invoices->getBuyerSnapshot($payment),
            'lines'   => $this->invoices->getLineItems($payment),
        ]);
    }

    /**
     * Owner-or-admin gate. We let admins through unconditionally because
     * they sometimes need to re-send an invoice to a customer who can't
     * find their own login.
     */
    protected function authorizePayment(Payment $payment): void
    {
        $user = Auth::user();
        if (!$user) abort(403);
        if ($user->is_admin) return;

        $workspace = $user->activeWorkspace;
        if (!$workspace || $payment->workspace_id !== $workspace->id) {
            abort(403, 'You do not have access to this invoice.');
        }
    }
}
