<?php

namespace App\Http\Controllers;

use App\Models\SalesReceipt;
use App\Models\SalesReceiptItem;
use App\Models\SalesReceiptReversal;
use App\Models\SalesReceiptReversalItem;
use App\Models\Customer;
use App\Models\Account;
use App\Models\Product;
use App\Models\JournalEntry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class SalesReceiptController extends Controller
{
    /**
     * Display a listing of sales receipts for the current company.
     */
    public function index()
    {
        $receipts = SalesReceipt::with(['customer', 'bankAccount', 'reversals'])
            ->where('company_id', Auth::user()->current_company_id)
            ->orderBy('transaction_date', 'desc')
            ->paginate(15);

        return view('sales-receipts.index', compact('receipts'));
    }

    /**
     * Show the form for creating a new sales receipt.
     */
    public function create()
    {
        $companyId = Auth::user()->current_company_id;

        // Fetch active customers
        $customers = Customer::where('company_id', $companyId)
            ->where('status', 'active')
            ->get();

        // Fetch Receipting Accounts: Only types Bank (1), Cash (2), and Mobile Money (16)
        $receiptingAccounts = Account::where('company_id', $companyId)
            ->whereIn('account_type_id', [1, 2, 16]) 
            ->where('is_active', true)
            ->get();

        // Fetch products to populate the items table
        $products = Product::where('company_id', $companyId)->get();

        // Generate the next receipt number
        $lastReceipt = SalesReceipt::where('company_id', $companyId)->latest()->first();
        $receiptNo = $lastReceipt ? $lastReceipt->id + 1001 : 1001;

        return view('sales-receipts.create', compact('customers', 'receiptingAccounts', 'products', 'receiptNo'));
    }

    /**
     * Store a newly created sales receipt and post double-entries to the ledger.
     */
    public function store(Request $request)
    {
        $request->validate([
            'customer_id' => 'required|exists:customers,id',
            'transaction_date' => 'required|date',
            'cash_bank_account_id' => 'required|exists:accounts,id',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.qty' => 'required|numeric|min:0.01',
            'items.*.rate' => 'required|numeric|min:0',
        ]);

        return DB::transaction(function () use ($request) {
            $companyId = Auth::user()->current_company_id;
            $userId = Auth::id();

            // Calculate total amount from all line items
            $totalAmount = collect($request->items)->sum(function($item) {
                return $item['qty'] * $item['rate'];
            });

            // Get account to determine payment method
            $account = Account::find($request->cash_bank_account_id);
            
            // Determine payment method based on account type
            $paymentMethod = $request->payment_method;
            if (empty($paymentMethod)) {
                switch ($account->account_type_id) {
                    case 1: // Bank
                        $paymentMethod = 'Bank Transfer';
                        break;
                    case 2: // Cash
                        $paymentMethod = 'Cash';
                        break;
                    case 16: // Mobile Money
                        $paymentMethod = 'Mobile Money';
                        break;
                    default:
                        $paymentMethod = 'Other';
                }
            }

            // 1. Create the Sales Receipt Header
            $receipt = SalesReceipt::create([
                'company_id' => $companyId,
                'customer_id' => $request->customer_id,
                'receipt_no' => $request->receipt_no,
                'transaction_date' => $request->transaction_date,
                'cash_bank_account_id' => $request->cash_bank_account_id,
                'amount' => $totalAmount,
                'remaining_amount' => $totalAmount,
                'total_reversed_amount' => 0,
                'payment_method' => $paymentMethod,
                'reference_no' => $request->reference_no,
                'billing_address' => $request->billing_address,
                'memo' => $request->memo,
                'status' => SalesReceipt::STATUS_CLEARED,
                'created_by' => $userId,
                'is_reversed' => false,
            ]);

            // 2. Process Line Items and individual Revenue Credits
            foreach ($request->items as $itemData) {
                $product = Product::findOrFail($itemData['product_id']);
                $lineTotal = $itemData['qty'] * $itemData['rate'];

                // Save line item to database
                SalesReceiptItem::create([
                    'sales_receipt_id' => $receipt->id,
                    'product_id' => $product->id,
                    'income_account_id' => $product->income_account_id,
                    'description' => $itemData['description'] ?? $product->name,
                    'qty' => $itemData['qty'],
                    'rate' => $itemData['rate'],
                    'amount' => $lineTotal,
                ]);
                
                

                // CR (Credit) the Income Account for this specific product line
                $this->postJournalEntry(
                    $receipt,
                    $product->income_account_id,
                    0,               // Debit
                    $lineTotal,      // Credit
                    $itemData['description'] ?? $product->name
                );
            }

            // 3. DR (Debit) the Bank/Cash Account for the Grand Total
            $this->postJournalEntry(
                $receipt,
                $request->cash_bank_account_id,
                $totalAmount,    // Debit
                0,               // Credit
                "Total deposit for Receipt #" . $receipt->receipt_no
            );
            
            
            // Post to Cashbook
            \App\Models\Cashbook::create([
                'company_id'               => $companyId,
                'customer_id'              => $request->customer_id,
                'sales_receipt_id'         => $receipt->id, // Linked to the new receipt
                'cash_bank_account_id'     => $request->cash_bank_account_id,
                'corresponding_account_id' => $request->cash_bank_account_id, 
                'reference'                => $receipt->receipt_no,
                'memo'                     => $request->memo ?? "Sales Receipt Payment",
                'payment_method'           => $paymentMethod,
                'debit'                    => $totalAmount,
                'credit'                   => 0,
                'transaction_date'         => $request->transaction_date,
                'status'                   => 'cleared',
                'created_by'               => $userId,
            ]);

            return redirect()->route('sales-receipts.index')
                ->with('success', "Sales Receipt #{$receipt->receipt_no} has been posted successfully.");
        });
    }

    /**
     * Display the specified sales receipt.
     */
    public function show($id)
    {
        $receipt = SalesReceipt::with(['customer', 'bankAccount', 'items.product', 'reversals', 'reversedBy'])
            ->where('company_id', Auth::user()->current_company_id)
            ->findOrFail($id);
        
        return view('sales-receipts.show', compact('receipt'));
    }

    /**
     * Show the reversal confirmation form for a sales receipt.
     */
    public function reverseForm($id)
    {
        $receipt = SalesReceipt::with(['customer', 'items.product', 'bankAccount', 'reversals'])
            ->where('company_id', Auth::user()->current_company_id)
            ->findOrFail($id);

        // Check if receipt can be reversed
        if (!$receipt->canBeReversed()) {
            return redirect()->route('sales-receipts.index')
                ->with('error', 'This receipt cannot be reversed. Current status: ' . $receipt->getStatusText());
        }

        // Fetch credit note reasons
        $creditNoteReasons = DB::table('credit_note_reasons')
            ->orderBy('sort_order')
            ->get();

        return view('sales-receipts.reverse', compact('receipt', 'creditNoteReasons'));
    }

    /**
     * Process the reversal of a sales receipt.
     */
    public function reverse(Request $request, $id)
    {
        $request->validate([
            'reversal_date' => 'required|date',
            'reversal_reason' => 'required|string|max:500',
            'reference_no' => 'nullable|string|max:255',
            'items' => 'required|array',
            'items.*.reversal_qty' => 'required|numeric|min:0',
            'items.*.reversal_rate' => 'required|numeric|min:0',
            'items.*.reversal_amount' => 'required|numeric|min:0',
            'items.*.original_item_id' => 'required|exists:sales_receipt_items,id',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.income_account_id' => 'required|exists:accounts,id',
        ]);

        return DB::transaction(function () use ($request, $id) {
            $receipt = SalesReceipt::with(['customer', 'items', 'reversals'])
                ->where('company_id', Auth::user()->current_company_id)
                ->findOrFail($id);

            // Check if receipt can be reversed
            if (!$receipt->canBeReversed()) {
                throw new \Exception('This receipt cannot be reversed. Current status: ' . $receipt->getStatusText());
            }

            $userId = Auth::id();
            $companyId = Auth::user()->current_company_id;
            
            // Calculate total reversal amount from items
            $totalReversalAmount = collect($request->items)->sum('reversal_amount');
            
            // Validate that reversal amount doesn't exceed remaining amount
            if ($totalReversalAmount <= 0) {
                throw new \Exception('Reversal amount must be greater than zero.');
            }
            
            if ($totalReversalAmount > $receipt->remaining_amount) {
                throw new \Exception('Reversal amount (ZMW ' . number_format($totalReversalAmount, 2) . 
                    ') exceeds remaining balance (ZMW ' . number_format($receipt->remaining_amount, 2) . ').');
            }
            
            // Generate reversal number
            $lastReversal = SalesReceiptReversal::where('company_id', $companyId)
                ->latest()
                ->first();
            $reversalNo = $lastReversal ? 'REV-' . ($lastReversal->id + 1001) : 'REV-1001';
            
            // Create reversal record - always use 'completed' for successful reversals
            $reversal = SalesReceiptReversal::create([
                'company_id' => $companyId,
                'original_sales_receipt_id' => $receipt->id,
                'customer_id' => $receipt->customer_id,
                'reversal_no' => $reversalNo,
                'reversal_date' => $request->reversal_date,
                'reversal_reason' => $request->reversal_reason,
                'reversed_by' => $userId,
                'original_amount' => $receipt->amount,
                'reversal_amount' => $totalReversalAmount,
                'status' => SalesReceiptReversal::STATUS_COMPLETED,
                'reference_no' => $request->reference_no,
                'notes' => $request->notes ?? null,
            ]);
            
            // Create reversal items
            foreach ($request->items as $itemData) {
                // Skip items with zero reversal amount
                if ($itemData['reversal_amount'] <= 0) {
                    continue;
                }
                
                $originalItem = SalesReceiptItem::findOrFail($itemData['original_item_id']);
                
                // Validate reversal quantity doesn't exceed original
                if ($itemData['reversal_qty'] > $originalItem->qty) {
                    throw new \Exception('Reversal quantity cannot exceed original quantity for item: ' . $originalItem->description);
                }
                
                SalesReceiptReversalItem::create([
                    'sales_receipt_reversal_id' => $reversal->id,
                    'original_sales_receipt_item_id' => $originalItem->id,
                    'product_id' => $itemData['product_id'],
                    'income_account_id' => $itemData['income_account_id'],
                    'expense_account_id' => $originalItem->expense_account_id ?? null,
                    'asset_account_id' => $originalItem->asset_account_id ?? null,
                    'description' => $itemData['description'] ?? $originalItem->description,
                    'original_qty' => $originalItem->qty,
                    'original_rate' => $originalItem->rate,
                    'original_amount' => $originalItem->amount,
                    'reversal_qty' => $itemData['reversal_qty'],
                    'reversal_rate' => $itemData['reversal_rate'],
                    'reversal_amount' => $itemData['reversal_amount'],
                    'tax_amount' => $originalItem->tax_amount ?? 0,
                    'reversal_reason' => $request->reversal_reason,
                ]);
            }
            
            // Create reversal journal entries
            if ($totalReversalAmount > 0) {
                // 1. CREDIT the Bank/Cash Account (reverse the original debit)
                $this->postReversalJournalEntry(
                    $receipt,
                    $receipt->cash_bank_account_id,
                    0,
                    $totalReversalAmount,
                    "REVERSAL: {$request->reversal_reason} - Original Receipt #{$receipt->receipt_no} (Reversal #{$reversalNo})",
                    $request->reversal_date
                );

                // 2. DEBIT the Income Accounts (reverse the original credits)
                foreach ($request->items as $itemData) {
                    if ($itemData['reversal_amount'] > 0) {
                        $originalItem = SalesReceiptItem::find($itemData['original_item_id']);
                        $description = "REVERSAL: {$request->reversal_reason} - Item reversal (Reversal #{$reversalNo})";
                        
                        // Add partial reversal info if applicable
                        if ($originalItem && $itemData['reversal_qty'] < $originalItem->qty) {
                            $description .= " (Partial: {$itemData['reversal_qty']}/{$originalItem->qty} units)";
                        }
                        
                        // Add rate adjustment info if rate changed
                        if ($originalItem && floatval($itemData['reversal_rate']) != floatval($originalItem->rate)) {
                            $description .= " (Rate adjusted from {$originalItem->rate} to {$itemData['reversal_rate']})";
                        }
                        
                        $this->postReversalJournalEntry(
                            $receipt,
                            $itemData['income_account_id'],
                            $itemData['reversal_amount'],
                            0,
                            $description,
                            $request->reversal_date
                        );
                    }
                }
                
                \App\Models\Cashbook::create([
                  'company_id'                => Auth::user()->current_company_id,
                  'customer_id'               => $receipt->customer_id,
                  'sales_receipt_id'          => $receipt->id,    // Original Receipt ID
                  'sales_receipt_reversal_id' => $reversal->id,   // Reversal ID
                  'cash_bank_account_id'      => $receipt->cash_bank_account_id,
                  'corresponding_account_id'  => $receipt->cash_bank_account_id,
                  'reference'                 => $reversal->reversal_no,
                  'memo'                      => "Reversal of Receipt #" . $receipt->receipt_no,
                  'payment_method'            => $receipt->payment_method,
                  'debit'                     => 0,
                  'credit'                    => $totalReversalAmount, // Money going out
                  'transaction_date'          => $request->reversal_date,
                  'status'                    => 'cleared',
                  'reversal_reason'           => $request->reversal_reason,
                  'created_by'                => Auth::id(),
               ]);
                
                
            }

            // Update the receipt with new balances
            $newTotalReversed = $receipt->total_reversed_amount + $totalReversalAmount;
            $newRemainingAmount = $receipt->amount - $newTotalReversed;
            
            // Determine new status for parent receipt
            $newStatus = SalesReceipt::STATUS_PARTIALLY_REVERSED;
            $isFullyReversed = false;
            
            if ($newRemainingAmount <= 0) {
                $newStatus = SalesReceipt::STATUS_FULLY_REVERSED;
                $isFullyReversed = true;
            }
            
            $receipt->update([
                'total_reversed_amount' => $newTotalReversed,
                'remaining_amount' => $newRemainingAmount,
                'status' => $newStatus,
                'is_reversed' => $isFullyReversed,
                'reversal_reason' => $request->reversal_reason,
                'reversed_at' => $isFullyReversed ? now() : null,
                'reversed_by' => $isFullyReversed ? $userId : null,
                'reversal_id' => $isFullyReversed ? $reversal->id : null,
            ]);

            // Prepare success message
            if ($newRemainingAmount <= 0) {
                $message = "✓ Sales Receipt #{$receipt->receipt_no} has been fully reversed.\n";
                $message .= "Total reversed: ZMW " . number_format($newTotalReversed, 2);
            } else {
                $message = "✓ Partial reversal processed for Sales Receipt #{$receipt->receipt_no}.\n";
                $message .= "Reversed amount: ZMW " . number_format($totalReversalAmount, 2) . "\n";
                $message .= "Remaining balance: ZMW " . number_format($newRemainingAmount, 2) . "\n";
                $message .= "You can process additional reversals if needed.";
            }

            return redirect()->route('sales-receipts.index')
                ->with('success', $message);
        });
    }

    /**
     * Export sales receipts to CSV.
     */
    public function export()
    {
        $receipts = SalesReceipt::with(['customer', 'bankAccount'])
            ->where('company_id', Auth::user()->current_company_id)
            ->get();
        
        $filename = 'sales_receipts_' . date('Y-m-d_His') . '.csv';
        $handle = fopen('php://temp', 'w+');
        
        // Add UTF-8 BOM for proper Excel encoding
        fwrite($handle, "\xEF\xBB\xBF");
        
        // Add headers
        fputcsv($handle, [
            'Receipt No', 'Date', 'Customer', 'Payment Method', 'Reference No',
            'Deposit Account', 'Amount', 'Reversed Amount', 'Remaining Balance', 
            'Status', 'Memo'
        ]);
        
        // Add data
        foreach ($receipts as $receipt) {
            fputcsv($handle, [
                $receipt->receipt_no,
                $receipt->transaction_date->format('Y-m-d'),
                $receipt->customer->name,
                $receipt->payment_method,
                $receipt->reference_no ?? '',
                $receipt->bankAccount->name ?? '',
                number_format($receipt->amount, 2),
                number_format($receipt->total_reversed_amount, 2),
                number_format($receipt->remaining_amount, 2),
                $receipt->getStatusText(),
                $receipt->memo ?? ''
            ]);
        }
        
        rewind($handle);
        $csv = stream_get_contents($handle);
        fclose($handle);
        
        return response($csv, 200, [
            'Content-Type' => 'text/csv; charset=UTF-8',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }

    /**
     * Import sales receipts from CSV.
     */
    public function import(Request $request)
    {
        $request->validate([
            'file' => 'required|file|mimes:csv,txt',
        ]);
        
        // Process import logic here
        // This would be implemented based on your requirements
        
        return redirect()->route('sales-receipts.index')
            ->with('success', 'Import functionality to be implemented.');
    }

    /**
     * Helper to create ledger entries for the double-entry system.
     */
    private function postJournalEntry($receipt, $accountId, $debit, $credit, $description)
    {
        JournalEntry::create([
            'company_id' => $receipt->company_id,
            'customer_id' => $receipt->customer_id,
            'sales_receipt_id' => $receipt->id,
            'account_id' => $accountId,
            'transaction_date' => $receipt->transaction_date,
            'reference' => $receipt->receipt_no,
            'description' => $description,
            'debit' => $debit,
            'credit' => $credit,
            'user_id' => Auth::id(),
        ]);
    }

    /**
     * Helper to create reversal journal entries.
     */
    private function postReversalJournalEntry($receipt, $accountId, $debit, $credit, $description, $reversalDate)
    {
        JournalEntry::create([
            'company_id' => $receipt->company_id,
            'customer_id' => $receipt->customer_id,
            'sales_receipt_id' => $receipt->id,
            'account_id' => $accountId,
            'transaction_date' => $reversalDate,
            'reference' => $receipt->receipt_no . '-REVERSAL',
            'description' => $description,
            'debit' => $debit,
            'credit' => $credit,
            'user_id' => Auth::id(),
        ]);
    }
    
    /**
 * Display the transaction history (statement) for a specific sales receipt.
 */
public function history($id)
{
    $companyId = Auth::user()->current_company_id;

    // 1. Fetch Receipt with Customer and items
    $receipt = SalesReceipt::with(['customer', 'bankAccount', 'items.product'])
        ->where('company_id', $companyId)
        ->findOrFail($id);

    // 2. Fetch Reversals linked to this receipt
    $reversals = SalesReceiptReversal::where('original_sales_receipt_id', $id)
        ->where('company_id', $companyId)
        ->select(
            'reversal_date as date',
            'reversal_no as reference',
            DB::raw("'Receipt Reversal' as type"),
            'reversal_amount as amount',
            DB::raw("0 as is_debit") // Reversals decrease the cash/revenue, so they are Credits here
        )
        ->get();

    // 3. Combine and Sort
    // The Original Receipt is the starting Debit (increase in cash/revenue)
    $history = collect([
        (object)[
            'date' => $receipt->transaction_date->format('Y-m-d'),
            'reference' => $receipt->receipt_no,
            'type' => 'Original Sale',
            'amount' => $receipt->amount,
            'is_debit' => 1
        ]
    ])
    ->concat($reversals->map(function($item) {
        $item->date = \Carbon\Carbon::parse($item->date)->format('Y-m-d');
        return $item;
    }))
    ->sort(function ($a, $b) {
        if ($a->date != $b->date) {
            return strcmp($a->date, $b->date);
        }
        return $b->is_debit - $a->is_debit; // Debit first on same day
    });

    return view('sales-receipts.history', compact('receipt', 'history', 'reversals'));
}
    
}