<?php

namespace App\Http\Controllers\Admin;

use App\Core\Repositories\CustomerRepository;
use App\Core\Repositories\InvoiceRepository;
use App\Core\Services\Invoice\InvoiceService;
use App\Core\Services\Invoice\PdfService;
use App\Core\Services\Payment\PaymentService;
use App\Http\Controllers\Controller;
use App\Models\Company;
use App\Models\CompanySetting;
use App\Models\Invoice;
use App\Services\ReminderService;
use App\Support\InvoiceTemplateResolver;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\Response;

class InvoiceController extends Controller
{
    public function __construct(
        private InvoiceService $invoiceService,
        private InvoiceRepository $invoiceRepository,
        private CustomerRepository $customerRepository,
        private PdfService $pdfService,
        private PaymentService $paymentService,
        private ReminderService $reminderService
    ) {}

    /**
     * Display a listing of invoices
     */
    public function index(Request $request): View
    {
        $this->authorize('viewAny', Invoice::class);

        $filters = [
            'status' => $request->get('status'),
            'customer_id' => $request->get('customer_id'),
            'date_from' => $request->get('date_from'),
            'date_to' => $request->get('date_to'),
            'search' => $request->get('search'),
        ];

        $perPage = $request->get('per_page', 15);
        $invoices = $this->invoiceRepository->getPaginated($perPage, $filters);
        $customers = $this->customerRepository->getAll();

        return view('admin.invoices.index', [
            'invoices' => $invoices,
            'customers' => $customers,
            'filters' => $filters,
        ]);
    }

    /**
     * Show the form for creating a new invoice
     */
    public function create(): View
    {
        $this->authorize('create', Invoice::class);

        $customers = $this->customerRepository->getAll();
        $companySettings = \App\Models\CompanySetting::getSettings();
        $localizationSettings = \App\Models\LocalizationSetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $bankAccounts = \App\Models\BankAccount::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $nextInvoiceNumber = $this->invoiceRepository->getPreviewInvoiceNumber();
        $invoiceSettings = \App\Models\InvoiceNumberingSetting::getSettings();

        return view('admin.invoices.create', [
            'customers' => $customers,
            'companySettings' => $companySettings,
            'localizationSettings' => $localizationSettings,
            'currencies' => $currencies,
            'signatures' => $signatures,
            'bankAccounts' => $bankAccounts,
            'nextInvoiceNumber' => $nextInvoiceNumber,
            'invoiceSettings' => $invoiceSettings,
        ]);
    }

