<?php

namespace App\Http\Controllers\Modules\Accounts;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\TaxInvoice;
use App\Models\SalesPayment;
use App\Models\CustomerVendor;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

/**
 * Unified Accounts Receivable Controller
 *
 * Handles customer receivables (invoices) for all roles.
 * Uses HasRoleViews trait to automatically resolve role-specific views.
 */
class AccountsReceivableController extends Controller
{
    use HasRoleViews;

    /**
     * Display list of all receivables (customer invoices)
     */
    public function index(Request $request)
    {
        $query = TaxInvoice::with('company')
            ->orderBy('invoice_date', 'desc');

        // Filter by customer
        if ($request->filled('customer_id')) {
            $query->where('company_id', $request->customer_id);
        }

        // Filter by date range
        if ($request->filled('from_date')) {
            $query->whereDate('invoice_date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $query->whereDate('invoice_date', '<=', $request->to_date);
        }

        $invoices = $query->paginate(20);

        // Calculate paid amounts for each invoice
        $invoiceIds = $invoices->pluck('id')->toArray();
        $payments = SalesPayment::whereIn('invoice_id', $invoiceIds)
            ->selectRaw('invoice_id, SUM(payment_amount) as total_paid')
            ->groupBy('invoice_id')
            ->pluck('total_paid', 'invoice_id')
            ->toArray();

        // Get summary statistics
        $stats = $this->getReceivableStats();

        // Get customers for filter dropdown
        $customers = CustomerVendor::where('company_role', 'customer')
            ->orWhere('company_role', 'both')
            ->orderBy('company')
            ->get();

        return $this->roleView('accounts.receivable.index', compact('invoices', 'payments', 'stats', 'customers'));
    }

    /**
     * Show single receivable details with payment history
     */
    public function show($id)
    {
        $invoice = TaxInvoice::with(['company', 'items'])->findOrFail($id);

        // Get payment history
        $paymentHistory = SalesPayment::where('invoice_id', $id)
            ->orderBy('payment_date', 'desc')
            ->get();

        $totalPaid = $paymentHistory->sum('payment_amount');
        $balance = $invoice->total_amount - $totalPaid;

        return $this->roleView('accounts.receivable.show', compact('invoice', 'paymentHistory', 'totalPaid', 'balance'));
    }

    /**
     * Record payment against a receivable
     */
    public function recordPayment(Request $request, $id)
    {
        $request->validate([
            'payment_amount' => 'required|numeric|min:0.01',
            'payment_date' => 'required|date',
            'payment_method' => 'nullable|string|max:50',
            'reference_no' => 'nullable|string|max:100',
            'notes' => 'nullable|string|max:500',
        ]);

        $invoice = TaxInvoice::findOrFail($id);

        // Calculate current balance
        $totalPaid = SalesPayment::where('invoice_id', $id)->sum('payment_amount');
        $balance = $invoice->total_amount - $totalPaid;

        // Validate payment amount doesn't exceed balance
        if ($request->payment_amount > $balance) {
            return back()->with('error', 'Payment amount exceeds outstanding balance!');
        }

        // Generate payment number
        $lastPayment = SalesPayment::orderBy('id', 'desc')->first();
        $nextNumber = $lastPayment ? ((int)substr($lastPayment->payment_no, -4) + 1) : 1;
        $paymentNo = 'UEPL/PAY/' . str_pad($nextNumber, 4, '0', STR_PAD_LEFT);

        DB::transaction(function () use ($invoice, $request, $paymentNo) {
            SalesPayment::create([
                'payment_no' => $paymentNo,
                'invoice_id' => $invoice->id,
                'invoice_no' => $invoice->invoice_no,
                'party_id' => $invoice->company_id,
                'payment_date' => $request->payment_date,
                'payment_amount' => $request->payment_amount,
                'payment_method' => $request->payment_method,
                'reference_no' => $request->reference_no,
                'notes' => $request->notes,
            ]);
        });

        return back()->with('success', 'Payment recorded successfully! Payment No: ' . $paymentNo);
    }

    /**
     * Generate aging report (30/60/90 days)
     */
    public function agingReport(Request $request)
    {
        $today = Carbon::today();

        // Get all invoices
        $invoices = TaxInvoice::with('company')
            ->orderBy('invoice_date', 'asc')
            ->get();

        // Get all payments grouped by invoice
        $payments = SalesPayment::selectRaw('invoice_id, SUM(payment_amount) as total_paid')
            ->groupBy('invoice_id')
            ->pluck('total_paid', 'invoice_id')
            ->toArray();

        // Categorize by aging buckets
        $aging = [
            'current' => ['items' => collect(), 'total' => 0],
            'days_30' => ['items' => collect(), 'total' => 0],
            'days_60' => ['items' => collect(), 'total' => 0],
            'days_90_plus' => ['items' => collect(), 'total' => 0],
        ];

        foreach ($invoices as $invoice) {
            $paid = $payments[$invoice->id] ?? 0;
            $balance = $invoice->total_amount - $paid;

            if ($balance <= 0) continue; // Skip fully paid invoices

            $invoiceDate = Carbon::parse($invoice->invoice_date);
            $daysOld = $invoiceDate->diffInDays($today);

            // Add calculated fields
            $invoice->paid_amount = $paid;
            $invoice->balance_amount = $balance;

            if ($daysOld <= 30) {
                $aging['current']['items']->push($invoice);
                $aging['current']['total'] += $balance;
            } elseif ($daysOld <= 60) {
                $aging['days_30']['items']->push($invoice);
                $aging['days_30']['total'] += $balance;
            } elseif ($daysOld <= 90) {
                $aging['days_60']['items']->push($invoice);
                $aging['days_60']['total'] += $balance;
            } else {
                $aging['days_90_plus']['items']->push($invoice);
                $aging['days_90_plus']['total'] += $balance;
            }
        }

        $grandTotal = array_sum(array_column($aging, 'total'));

        return $this->roleView('accounts.receivable.aging', compact('aging', 'grandTotal'));
    }

    /**
     * Get receivable summary statistics
     */
    protected function getReceivableStats(): array
    {
        $totalInvoices = TaxInvoice::sum('total_amount');
        $totalPaid = SalesPayment::sum('payment_amount');
        $totalOutstanding = $totalInvoices - $totalPaid;

        $invoiceCount = TaxInvoice::count();

        // Count overdue invoices (older than 30 days with balance)
        $overdueInvoices = TaxInvoice::whereDate('invoice_date', '<', Carbon::today()->subDays(30))
            ->select('id', 'total_amount')
            ->get();

        $overdueIds = $overdueInvoices->pluck('id')->toArray();
        $paidByInvoice = SalesPayment::whereIn('invoice_id', $overdueIds)
            ->selectRaw('invoice_id, SUM(payment_amount) as total_paid')
            ->groupBy('invoice_id')
            ->pluck('total_paid', 'invoice_id');

        $overdueCount = 0;
        foreach ($overdueInvoices as $invoice) {
            $paid = $paidByInvoice[$invoice->id] ?? 0;
            if ($invoice->total_amount - $paid > 0) {
                $overdueCount++;
            }
        }

        return [
            'total_invoices' => $totalInvoices,
            'total_paid' => $totalPaid,
            'total_outstanding' => $totalOutstanding,
            'invoice_count' => $invoiceCount,
            'overdue_count' => $overdueCount,
        ];
    }
}
