<?php

namespace App\Http\Controllers;

use App\Enums\FbrInvoiceType;
use App\Enums\InvoiceSyncStatus;
use App\Exceptions\FbrApiException;
use App\Http\Requests\StoreInvoiceDraftRequest;
use App\Http\Requests\StoreInvoiceNoteDraftRequest;
use App\Jobs\SyncInvoiceToFbrJob;
use App\Models\Business;
use App\Models\Invoice;
use App\Models\Item;
use App\Services\FbrDigitalInvoiceService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Spatie\Browsershot\Browsershot;


class InvoiceController extends Controller
{
    public function __construct(protected FbrDigitalInvoiceService $fbr)
    {
    }

    /**
     * GET /api/invoices
     */
    public function index(Request $request): JsonResponse
    {
        if ($request->input('sync_status') === 'trashed' || $request->boolean('trashed')) {
            $query = Invoice::onlyTrashed()->with(['customer', 'items'])->latest();
        } else {
            $query = Invoice::query()->with(['customer', 'items'])->latest();

            if ($request->filled('sync_status')) {
                $query->where('sync_status', $request->input('sync_status'));
            }
        }

        if ($request->filled('invoice_type')) {
            $query->where('invoice_type', $request->input('invoice_type'));
        }

        if ($request->filled('customer_id')) {
            $query->where('customer_id', $request->input('customer_id'));
        }

        if ($request->filled('from_date')) {
            $query->whereDate('invoice_date', '>=', $request->input('from_date'));
        }

        if ($request->filled('to_date')) {
            $query->whereDate('invoice_date', '<=', $request->input('to_date'));
        }

        
        $perPageInput = $request->input('per_page', 25);

        if ($perPageInput === 'all') {
            $perPage = max($query->count(), 1);
        } else {
            $perPage = (int) $perPageInput ?: 25;
        }

        return response()->json($query->paginate($perPage));
    }

    /**
     * GET /invoices/metrics
     */
    public function metrics(Request $request): JsonResponse
    {
        $query = Invoice::query();

        if ($request->filled('invoice_type')) {
            $query->where('invoice_type', $request->input('invoice_type'));
        }

        if ($request->filled('customer_id')) {
            $query->where('customer_id', $request->input('customer_id'));
        }

        if ($request->filled('from_date')) {
            $query->whereDate('invoice_date', '>=', $request->input('from_date'));
        }

        if ($request->filled('to_date')) {
            $query->whereDate('invoice_date', '<=', $request->input('to_date'));
        }

        $counts = $query->selectRaw('sync_status, count(*) as count')
            ->groupBy('sync_status')
            ->pluck('count', 'sync_status');

        $synced = (int) ($counts['synced'] ?? 0);
        $drafts = (int) ($counts['draft'] ?? 0);
        $failed = (int) ($counts['failed'] ?? 0);
        $queued = (int) ($counts['queued'] ?? 0);
        $syncing = (int) ($counts['syncing'] ?? 0);

        $trashedQuery = Invoice::onlyTrashed();
        if ($request->filled('invoice_type')) {
            $trashedQuery->where('invoice_type', $request->input('invoice_type'));
        }
        if ($request->filled('customer_id')) {
            $trashedQuery->where('customer_id', $request->input('customer_id'));
        }
        if ($request->filled('from_date')) {
            $trashedQuery->whereDate('invoice_date', '>=', $request->input('from_date'));
        }
        if ($request->filled('to_date')) {
            $trashedQuery->whereDate('invoice_date', '<=', $request->input('to_date'));
        }
        $trashed = $trashedQuery->count();

        return response()->json([
            'synced' => $synced,
            'drafts' => $drafts,
            'failed' => $failed,
            'queued' => $queued,
            'syncing' => $syncing,
            'trashed' => $trashed,
            'total'  => $synced + $drafts + $failed + $queued + $syncing,
        ]);
    }



    public function page()
    {
        return view('invoices.index');
    }

    public function create()
    {
        return view('invoices.create');
    }

    public function edit(Invoice $invoice)
    {
        if ($invoice->isSynced()) {
            return redirect()->route('invoices.index')
                ->with('error', 'Synced invoices cannot be edited.');
        }

        $invoice->load(['customer', 'items']);
        return view('invoices.edit', compact('invoice'));
    }