    /**
     * Preview invoice before creating
     */
    public function preview(Request $request): View
    {
        $this->authorize('create', Invoice::class);

        // Get form data
        $data = $request->all();

        // Get related data
        $companySettings = \App\Models\CompanySetting::getSettings();
        $customers = $this->customerRepository->getAll();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();

        // Get customer if selected
        $customer = null;
        if (! empty($data['customer_id'])) {
            $customer = $this->customerRepository->getById($data['customer_id']);
        }

        // Get selected currency
        $selectedCurrency = $currencies->where('code', $data['currency'] ?? 'USD')->first();

        // Calculate totals
        $subtotal = 0;
        $taxAmount = 0;
        $items = [];

        if (! empty($data['items'])) {
            foreach ($data['items'] as $item) {
                $quantity = floatval($item['quantity'] ?? 0);
                $unitPrice = floatval($item['unit_price'] ?? 0);
                $taxRate = floatval($item['tax_rate'] ?? 0);

                $itemSubtotal = $quantity * $unitPrice;
                $itemTax = $itemSubtotal * ($taxRate / 100);

                $subtotal += $itemSubtotal;
                $taxAmount += $itemTax;

                $items[] = [
                    'description' => $item['description'] ?? '',
                    'notes' => $item['notes'] ?? '',
                    'quantity' => $quantity,
                    'unit_price' => $unitPrice,
                    'tax_rate' => $taxRate,
                    'total' => $itemSubtotal + $itemTax,
                ];
            }
        }

        // Calculate discount
        $discountType = $data['discount_type'] ?? 'fixed';
        $discountAmount = floatval($data['discount_amount'] ?? 0);
        $discount = 0;

        if ($discountType === 'percentage') {
            $discount = $subtotal * ($discountAmount / 100);
        } else {
            $discount = $discountAmount;
        }

        $total = $subtotal + $taxAmount - $discount;
        $paidAmount = floatval($data['paid_amount'] ?? 0);
        $balanceDue = max(0, $total - $paidAmount);

        $templateKey = InvoiceTemplateResolver::normalize($data['template'] ?? CompanySetting::getDocumentDefaultTemplateKey('invoice'));
        $templateView = InvoiceTemplateResolver::webView($templateKey);

        // Invoice PDF/HTML templates expect a single $invoice with customer + items relations.
        // This unsaved model mirrors saved invoices so @include($templateView) renders line items and Bill To.
        $previewInvoice = Invoice::make([
            'invoice_number' => $data['invoice_number'] ?? 'PREVIEW',
            'issue_date' => ! empty($data['issue_date']) ? Carbon::parse($data['issue_date']) : now(),
            'due_date' => ! empty($data['due_date']) ? Carbon::parse($data['due_date']) : now()->addDays(30),
            'status' => $data['status'] ?? 'draft',
            'currency' => $data['currency'] ?? 'USD',
            'subtotal' => $subtotal,
            'tax_amount' => $taxAmount,
            'discount_amount' => $discount,
            'discount_type' => $discountType,
            'total' => $total,
            'paid_amount' => $paidAmount,
            'balance' => $balanceDue,
            'notes' => $data['notes'] ?? null,
            'terms' => $data['terms'] ?? null,
            'payment_method' => $data['payment_method'] ?? null,
            'customer_id' => $data['customer_id'] ?? null,
        ]);

        if ($customer) {
            $previewInvoice->setRelation('customer', $customer);
        }

        $lineItemModels = collect($items)->values()->map(function (array $row) {
            return (object) [
                'description' => $row['description'] ?? '',
                'notes' => $row['notes'] ?? '',
                'quantity' => (float) ($row['quantity'] ?? 0),
                'unit_price' => (float) ($row['unit_price'] ?? 0),
                'tax_rate' => (float) ($row['tax_rate'] ?? 0),
                'total' => (float) ($row['total'] ?? 0),
            ];
        });
        $previewInvoice->setRelation('items', $lineItemModels);

        return view('admin.invoices.preview', [
            'invoice' => $previewInvoice,
            'data' => $data,
            'templateView' => $templateView,
            'companySettings' => $companySettings,
            'customer' => $customer,
            'currencies' => $currencies,
            'selectedCurrency' => $selectedCurrency,
            'signatures' => $signatures,
            'items' => $items,
            'subtotal' => $subtotal,
            'taxAmount' => $taxAmount,
            'discount' => $discount,
            'total' => $total,
            'paidAmount' => $paidAmount,
            'balanceDue' => $balanceDue,
        ]);
    }

    /**
     * Store a newly created invoice
     */
    public function store(Request $request): RedirectResponse
    {
        $this->authorize('create', Invoice::class);

        // After POST preview, the browser URL is still /admin/invoices/preview; default
        // validate() redirect("back") would hit GET /invoices/preview and break the flow.
        $request->merge([
            'signature_id' => $request->filled('signature_id') ? $request->input('signature_id') : null,
        ]);

        $validator = Validator::make($request->all(), [
            'invoice_number' => 'nullable|string|unique:invoices,invoice_number',
            'customer_id' => 'required|exists:customers,id',
            'issue_date' => 'required|date',
            'due_date' => 'required|date|after_or_equal:issue_date',
            'status' => 'nullable|in:draft,sent,viewed,partial,paid,overdue,cancelled',
            'currency' => 'nullable|string|size:3',
            'exchange_rate' => 'nullable|numeric|min:0',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'discount_amount' => 'nullable|numeric|min:0|max:999999999.99',
            'discount_type' => 'nullable|in:fixed,percentage',
            'paid_amount' => 'nullable|numeric|min:0|max:999999999.99',
            'payment_method' => 'nullable|string|max:255',
            'signature_id' => 'nullable|exists:signatures,id',
            'items' => 'required|array|min:1',
            'items.*.description' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0|max:100',
            'items.*.notes' => 'nullable|string',
            'template' => 'nullable|in:modern,classic,minimal,bold',
        ]);

        if ($validator->fails()) {
            return redirect()
                ->route('admin.invoices.create')
                ->withErrors($validator)
                ->withInput();
        }

        $validated = $validator->validated();

        // Sanitize numeric values to prevent overflow
        if (isset($validated['discount_amount'])) {
            $validated['discount_amount'] = min(max(floatval($validated['discount_amount']), 0), 999999999.99);
        }
        if (isset($validated['paid_amount'])) {
            $validated['paid_amount'] = min(max(floatval($validated['paid_amount']), 0), 999999999.99);
        }

        // Ensure items have proper numeric values
        if (isset($validated['items'])) {
            foreach ($validated['items'] as $key => $item) {
                $validated['items'][$key]['quantity'] = min(max(floatval($item['quantity'] ?? 0), 0.01), 999999.99);
                $validated['items'][$key]['unit_price'] = min(max(floatval($item['unit_price'] ?? 0), 0), 999999999.99);
                $validated['items'][$key]['tax_rate'] = min(max(floatval($item['tax_rate'] ?? 0), 0), 100);
            }
        }

        $invoice = $this->invoiceService->create($validated);

        try {
            $this->reminderService->sendInvoiceCreated($invoice->fresh(['customer']));
        } catch (\Throwable) {
        }

        return redirect()
            ->route('admin.invoices.index')
            ->with('success', 'Invoice '.$invoice->invoice_number.' created successfully.');
    }