    /**
     * GET /invoices/{invoice}
     */
    public function show(Request $request, Invoice $invoice)
    {
        $invoice->load(['customer', 'items.item', 'originalInvoice', 'notes', 'fbrLogs' => fn($q) => $q->latest()]);

        if ($request->wantsJson()) {
            return response()->json(['data' => $invoice]);
        }

        return view('invoices.show', compact('invoice'));
    }

    /**
     * POST /api/invoices
     * Create a Sale Invoice as a Draft. Optionally sync immediately
     * (synchronously) or queue it for background sync.
     */
    public function store(StoreInvoiceDraftRequest $request): JsonResponse
    {
        $business = Business::current();
        if ($business) {
            $currentInvoicesCount = Invoice::where('business_id', $business->id)->count();
            if (!$business->checkLimit('max_invoices', $currentInvoicesCount)) {
                return response()->json([
                    'success' => false,
                    'message' => 'Invoices limit reached for your subscription plan.'
                ], 422);
            }
        }

        $invoice = DB::transaction(function () use ($request) {
            $invoice = Invoice::create([
                'customer_id' => $request->input('customer_id'),
                'local_invoice_no' => $request->input('local_invoice_no'),
                'invoice_type' => FbrInvoiceType::SaleInvoice,
                'invoice_date' => $request->input('invoice_date'),
                'scenario_id' => $request->input('scenario_id'),
                'notes' => $request->input('notes'),
            ]);

            $this->attachItems($invoice, $request->input('items'));
            $invoice->recalculateTotals();
            $invoice->save();

            return $invoice;
        });

        return $this->respondAfterDraftCreate($invoice, $request);
    }

    /**
     * POST /api/invoices/{originalInvoice}/debit-note
     */
    public function storeDebitNote(StoreInvoiceNoteDraftRequest $request): JsonResponse
    {
        return $this->storeNote($request, FbrInvoiceType::DebitNote);
    }

    /**
     * POST /api/invoices/{originalInvoice}/credit-note
     */
    public function storeCreditNote(StoreInvoiceNoteDraftRequest $request): JsonResponse
    {
        return $this->storeNote($request, FbrInvoiceType::CreditNote);
    }

    protected function storeNote(StoreInvoiceNoteDraftRequest $request, FbrInvoiceType $type): JsonResponse
    {
        $original = Invoice::findOrFail($request->input('original_invoice_id'));

        // Credit Note value must not exceed the original invoice's value —
        // app-level pre-check mirroring FBR error 0036, before we even call out.
        if ($type === FbrInvoiceType::CreditNote) {
            $noteTotal = collect($request->input('items'))->sum(fn($i) => (float) ($i['value_sales_excluding_st'] ?? 0));
            if ($noteTotal > (float) $original->subtotal) {
                throw new FbrApiException(
                    'Credit Note value cannot exceed the original invoice value.',
                    fbrErrorCode: '0036',
                    code: 422,
                );
            }
        }

        // Only one Credit Note allowed per original invoice (FBR error 0064).
        if ($type === FbrInvoiceType::CreditNote && $original->notes()->where('invoice_type', FbrInvoiceType::CreditNote)->exists()) {
            throw new FbrApiException(
                'A Credit Note has already been issued for this invoice.',
                fbrErrorCode: '0064',
                code: 422,
            );
        }

        $invoice = DB::transaction(function () use ($request, $type, $original) {
            $invoice = Invoice::create([
                'customer_id' => $original->customer_id,
                'invoice_type' => $type,
                'invoice_date' => $request->input('invoice_date'),
                'original_invoice_id' => $original->id,
                'scenario_id' => $request->input('scenario_id'),
                'notes' => $request->input('notes'),
            ]);

            $this->attachItems($invoice, $request->input('items'));
            $invoice->recalculateTotals();
            $invoice->save();

            return $invoice;
        });

        return $this->respondAfterDraftCreate($invoice, $request);
    }