    /**
     * Display the specified invoice
     */
    public function show(Invoice $invoice): View
    {
        $this->authorize('view', $invoice);

        $invoice->load([
            'customer',
            'items',
            'payments',
            'reminders',
            'receipt',
            'reminderLogs' => fn ($q) => $q->orderByDesc('id')->limit(20),
        ]);

        return view('admin.invoices.show', [
            'invoice' => $invoice,
        ]);
    }

    /**
     * View invoice with template and action buttons
     */
    public function view(Request $request, Invoice $invoice): View|Response
    {
        $this->authorize('view', $invoice);

        if ($request->query('preview') === 'pdf-template') {
            $invoice->load(['customer', 'items']);

            return response($this->pdfService->generate($invoice), 200, [
                'Content-Type' => 'application/pdf',
                'Content-Disposition' => 'inline; filename="invoice-'.$invoice->invoice_number.'-preview.pdf"',
            ]);
        }

        $invoice->load(['customer', 'items', 'payments']);
        $companySettings = \App\Models\CompanySetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $selectedCurrency = $currencies->where('code', $invoice->currency)->first();

        $templateKey = InvoiceTemplateResolver::resolveKeyForInvoice($invoice);
        $templateView = InvoiceTemplateResolver::webView($templateKey);

        // Get email and WhatsApp configurations
        $emailConfig = \App\Models\EmailConfiguration::getActive();
        $whatsappConfig = \App\Models\WhatsAppConfiguration::where('is_active', true)->first();

        // Calculate totals from invoice
        $subtotal = $invoice->items->sum(function ($item) {
            return $item->quantity * $item->unit_price;
        });

        $taxAmount = $invoice->items->sum(function ($item) {
            return ($item->quantity * $item->unit_price) * ($item->tax_rate / 100);
        });

        $discountType = $invoice->discount_type ?? 'fixed';
        $discountAmount = floatval($invoice->discount_amount ?? 0);
        $discount = 0;

        if ($discountType === 'percentage') {
            $discount = $subtotal * ($discountAmount / 100);
        } else {
            $discount = $discountAmount;
        }

        $total = $subtotal + $taxAmount - $discount;
        $paidAmount = floatval($invoice->paid_amount ?? 0);
        // Line-item math can drift from stored invoice totals; `balance` can drift too.
        // Header totals (invoice.total − paid_amount) are what partial payments use — include them.
        $calculatedBalanceDue = max(0, $total - $paidAmount);
        $storedBalanceDue = max(0, (float) ($invoice->balance ?? 0));
        $dbOutstanding = max(0, (float) ($invoice->total ?? 0) - $paidAmount);
        $balanceDue = max($calculatedBalanceDue, $storedBalanceDue, $dbOutstanding);
        $isFullyPaid = $balanceDue <= 0;

        // Format items for template
        $items = $invoice->items->map(function ($item) {
            return [
                'description' => $item->description,
                'notes' => $item->notes ?? '',
                'quantity' => $item->quantity,
                'unit_price' => $item->unit_price,
                'tax_rate' => $item->tax_rate,
                'total' => ($item->quantity * $item->unit_price) + (($item->quantity * $item->unit_price) * ($item->tax_rate / 100)),
            ];
        })->toArray();

        // Format data for template
        $data = [
            'invoice_number' => $invoice->invoice_number,
            'issue_date' => $invoice->issue_date->format('Y-m-d'),
            'due_date' => $invoice->due_date->format('Y-m-d'),
            'currency' => $invoice->currency,
            'notes' => $invoice->notes,
            'terms' => $invoice->terms,
            'signature_id' => $invoice->signature_id,
            'discount_type' => $invoice->discount_type,
            'discount_amount' => $invoice->discount_amount,
            'paid_amount' => $invoice->paid_amount,
        ];

        return view('admin.invoices.view', [
            'invoice' => $invoice,
            'data' => $data,
            'companySettings' => $companySettings,
            'customer' => $invoice->customer,
            'currencies' => $currencies,
            'selectedCurrency' => $selectedCurrency,
            'signatures' => $signatures,
            'items' => $items,
            'subtotal' => $subtotal,
            'taxAmount' => $taxAmount,
            'discount' => $discount,
            'total' => $total,
            'paidAmount' => $paidAmount,
            'balanceDue' => $balanceDue,
            'isFullyPaid' => $isFullyPaid,
            'emailConfig' => $emailConfig,
            'whatsappConfig' => $whatsappConfig,
            'templateView' => $templateView,
        ]);
    }