    protected function respondAfterDraftCreate(Invoice $invoice, Request $request): JsonResponse
    {
        if ($request->boolean('sync_immediately')) {
            try {
                $this->fbr->syncInvoice($invoice->refresh());

                return response()->json(['success' => true, 'data' => $invoice->fresh(['items'])], 201);
            } catch (FbrApiException $e) {
                // Draft is saved either way — return 201 with the error attached,
                // since the local record exists and the user can retry the sync.
                return response()->json([
                    'success' => false,
                    'data' => $invoice->fresh(['items']),
                    'sync_error' => $e->getMessage(),
                    'fbr_error_code' => $e->fbrErrorCode,
                ], 201);
            }
        }

        $business = Business::withoutGlobalScopes()->find($invoice->business_id);
        if ($business?->auto_sync_enabled) {
            $this->queueForSync($invoice);
        }

        return response()->json(['success' => true, 'data' => $invoice->fresh(['items'])], 201);
    }

    /**
     * PUT /api/invoices/{invoice}
     * Edit a draft. Blocked once synced — corrections beyond that point
     * must go through a Debit/Credit Note.
     */
    public function update(StoreInvoiceDraftRequest $request, Invoice $invoice): JsonResponse
    {
        if (!$invoice->canEdit()) {
            throw new FbrApiException(
                "Invoice {$invoice->local_invoice_no} is {$invoice->sync_status->label()} and can no longer be edited directly. " .
                'File a Debit/Credit Note instead.',
                code: 409,
            );
        }

        DB::transaction(function () use ($request, $invoice) {
            $invoice->update([
                'customer_id' => $request->input('customer_id'),
                'local_invoice_no' => $request->input('local_invoice_no'),
                'invoice_date' => $request->input('invoice_date'),
                'scenario_id' => $request->input('scenario_id'),
                'notes' => $request->input('notes'),
            ]);

            $invoice->items()->delete();
            $this->attachItems($invoice, $request->input('items'));
            $invoice->recalculateTotals();
            $invoice->save();
        });

        return $this->respondAfterDraftCreate($invoice->fresh(), $request);
    }

    /**
     * DELETE /api/invoices/{id}
     * Soft delete or force delete based on force parameter or current trashed state.
     */
    public function destroy(Request $request, int|string $id): JsonResponse
    {
        $invoice = Invoice::withTrashed()->findOrFail($id);

        if ($invoice->isSynced() && !$invoice->trashed()) {
            throw new FbrApiException(
                'Synced invoices cannot be deleted — they exist on FBR\'s record. File a Credit Note to reverse it instead.',
                code: 409,
            );
        }

        if ($request->boolean('force') || $invoice->trashed()) {
            $invoice->items()->delete();
            $invoice->forceDelete();
            return response()->json(['success' => true, 'message' => 'Invoice permanently deleted.']);
        } else {
            $invoice->delete();
            return response()->json(['success' => true, 'message' => 'Invoice moved to trash.']);
        }
    }

    /**
     * POST /api/invoices/{id}/restore
     * Restore a soft-deleted invoice from trash.
     */
    public function restore(int|string $id): JsonResponse
    {
        $invoice = Invoice::onlyTrashed()->findOrFail($id);
        $invoice->restore();

        return response()->json(['success' => true, 'message' => 'Invoice restored successfully.']);
    }


    /**
     * POST /api/invoices/{invoice}/sync
     * Manual "Sync Now" — synchronous call, returns the FBR result immediately.
     */
    public function syncNow(Invoice $invoice): JsonResponse
    {
        try {
            $synced = $this->fbr->syncInvoice($invoice);

            return response()->json(['success' => true, 'data' => $synced]);
        } catch (FbrApiException $e) {
            return $e->render();
        }
    }

    /**
     * POST /api/invoices/{invoice}/queue-sync
     * Push onto the background queue instead of blocking the request.
     * Useful for bulk "sync all drafts" actions from the UI.
     */
    public function queueSync(Invoice $invoice): JsonResponse
    {
        if (!$invoice->canQueueForSync()) {
            throw new FbrApiException(
                "Invoice {$invoice->local_invoice_no} cannot be queued from its current state ({$invoice->sync_status->value}).",
                code: 409,
            );
        }

        $this->queueForSync($invoice);

        return response()->json(['success' => true, 'message' => 'Invoice queued for background sync.']);
    }

    /**
     * POST /api/invoices/bulk-queue-sync
     * Queue every Draft/Failed invoice for the current business at once.
     */
    public function bulkQueueSync(Request $request): JsonResponse
    {
        $invoices = Invoice::query()
            ->whereIn('sync_status', [InvoiceSyncStatus::Draft, InvoiceSyncStatus::Failed])
            ->get();

        foreach ($invoices as $invoice) {
            $this->queueForSync($invoice);
        }

        return response()->json([
            'success' => true,
            'queued_count' => $invoices->count(),
        ]);
    }

    /**
     * POST /api/invoices/{invoice}/validate
     * Dry-run check against FBR without affecting sync_status.
     */
    public function validateNow(Invoice $invoice): JsonResponse
    {
        try {
            $result = $this->fbr->validateStoredInvoice($invoice);

            return response()->json(['success' => true, 'data' => $result]);
        } catch (FbrApiException $e) {
            return $e->render();
        }
    }

    protected function queueForSync(Invoice $invoice): void
    {
        $invoice->forceFill(['sync_status' => InvoiceSyncStatus::Queued])->save();
        SyncInvoiceToFbrJob::dispatch($invoice->id);
    }

    /**
     * Builds InvoiceItem rows from request data, resolving Item master
     * defaults when item_id is given and letting explicit fields override.
     */
    protected function attachItems(Invoice $invoice, array $items): void
    {
        foreach ($items as $row) {
            $defaults = [];

            if (!empty($row['item_id'])) {
                $item = Item::find($row['item_id']);
                if ($item) {
                    $defaults = $item->toInvoiceItemDefaults((float) ($row['quantity'] ?? 1));
                }
            }

            $invoice->items()->create([
                'item_id' => $row['item_id'] ?? null,
                'hs_code' => $row['hs_code'] ?? $defaults['hs_code'] ?? null,
                'product_description' => $row['product_description'] ?? $defaults['product_description'] ?? null,
                'rate' => $row['rate'] ?? $defaults['rate'] ?? null,
                'uom' => $row['uom'] ?? $defaults['uom'] ?? null,
                'quantity' => $row['quantity'],
                'total_values' => $row['total_values'] ?? 0,
                'value_sales_excluding_st' => $row['value_sales_excluding_st'] ?? $defaults['value_sales_excluding_st'] ?? 0,
                'fixed_notified_value_or_retail_price' => $row['fixed_notified_value_or_retail_price'] ?? 0,
                'sales_tax_applicable' => $row['sales_tax_applicable'] ?? 0,
                'sales_tax_withheld_at_source' => $row['sales_tax_withheld_at_source'] ?? 0,
                'extra_tax' => $row['extra_tax'] ?? 0,
                'further_tax' => $row['further_tax'] ?? 0,
                'sro_schedule_no' => $row['sro_schedule_no'] ?? $defaults['sro_schedule_no'] ?? null,
                'fed_payable' => $row['fed_payable'] ?? 0,
                'discount' => $row['discount'] ?? 0,
                'discount_type' => $row['discount_type'] ?? 'fixed',
                'discount_value' => $row['discount_value'] ?? 0,
                'sale_type' => $row['sale_type'] ?? $defaults['sale_type'] ?? null,
                'sro_item_serial_no' => $row['sro_item_serial_no'] ?? $defaults['sro_item_serial_no'] ?? null,
            ]);
        }
    }