    /**
     * Show the form for editing the invoice
     */
    public function edit(Invoice $invoice): View
    {
        $this->authorize('update', $invoice);

        $invoice->load(['customer', 'items']);
        $customers = $this->customerRepository->getAll();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $bankAccounts = \App\Models\BankAccount::where('is_active', true)->orderBy('is_default', 'desc')->get();

        return view('admin.invoices.edit', [
            'invoice' => $invoice,
            'customers' => $customers,
            'currencies' => $currencies,
            'signatures' => $signatures,
            'bankAccounts' => $bankAccounts,
            'invoiceTemplateOptions' => $this->invoiceTemplateOptions(),
            'defaultInvoiceTemplate' => CompanySetting::getDocumentDefaultTemplateKey('invoice'),
        ]);
    }

    /**
     * Update the invoice
     */
    public function update(Request $request, Invoice $invoice): RedirectResponse
    {
        $this->authorize('update', $invoice);

        $validated = $request->validate([
            'customer_id' => 'required|exists:customers,id',
            'issue_date' => 'required|date',
            'due_date' => 'required|date|after_or_equal:issue_date',
            'status' => 'nullable|in:draft,sent,viewed,partial,paid,overdue,cancelled',
            'currency' => 'nullable|string|size:3',
            'exchange_rate' => 'nullable|numeric|min:0',
            'notes' => 'nullable|string',
            'terms' => 'nullable|string',
            'discount_amount' => 'nullable|numeric|min:0|max:999999999.99',
            'discount_type' => 'nullable|in:fixed,percentage',
            'payment_method' => 'nullable|string|max:255',
            'signature_id' => 'nullable|exists:signatures,id',
            'items' => 'required|array|min:1',
            'items.*.description' => 'required|string',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_price' => 'required|numeric|min:0',
            'items.*.tax_rate' => 'nullable|numeric|min:0|max:100',
            'template' => 'nullable|in:modern,classic,minimal,bold',
        ]);

        // Sanitize numeric values to prevent overflow
        if (isset($validated['discount_amount'])) {
            $validated['discount_amount'] = min(max(floatval($validated['discount_amount']), 0), 999999999.99);
        }

        // Ensure items have proper numeric values
        if (isset($validated['items'])) {
            foreach ($validated['items'] as $key => $item) {
                $validated['items'][$key]['quantity'] = min(max(floatval($item['quantity'] ?? 0), 0.01), 999999.99);
                $validated['items'][$key]['unit_price'] = min(max(floatval($item['unit_price'] ?? 0), 0), 999999999.99);
                $validated['items'][$key]['tax_rate'] = min(max(floatval($item['tax_rate'] ?? 0), 0), 100);
            }
        }

        $this->invoiceService->update($invoice, $validated);

        return redirect()
            ->route('admin.invoices.show', $invoice)
            ->with('success', 'Invoice updated successfully.');
    }

    /**
     * Remove the invoice
     */
    public function destroy(Invoice $invoice): RedirectResponse
    {
        $this->authorize('delete', $invoice);

        $this->invoiceService->delete($invoice);

        return redirect()
            ->route('admin.invoices.index')
            ->with('success', 'Invoice deleted successfully.');
    }

    /**
     * Send invoice
     */
    public function send(Invoice $invoice): RedirectResponse
    {
        $this->authorize('send', $invoice);

        $this->invoiceService->markAsSent($invoice);

        return redirect()
            ->route('admin.invoices.show', $invoice)
            ->with('success', 'Invoice sent successfully.');
    }

    /**
     * Preview existing invoice
     */
    public function previewExisting(Invoice $invoice): View
    {
        $this->authorize('view', $invoice);

        $invoice->load(['customer', 'items', 'payments']);
        $companySettings = \App\Models\CompanySetting::getSettings();
        $currencies = \App\Models\Currency::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $signatures = \App\Models\Signature::where('is_active', true)->orderBy('is_default', 'desc')->get();
        $selectedCurrency = $currencies->where('code', $invoice->currency)->first();

        $templateKey = InvoiceTemplateResolver::resolveKeyForInvoice($invoice);
        $templateView = InvoiceTemplateResolver::webView($templateKey);

        // Get email and WhatsApp configurations
        $emailConfig = \App\Models\EmailConfiguration::getActive();
        $whatsappConfig = \App\Models\WhatsAppConfiguration::where('is_active', true)->first();

        // Calculate totals from invoice
        $subtotal = $invoice->items->sum(function ($item) {
            return $item->quantity * $item->unit_price;
        });

        $taxAmount = $invoice->items->sum(function ($item) {
            return ($item->quantity * $item->unit_price) * ($item->tax_rate / 100);
        });

        $discountType = $invoice->discount_type ?? 'fixed';
        $discountAmount = floatval($invoice->discount_amount ?? 0);
        $discount = 0;

        if ($discountType === 'percentage') {
            $discount = $subtotal * ($discountAmount / 100);
        } else {
            $discount = $discountAmount;
        }

        $total = $subtotal + $taxAmount - $discount;
        $paidAmount = floatval($invoice->paid_amount ?? 0);
        $balanceDue = max(0, $total - $paidAmount);

        // Format items for preview
        $items = $invoice->items->map(function ($item) {
            return [
                'description' => $item->description,
                'notes' => $item->notes ?? '',
                'quantity' => $item->quantity,
                'unit_price' => $item->unit_price,
                'tax_rate' => $item->tax_rate,
                'total' => ($item->quantity * $item->unit_price) + (($item->quantity * $item->unit_price) * ($item->tax_rate / 100)),
            ];
        })->toArray();

        // Format data for preview view
        $data = [
            'invoice_number' => $invoice->invoice_number,
            'issue_date' => $invoice->issue_date->format('Y-m-d'),
            'due_date' => $invoice->due_date->format('Y-m-d'),
            'currency' => $invoice->currency,
            'notes' => $invoice->notes,
            'terms' => $invoice->terms,
            'payment_method' => $invoice->payment_method,
            'signature_id' => $invoice->signature_id,
            'discount_type' => $invoice->discount_type,
            'discount_amount' => $invoice->discount_amount,
            'paid_amount' => $invoice->paid_amount,
        ];

        return view('admin.invoices.preview', [
            'invoice' => $invoice,
            'data' => $data,
            'companySettings' => $companySettings,
            'customer' => $invoice->customer,
            'currencies' => $currencies,
            'selectedCurrency' => $selectedCurrency,
            'signatures' => $signatures,
            'items' => $items,
            'subtotal' => $subtotal,
            'taxAmount' => $taxAmount,
            'discount' => $discount,
            'total' => $total,
            'paidAmount' => $paidAmount,
            'balanceDue' => $balanceDue,
            'emailConfig' => $emailConfig,
            'whatsappConfig' => $whatsappConfig,
            'isExisting' => true,
            'templateView' => $templateView,
        ]);
    }