    public function downloadPdf(Request $request)
    {
        $id = $request->input('id');
        $invoice = Invoice::with(['customer', 'items.item', 'business'])->findOrFail($id);

        $layoutData = \App\Helpers\InvoicePdfHelper::getLayoutData($invoice);
        $html = view('invoices.invoice_pdf', compact('invoice', 'layoutData'))->render();

        $pdf = \App\Helpers\InvoicePdfHelper::makeBrowsershot($html)
            ->format('A4')
            ->showBackground()
            ->margins(0, 0, 0, 0)
            ->pdf();

        return response($pdf, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => "inline; filename=\"invoice-{$invoice->local_invoice_no}.pdf\"",
        ]);
    }

    public function emailPreview(Invoice $invoice): JsonResponse
    {
        $invoice->load(['customer', 'business']);

        $email = $invoice->customer->email ?? '';
        $subject = "Invoice #{$invoice->local_invoice_no} from " . ($invoice->business->name ?? 'Digital Invoicing');
        $body = "Please find attached your invoice (#{$invoice->local_invoice_no}) for your recent purchase. If you have any questions, feel free to reply to this email.";

        return response()->json([
            'recipient' => $email,
            'subject' => $subject,
            'body' => $body,
            'filename' => "invoice-{$invoice->local_invoice_no}.pdf"
        ]);
    }

    public function sendEmail(Request $request, Invoice $invoice): JsonResponse
    {
        $invoice->load(['customer', 'business']);

        $email = $invoice->customer->email ?? '';
        if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return response()->json([
                'success' => false,
                'message' => 'Customer does not have a valid email address configured.'
            ], 422);
        }

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

        try {
            \Illuminate\Support\Facades\Mail::to($email)->send(
                new \App\Mail\SendInvoiceMail(
                    $invoice,
                    $request->input('subject'),
                    $request->input('body')
                )
            );
            return response()->json([
                'success' => true,
                'message' => "Invoice PDF emailed successfully to {$email}."
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send email: ' . $e->getMessage()
            ], 500);
        }
    }

    public function fbrLogsPage()
    {
        return view('fbr-logs.index');
    }

    public function fbrLogsData(Request $request): JsonResponse
    {
        $query = \App\Models\FbrInvoiceLog::query()
            ->with(['business'])
            ->latest();

        if ($request->filled('status')) {
            $query->where('status', $request->input('status'));
        }

        if ($request->filled('action')) {
            $query->where('action', $request->input('action'));
        }

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

        return response()->json($query->paginate($request->integer('per_page', 25)));
    }

    public function bulkDelete(Request $request): JsonResponse
    {
        $ids = $request->input('ids', []);
        $force = $request->boolean('force');

        $invoices = Invoice::withTrashed()->whereIn('id', $ids)->get();

        $deleted = 0;
        $failed = 0;

        foreach ($invoices as $invoice) {
            if ($invoice->isSynced() && !$invoice->trashed()) {
                $failed++;
            } else {
                if ($force || $invoice->trashed()) {
                    $invoice->items()->delete();
                    $invoice->forceDelete();
                } else {
                    $invoice->delete();
                }
                $deleted++;
            }
        }

        $typeMsg = ($force) ? "permanently deleted" : "moved to trash";

        return response()->json([
            'success' => true,
            'message' => "Successfully {$typeMsg} {$deleted} invoice(s)." . ($failed > 0 ? " {$failed} synced invoices could not be deleted." : "")
        ]);
    }

    public function bulkSync(Request $request): JsonResponse
    {
        $ids = $request->input('ids', []);

        $invoices = Invoice::whereIn('id', $ids)->get();

        $queued = 0;
        foreach ($invoices as $invoice) {
            if ($invoice->canQueueForSync()) {
                $invoice->update(['sync_status' => InvoiceSyncStatus::Queued]);
                SyncInvoiceToFbrJob::dispatch($invoice->id);
                $queued++;
            }
        }

        return response()->json([
            'success' => true,
            'message' => "Queued {$queued} invoices for FBR synchronization."
        ]);
    }

    public function bulkPdf(Request $request)
    {
        $ids = explode(',', $request->input('ids', ''));
        $invoices = Invoice::with(['customer', 'items.item', 'business'])->whereIn('id', $ids)->get();

        if ($invoices->isEmpty()) {
            abort(404, 'No invoices selected.');
        }

        $invoicesLayoutData = [];
        foreach ($invoices as $invoice) {
            $invoicesLayoutData[$invoice->id] = \App\Helpers\InvoicePdfHelper::getLayoutData($invoice);
        }

        $html = view('invoices.invoice_pdf', compact('invoices', 'invoicesLayoutData'))->render();

        $pdf = \App\Helpers\InvoicePdfHelper::makeBrowsershot($html)
            ->format('A4')
            ->showBackground()
            ->margins(0, 0, 0, 0)
            ->pdf();

        return response($pdf, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="invoices_combined.pdf"',
        ]);
    }

    public function scheduleSync(Request $request, Invoice $invoice): JsonResponse
    {
        $request->validate([
            'scheduled_sync_at' => ['nullable', 'date', 'after:now'],
        ]);

        $invoice->update([
            'scheduled_sync_at' => $request->input('scheduled_sync_at'),
        ]);

        return response()->json([
            'success' => true,
            'message' => $invoice->scheduled_sync_at
                ? "Invoice scheduled to sync at " . $invoice->scheduled_sync_at->format('Y-m-d H:i:s')
                : "Invoice sync schedule removed.",
            'data' => $invoice->fresh()
        ]);
    }

    /**
     * Export invoices to CSV/Excel format.
     */
    // public function exportExcel(Request $request)
    // {
    //     if ($request->input('sync_status') === 'trashed') {
    //         $query = Invoice::onlyTrashed()->with(['customer', 'items'])->latest();
    //     } else {
    //         $query = Invoice::query()->with(['customer', 'items'])->latest();
    //     }

    //     if ($request->filled('ids')) {
    //         $ids = explode(',', $request->input('ids'));
    //         $query->whereIn('id', $ids);
    //     } else {
    //         if ($request->filled('sync_status') && $request->input('sync_status') !== 'trashed') {
    //             $query->where('sync_status', $request->input('sync_status'));
    //         }
    //         if ($request->filled('invoice_type')) {
    //             $typeMap = [
    //                 '1' => FbrInvoiceType::SaleInvoice,
    //                 '2' => FbrInvoiceType::DebitNote,
    //                 '3' => FbrInvoiceType::CreditNote,
    //             ];
    //             $typeInput = $request->input('invoice_type');
    //             if (isset($typeMap[$typeInput])) {
    //                 $query->where('invoice_type', $typeMap[$typeInput]);
    //             } else {
    //                 $query->where('invoice_type', $typeInput);
    //             }
    //         }
    //         if ($request->filled('date_range')) {
    //             $dates = explode(' to ', $request->input('date_range'));
    //             if (count($dates) === 2) {
    //                 $query->whereBetween('invoice_date', [$dates[0], $dates[1]]);
    //             } elseif (count($dates) === 1) {
    //                 $query->whereDate('invoice_date', $dates[0]);
    //             }
    //         }
    //     }

    //     $invoices = $query->get();

    //     $headers = [
    //         'Content-Type' => 'text/csv',
    //         'Content-Disposition' => 'attachment; filename="invoices_' . now()->format('Y-m-d_H-i-s') . '.csv"',
    //         'Pragma' => 'no-cache',
    //         'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
    //         'Expires' => '0'
    //     ];

    //     $qtyPrecision = (int) \App\Models\Setting::get('quantity_precision', 2);
    //     $currPrecision = (int) \App\Models\Setting::get('currency_precision', 2);

    //     $callback = function () use ($invoices, $qtyPrecision, $currPrecision) {
    //         $file = fopen('php://output', 'w');
    //         fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF)); // UTF-8 BOM for Excel

    //         fputcsv($file, [
    //             'Invoice No',
    //             'Invoice Date',
    //             'Customer Name',
    //             'Customer NTN/CNIC',
    //             'Invoice Type',
    //             'FBR Invoice ID',
    //             'Sync Status',
    //             'Total Quantity',
    //             'Subtotal (Excl. Tax)',
    //             'Item Discount',
    //             'Sales Tax',
    //             'Further Tax',
    //             'Advance Tax',
    //             'Total Tax',
    //             'Total Amount'
    //         ]);

    //         foreach ($invoices as $inv) {
    //             $totalQty = (float) $inv->items->sum('quantity');
    //             $salesTax = (float) $inv->items->sum('sales_tax_applicable');
    //             $furtherTax = (float) $inv->items->sum('further_tax');
    //             $advanceTax = (float) $inv->items->sum('extra_tax');
    //             $discount = (float) $inv->items->sum('discount');

    //             fputcsv($file, [
    //                 $inv->local_invoice_no,
    //                 $inv->invoice_date,
    //                 $inv->customer?->name ?? 'Walk-in Customer',
    //                 $inv->customer?->ntn_cnic ?? '—',
    //                 $inv->invoice_type->value ?? $inv->invoice_type,
    //                 $inv->fbr_invoice_number ?? '—',
    //                 $inv->sync_status->value ?? $inv->sync_status,
    //                 number_format($totalQty, $qtyPrecision, '.', ''),
    //                 number_format($inv->subtotal, $currPrecision, '.', ''),
    //                 number_format($discount, $currPrecision, '.', ''),
    //                 number_format($salesTax, $currPrecision, '.', ''),
    //                 number_format($furtherTax, $currPrecision, '.', ''),
    //                 number_format($advanceTax, $currPrecision, '.', ''),
    //                 number_format($inv->total_tax, $currPrecision, '.', ''),
    //                 number_format($inv->total_amount, $currPrecision, '.', '')
    //             ]);
    //         }

    //         fclose($file);
    //     };

    //     return response()->stream($callback, 200, $headers);
    // }
    
    
    /**
 * Export invoices to CSV/Excel format.
 */
public function exportExcel(Request $request)
{
    if ($request->input('sync_status') === 'trashed') {
        $query = Invoice::onlyTrashed()->with(['customer', 'items'])->latest();
    } else {
        $query = Invoice::query()->with(['customer', 'items'])->latest();
    }

    if ($request->filled('ids')) {
        $ids = explode(',', $request->input('ids'));
        $query->whereIn('id', $ids);
    } else {
        if ($request->filled('sync_status') && $request->input('sync_status') !== 'trashed') {
            $query->where('sync_status', $request->input('sync_status'));
        }
        if ($request->filled('invoice_type')) {
            $typeMap = [
                '1' => FbrInvoiceType::SaleInvoice,
                '2' => FbrInvoiceType::DebitNote,
                '3' => FbrInvoiceType::CreditNote,
            ];
            $typeInput = $request->input('invoice_type');
            if (isset($typeMap[$typeInput])) {
                $query->where('invoice_type', $typeMap[$typeInput]);
            } else {
                $query->where('invoice_type', $typeInput);
            }
        }
        if ($request->filled('date_range')) {
            $dates = explode(' to ', $request->input('date_range'));
            if (count($dates) === 2) {
                $query->whereBetween('invoice_date', [$dates[0], $dates[1]]);
            } elseif (count($dates) === 1) {
                $query->whereDate('invoice_date', $dates[0]);
            }
        }
    }

    $invoices = $query->get();

    $headers = [
        'Content-Type' => 'text/csv',
        'Content-Disposition' => 'attachment; filename="invoices_' . now()->format('Y-m-d_H-i-s') . '.csv"',
        'Pragma' => 'no-cache',
        'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
        'Expires' => '0'
    ];

    $qtyPrecision = (int) \App\Models\Setting::get('quantity_precision', 2);
    $currPrecision = (int) \App\Models\Setting::get('currency_precision', 2);

    $callback = function () use ($invoices, $qtyPrecision, $currPrecision) {
        $file = fopen('php://output', 'w');
        fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF)); // UTF-8 BOM for Excel

        fputcsv($file, [
            'Invoice No',
            'Invoice Date',
            'Customer Name',
            'Customer NTN/CNIC',
            'HS Code',
            'HS Code Description',
            'Invoice Type',
            'FBR Invoice ID',
            'Sync Status',
            'Total Quantity',
            'Subtotal (Excl. Tax)',
            'Item Discount',
            'Sales Tax',
            'Further Tax',
            'Advance Tax',
            'Total Tax',
            'Total Amount'
        ]);

        foreach ($invoices as $inv) {
            $totalQty = (float) $inv->items->sum('quantity');
            $salesTax = (float) $inv->items->sum('sales_tax_applicable');
            $furtherTax = (float) $inv->items->sum('further_tax');
            $advanceTax = (float) $inv->items->sum('extra_tax');
            $discount = (float) $inv->items->sum('discount');

            $hsCodes = $inv->items->pluck('hs_code')->filter()->unique()->implode(', ');
            $hsDescriptions = $inv->items->pluck('product_description')->filter()->unique()->implode(' | ');

            fputcsv($file, [
                $inv->local_invoice_no,
                $inv->invoice_date,
                $inv->customer?->name ?? 'Walk-in Customer',
                $inv->customer?->ntn_cnic ?? '—',
                $hsCodes ?: '—',
                $hsDescriptions ?: '—',
                $inv->invoice_type->value ?? $inv->invoice_type,
                $inv->fbr_invoice_number ?? '—',
                $inv->sync_status->value ?? $inv->sync_status,
                number_format($totalQty, $qtyPrecision, '.', ''),
                number_format($inv->subtotal, $currPrecision, '.', ''),
                number_format($discount, $currPrecision, '.', ''),
                number_format($salesTax, $currPrecision, '.', ''),
                number_format($furtherTax, $currPrecision, '.', ''),
                number_format($advanceTax, $currPrecision, '.', ''),
                number_format($inv->total_tax, $currPrecision, '.', ''),
                number_format($inv->total_amount, $currPrecision, '.', '')
            ]);
        }

        fclose($file);
    };

    return response()->stream($callback, 200, $headers);
}
}