    /**
     * Send invoice via email
     */
    public function sendEmail(Request $request, Invoice $invoice): JsonResponse
    {
        $this->authorize('send', $invoice);

        $request->validate([
            'email' => 'required|email',
        ]);

        $emailConfig = \App\Models\EmailConfiguration::getActive();
        if (! $emailConfig || ! $emailConfig->is_active) {
            return response()->json([
                'success' => false,
                'message' => 'Email configuration is not set up. Please configure email settings first.',
            ], 400);
        }

        try {
            $invoice->loadMissing('customer');
            $pdfContent = $this->pdfService->generate($invoice);
            $filename = 'invoice-'.$invoice->invoice_number.'.pdf';
            $toEmail = trim((string) $request->input('email'));
            $companySettings = CompanySetting::getSettings();

            Mail::raw(
                'Hello '.($invoice->customer->name ?? 'Customer').",\n\n".
                "Please find your invoice #{$invoice->invoice_number} attached.\n\n".
                "Thank you,\n".($companySettings->company_name ?? config('app.name')),
                function ($message) use ($toEmail, $invoice, $pdfContent, $filename) {
                    $message->to($toEmail)
                        ->subject('Invoice '.$invoice->invoice_number)
                        ->attachData($pdfContent, $filename, ['mime' => 'application/pdf']);
                }
            );

            return response()->json([
                'success' => true,
                'message' => 'Invoice sent successfully to '.$toEmail,
            ]);
        } catch (\Throwable $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send invoice email: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * Send invoice via WhatsApp
     */
    public function sendWhatsApp(Request $request, Invoice $invoice): JsonResponse
    {
        $this->authorize('send', $invoice);

        $request->validate([
            'phone' => 'nullable|string',
        ]);

        try {
            $phone = trim((string) $request->input('phone', ''));
            if ($phone === '') {
                $invoice->loadMissing('customer');
                $phone = trim((string) ($invoice->customer->phone ?? ''));
            }
            if ($phone === '') {
                return response()->json([
                    'success' => false,
                    'message' => 'No WhatsApp recipient number found. Add one in WhatsApp settings or provide a number.',
                ], 422);
            }

            $whatsappService = new \App\Core\Services\WhatsAppService;

            // Generate PDF
            $pdfContent = $this->pdfService->generate($invoice);
            $filename = 'invoices/invoice_'.$invoice->invoice_number.'_'.time().'.pdf';
            \Illuminate\Support\Facades\Storage::disk('public')->put($filename, $pdfContent);

            // Get full URL for the document
            $documentUrl = \Illuminate\Support\Facades\Storage::disk('public')->url($filename);

            // Create message
            $companySettings = \App\Models\CompanySetting::getSettings();
            $invoice->load('customer');
            $message = 'Hello '.($invoice->customer->name ?? 'Customer').",\n\n";
            $message .= "Your invoice #{$invoice->invoice_number} is ready.\n\n";
            $message .= "Invoice Details:\n";
            $message .= 'Amount: '.number_format($invoice->total, 2)." {$invoice->currency}\n";
            $message .= 'Due Date: '.$invoice->due_date->format('M d, Y')."\n\n";
            $message .= "Please find the invoice attached.\n\n";
            $message .= "Thank you,\n{$companySettings->company_name}";

            // Send WhatsApp message with PDF
            $result = $whatsappService->send($phone, $message, $documentUrl, 'document');

            if ($result['success']) {
                return response()->json([
                    'success' => true,
                    'message' => 'Invoice sent successfully via WhatsApp to '.$phone,
                ]);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => $result['message'],
                ], 400);
            }
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send invoice via WhatsApp: '.$e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get shareable link for invoice
     */
    public function getShareLink(Invoice $invoice): JsonResponse
    {
        $this->authorize('view', $invoice);

        // Ensure invoice has a public token
        if (empty($invoice->public_token)) {
            $invoice->public_token = \Illuminate\Support\Str::random(32);
            $invoice->save();
        }

        // Prefer explicit public base so share links are real HTTPS URLs (WhatsApp links them reliably).
        $publicBase = trim((string) config('invoice.public_base_url', ''));
        $shareLink = $publicBase !== ''
            ? rtrim($publicBase, '/').'/invoice/'.$invoice->public_token
            : route('invoice.public', ['token' => $invoice->public_token], absolute: true);

        return response()->json([
            'success' => true,
            'link' => $shareLink,
        ]);
    }

    /**
     * Download invoice PDF
     */
    public function downloadPdf(Invoice $invoice)
    {
        $this->authorize('downloadPdf', $invoice);

        return $this->pdfService->download($invoice);
    }

    /**
     * Get invoice data for modals
     */
    public function getInvoiceData(Invoice $invoice): JsonResponse
    {
        $this->authorize('view', $invoice);

        $invoice->load('customer');
        $companySettings = \App\Models\CompanySetting::getSettings();

        $remainingDue = max(0, (float) $invoice->total - (float) ($invoice->paid_amount ?? 0));
        $storedBalance = max(0, (float) ($invoice->balance ?? 0));
        $balance = max($remainingDue, $storedBalance);

        return response()->json([
            'invoice_number' => $invoice->invoice_number,
            'customer_name' => $invoice->customer->name ?? 'N/A',
            'customer_email' => $invoice->customer->email ?? '',
            'total' => $invoice->total,
            'balance' => $balance,
            'currency' => $invoice->currency,
            'issue_date' => $invoice->issue_date?->toIso8601String(),
            'due_date' => $invoice->due_date?->toIso8601String(),
            'paid_amount' => $invoice->paid_amount,
            'company_name' => $companySettings->company_name ?? config('app.name'),
        ]);
    }

    /**
     * Update invoice status
     */
    public function updateStatus(Request $request, Invoice $invoice): RedirectResponse
    {
        $this->authorize('update', $invoice);

        $request->validate([
            'status' => 'required|in:draft,sent,viewed,unpaid,partial,paid,overdue',
        ]);

        $this->invoiceRepository->update($invoice, [
            'status' => $request->status,
        ]);

        return redirect()->back()->with('success', 'Invoice status updated successfully.');
    }

    /**
     * Mark invoice as paid
     */
    public function markAsPaid(Request $request, Invoice $invoice): RedirectResponse
    {
        $this->authorize('update', $invoice);

        $request->validate([
            'amount' => 'required|numeric|min:0',
            'payment_date' => 'required|date',
            'payment_method' => 'required|string',
            'transaction_charge' => 'nullable|numeric|min:0',
            'bank_account_id' => 'nullable|exists:bank_accounts,id',
            'transaction_id' => 'nullable|string',
        ]);

        // Record payment
        $this->paymentService->recordPayment($invoice, [
            'amount' => $request->amount,
            'currency' => $invoice->currency,
            'payment_method' => $request->payment_method,
            'payment_date' => $request->payment_date,
            'transaction_id' => $request->transaction_id,
            'reference' => $request->transaction_id,
            'notes' => $request->notes ?? null,
        ]);

        // TODO: Send notification email if requested
        if ($request->has('notify_client') && $request->notify_client) {
            // Implement email notification
        }

        // TODO: Collect testimonial if requested
        if ($request->has('collect_testimonial') && $request->collect_testimonial) {
            // Implement testimonial collection
        }

        return redirect()->back()->with('success', 'Invoice marked as paid successfully.');
    }

    /**
     * API: Get company settings for auto-loading
     */
    public function getCompanySettings(): JsonResponse
    {
        try {
            $companySettings = \App\Models\CompanySetting::getSettings();

            $logoUrl = null;
            if ($companySettings->company_logo) {
                if (\Illuminate\Support\Facades\Storage::disk('public')->exists($companySettings->company_logo)) {
                    $logoUrl = asset('storage/'.$companySettings->company_logo);
                }
            }

            $resolvedCompany = Company::resolveBillFromCompany();

            return response()->json([
                'success' => true,
                'company' => [
                    'id' => $resolvedCompany?->id,
                    'name' => $companySettings->company_name ?? '',
                    'email' => $companySettings->company_email ?? '',
                    'phone' => $companySettings->company_phone ?? '',
                    'fax' => $companySettings->company_fax ?? '',
                    'address' => $companySettings->company_address ?? '',
                    'city' => $companySettings->company_city ?? '',
                    'state' => $companySettings->company_state ?? '',
                    'zip' => $companySettings->company_zip ?? '',
                    'country' => $companySettings->company_country ?? '',
                    'tax_id' => $companySettings->company_tax_id ?? '',
                    'registration_number' => $companySettings->company_registration_number ?? '',
                    'logo' => $logoUrl,
                    'logo_path' => $companySettings->company_logo,
                ],
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching company settings: '.$e->getMessage(),
                'company' => null,
            ], 500);
        }
    }

    /**
     * API: Get companies for dropdown (AJAX)
     */
    public function getCompanies(Request $request): JsonResponse
    {
        try {
            $search = trim((string) $request->get('search', ''));
            $searchLower = strtolower($search);

            $rows = [];

            // Bill-from default: company settings (not always duplicated in `companies` table)
            $settings = CompanySetting::getSettings();
            if ($settings && filled($settings->company_name ?? null)) {
                $haystack = strtolower(implode(' ', array_filter([
                    (string) ($settings->company_name ?? ''),
                    (string) ($settings->company_email ?? ''),
                    (string) ($settings->company_phone ?? ''),
                ])));

                if ($search === '' || str_contains($haystack, $searchLower)) {
                    $logoUrl = null;
                    if (! empty($settings->company_logo) && \Illuminate\Support\Facades\Storage::disk('public')->exists($settings->company_logo)) {
                        $logoUrl = asset('storage/'.$settings->company_logo);
                    }

                    $rows[] = [
                        'id' => null,
                        'name' => $settings->company_name,
                        'email' => $settings->company_email ?? '',
                        'phone' => $settings->company_phone ?? '',
                        'address' => $settings->company_address ?? '',
                        'city' => $settings->company_city ?? '',
                        'state' => $settings->company_state ?? '',
                        'zip' => $settings->company_zip ?? '',
                        'country' => $settings->company_country ?? '',
                        'logo' => $logoUrl,
                        'logo_path' => $settings->company_logo,
                        'from_settings' => true,
                    ];
                }
            }

            $query = \App\Models\Company::where('is_active', true);

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

            $limit = max(0, 50 - count($rows));
            if ($limit > 0) {
                $companies = $query->orderBy('name', 'asc')->limit($limit)->get();
                foreach ($companies as $company) {
                    $rows[] = [
                        'id' => $company->id,
                        'name' => $company->name,
                        'email' => $company->email ?? '',
                        'phone' => $company->phone ?? '',
                        'address' => $company->address ?? '',
                        'city' => $company->city ?? '',
                        'state' => $company->state ?? '',
                        'zip' => $company->zip ?? '',
                        'country' => $company->country ?? '',
                        'logo' => $company->logo_url,
                        'logo_path' => $company->logo,
                    ];
                }
            }

            return response()->json([
                'success' => true,
                'companies' => $rows,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching companies: '.$e->getMessage(),
                'companies' => [],
            ], 500);
        }
    }

    /**
     * API: Get customers for dropdown (AJAX)
     */
    public function getCustomersAjax(Request $request): JsonResponse
    {
        try {
            $query = \App\Models\Customer::where('is_active', true);

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

            $customers = $query->orderBy('name', 'asc')->limit(50)->get();

            return response()->json([
                'success' => true,
                'customers' => $customers->map(function ($customer) {
                    $imageUrl = '';
                    if ($customer->image) {
                        $imageUrl = \Illuminate\Support\Facades\Storage::disk('public')->exists($customer->image)
                            ? \Illuminate\Support\Facades\Storage::disk('public')->url($customer->image)
                            : '';
                    }

                    return [
                        'id' => $customer->id,
                        'name' => $customer->name,
                        'email' => $customer->email ?? '',
                        'phone' => $customer->phone ?? '',
                        'company' => $customer->company ?? '',
                        'address' => $customer->address ?? '',
                        'city' => $customer->city ?? '',
                        'state' => $customer->state ?? '',
                        'zip' => $customer->zip ?? '',
                        'country' => $customer->country ?? '',
                        'image' => $imageUrl,
                        'image_path' => $customer->image,
                    ];
                })->toArray(),
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Error fetching customers: '.$e->getMessage(),
                'customers' => [],
            ], 500);
        }
    }

    /**
     * @return array<string, string>
     */
    private function invoiceTemplateOptions(): array
    {
        return [
            'modern' => 'Modern Corporate',
            'classic' => 'Minimal Clean',
            'minimal' => 'Business Professional',
            'bold' => 'Premium Branding',
        ];
    }
}
