<?php

namespace App\Http\Controllers\Accounting;

use App\Http\Controllers\Controller;
use App\Models\FinancialTransaction;
use App\Models\FinancialTreasury;
use App\Models\Customer;
use Illuminate\Http\Request;
use Carbon\Carbon;

class ReportController extends Controller
{
    public function index()
    {
        $dashboard = [
            'income' => (float) FinancialTransaction::where('type', 'in')
                ->where(function ($q) {
                    $q->whereNull('ref_no')->orWhere('ref_no', 'not like', 'TRF-%');
                })->sum(\Illuminate\Support\Facades\DB::raw('amount * COALESCE(exchange_rate, 1)')),

            'expenses' => (float) FinancialTransaction::where('type', 'out')
                ->where(function ($q) {
                    $q->whereNull('ref_no')->orWhere('ref_no', 'not like', 'TRF-%');
                })->sum(\Illuminate\Support\Facades\DB::raw('amount * COALESCE(exchange_rate, 1)')),

            // For Cash Balance, we need to iterate Treasuries and convert
            'cash_balance' => FinancialTreasury::with('currency')->get()->sum(function ($t) {
                return $t->balance * ($t->currency?->exchange_rate ?? 1);
            }),
        ];
        $dashboard['profit'] = $dashboard['income'] - $dashboard['expenses'];

        return view('accounting.reports.index', compact('dashboard'));
    }

    public function profitLoss(Request $request)
    {
        $startDate = $request->get('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        // 1. Revenue (Invoices) - Accrual (Recognition when issued)
        $revenue = \App\Models\Invoice::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->sum(\Illuminate\Support\Facades\DB::raw('total * COALESCE(exchange_rate, 1)'));

        // 2. Cost of Sales / Purchases (Bills) - Accrual
        $purchases = \App\Models\Bill::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->sum(\Illuminate\Support\Facades\DB::raw('total * COALESCE(exchange_rate, 1)'));

        // 3. Operating Expenses (Financial Transactions out, NOT linked to specific bills)
        // This takes general transactions like Rent, Salaries recorded via Expense module
        $expenseCategories = \App\Models\FinancialCategory::where('type', 'expense')
            ->with([
                'transactions' => function ($query) use ($startDate, $endDate) {
                    $query->whereBetween('date', [$startDate, $endDate])
                        ->whereNull('model_type'); // Exclude bill payments to avoid double counting
                }
            ])
            ->get()
            ->map(function ($category) {
                $category->total_amount = (float) $category->transactions->sum(function ($t) {
                    return $t->amount * ($t->exchange_rate ?: 1);
                });
                return $category;
            })
            ->filter(fn($c) => $c->total_amount > 0);

        $totalOperatingExpenses = (float) $expenseCategories->sum('total_amount');

        $grossProfit = $revenue - $purchases;
        $netProfit = $grossProfit - $totalOperatingExpenses;

        return view('accounting.reports.profit_loss', compact(
            'revenue',
            'purchases',
            'expenseCategories',
            'totalOperatingExpenses',
            'grossProfit',
            'netProfit',
            'startDate',
            'endDate'
        ));
    }

    public function customerStatement(Request $request)
    {
        // ... (Existing logic for selecting customer)
        $customers = Customer::orderBy('name')->get();
        $selectedCustomer = null;
        $transactions = collect();

        if ($request->has('customer_id')) {
            $selectedCustomer = Customer::findOrFail($request->customer_id);
            $startDate = $request->get('start_date', Carbon::now()->startOfYear()->toDateString());
            $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

            // Get Invoices (Debits) - Convert to Base
            $invoices = $selectedCustomer->invoices()
                ->whereBetween('date', [$startDate, $endDate])
                ->get()
                ->map(function ($invoice) {
                    $rate = $invoice->exchange_rate ?: 1;
                    return [
                        'date' => $invoice->date,
                        'type' => 'Invoice' . ($invoice->currency ? " ({$invoice->currency->code})" : ''),
                        'ref' => $invoice->code,
                        'description' => 'Invoice Generation',
                        'debit' => $invoice->total * $rate,
                        'credit' => 0,
                        'original_amount' => $invoice->total,
                        'currency' => $invoice->currency ? $invoice->currency->code : 'EGP'
                    ];
                });

            // Get Payments 
            $payments = collect();
            foreach ($selectedCustomer->invoices as $inv) {
                foreach ($inv->transactions as $trans) {
                    if ($trans->date >= $startDate && $trans->date <= $endDate) {
                        // Transaction Amount is the amount PAID. 
                        // If cross-currency, we stored 'currency_id' and 'exchange_rate' in transactions.
                        // We want the value in Base Currency.
                        $rate = $trans->exchange_rate ?: 1;
                        $payments->push([
                            'date' => $trans->date,
                            'type' => 'Payment',
                            'ref' => $inv->code,
                            'description' => 'Payment for ' . $inv->code,
                            'debit' => 0,
                            'credit' => $trans->amount * $rate,
                        ]);
                    }
                }
            }
            // Merge and sort
            $transactions = $invoices->merge($payments)->sortBy('date');
        }

        return view('accounting.reports.customer_statement', compact('customers', 'selectedCustomer', 'transactions'));
    }

    public function printCustomerStatement(Request $request)
    {
        // Similar update needed for print if used often. For now focused on view.
        return $this->customerStatement($request); // Should separate logic properly but for this step...
        // Actually let's just keep the original structure for print but update mapping 
        $selectedCustomer = Customer::findOrFail($request->customer_id);
        $startDate = $request->get('start_date', Carbon::now()->startOfYear()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        $invoices = $selectedCustomer->invoices()
            ->whereBetween('date', [$startDate, $endDate])
            ->get()
            ->map(function ($invoice) {
                $rate = $invoice->exchange_rate ?: 1;
                return (object) [
                    'date' => $invoice->date,
                    'type' => 'Invoice',
                    'ref' => $invoice->code,
                    'description' => 'Invoice Generation',
                    'debit' => $invoice->total * $rate,
                    'credit' => 0,
                ];
            });

        $payments = collect();
        foreach ($selectedCustomer->invoices as $inv) {
            foreach ($inv->transactions as $trans) {
                if ($trans->date >= $startDate && $trans->date <= $endDate) {
                    $rate = $trans->exchange_rate ?: 1;
                    $payments->push((object) [
                        'date' => $trans->date,
                        'type' => 'Payment',
                        'ref' => $inv->code,
                        'description' => 'Payment for ' . $inv->code,
                        'debit' => 0,
                        'credit' => $trans->amount * $rate,
                    ]);
                }
            }
        }

        $transactions = $invoices->merge($payments)->sortBy('date');
        $settings = \App\Models\Setting::getGroup('general');

        return view('accounting.reports.print_customer_statement', compact('selectedCustomer', 'transactions', 'settings', 'startDate', 'endDate'));
    }

    public function treasuryBalance()
    {
        $treasuries = FinancialTreasury::with(['transactions', 'currency'])->get();
        // Calculate total in Base Currency
        $totalBalance = $treasuries->sum(function ($t) {
            return $t->balance * ($t->currency?->exchange_rate ?? 1);
        });

        return view('accounting.reports.treasury_balance', compact('treasuries', 'totalBalance'));
    }

    public function expensesBreakdown(Request $request)
    {
        $startDate = $request->get('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        // Group Bills by Supplier - Assuming Bills are passed to Transaction eventually or we sum bills directly
        // If Bills have currency, we need to convert. Bills table not updated yet in this task scope.
        // Assuming Bills are EGP for now or handled separately.

        $billExpenses = \App\Models\Bill::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->with('supplier')
            ->get()
            ->groupBy('supplier.name')
            ->map(function ($bills) {
                return $bills->sum('total');
            });

        // Other expenses from transactions
        $otherExpenses = FinancialTransaction::where('type', 'out')
            ->whereBetween('date', [$startDate, $endDate])
            ->where(function ($q) {
                $q->whereNull('model_type')
                    ->orWhere('model_type', '!=', 'App\Models\Bill');
            })
            ->where(function ($q) {
                $q->whereNull('ref_no')
                    ->orWhere('ref_no', 'not like', 'TRF-%');
            })
            ->get()
            ->groupBy(function ($t) {
                return $t->ref_no ? explode('-', $t->ref_no)[0] : 'General Expense';
            })
            ->map(function ($trans) {
                // Sum converted amounts
                return $trans->sum(function ($t) {
                    return $t->amount * ($t->exchange_rate ?: 1);
                });
            });

        $combinedExpenses = $billExpenses->concat($otherExpenses);
        $labels = $combinedExpenses->keys();
        $data = $combinedExpenses->values();

        return view('accounting.reports.expenses_breakdown', compact('labels', 'data', 'startDate', 'endDate'));
    }

    public function cashFlow(Request $request)
    {
        $year = $request->get('year', Carbon::now()->year);

        // Monthly Income vs Expenses
        $incomeData = [];
        $expenseData = [];
        $months = [];

        for ($m = 1; $m <= 12; $m++) {
            $months[] = Carbon::create()->month($m)->format('F');

            $start = Carbon::create($year, $m, 1)->startOfMonth();
            $end = Carbon::create($year, $m, 1)->endOfMonth();

            $income = FinancialTransaction::where('type', 'in')
                ->whereBetween('date', [$start, $end])
                ->sum(\Illuminate\Support\Facades\DB::raw('amount * COALESCE(exchange_rate, 1)'));

            $expense = FinancialTransaction::where('type', 'out')
                ->whereBetween('date', [$start, $end])
                ->sum(\Illuminate\Support\Facades\DB::raw('amount * COALESCE(exchange_rate, 1)'));

            $incomeData[] = $income;
            $expenseData[] = $expense;
        }

        return view('accounting.reports.cash_flow', compact('months', 'incomeData', 'expenseData', 'year'));
    }

    public function vatReturn(Request $request)
    {
        $startDate = $request->get('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        // Output Tax (Sales) - Convert Tax Amount to Base
        $outputTax = \App\Models\Invoice::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->sum(\Illuminate\Support\Facades\DB::raw('tax_amount * COALESCE(exchange_rate, 1)'));

        // Input Tax (Purchases) - Assuming Bills are EGP for now as we didn't add currency to Bills
        $inputTax = \App\Models\Bill::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->sum('tax_amount');

        $netVat = $outputTax - $inputTax;

        return view('accounting.reports.vat_return', compact('outputTax', 'inputTax', 'netVat', 'startDate', 'endDate'));
    }

    public function equityStatement()
    {
        $partners = \App\Models\Partner::all();
        $investors = \App\Models\Investor::all();

        $totalCapital = \App\Models\JournalEntryLine::whereHas('account', function ($q) {
            $q->where('code', '3100');
        })->sum(\Illuminate\Support\Facades\DB::raw('credit - debit'));

        $retainedEarnings = \App\Models\JournalEntryLine::whereHas('account', function ($q) {
            $q->where('code', '3200');
        })->sum(\Illuminate\Support\Facades\DB::raw('credit - debit'));

        $distributions = \App\Models\ProfitDistribution::sum('amount');

        return view('accounting.reports.equity_statement', compact(
            'partners',
            'investors',
            'totalCapital',
            'retainedEarnings',
            'distributions'
        ));
    }

    public function salesAnalysis(Request $request)
    {
        $startDate = $request->get('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        $revenue = \App\Models\Invoice::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->sum(\Illuminate\Support\Facades\DB::raw('total * COALESCE(exchange_rate, 1)'));

        $invoiceCount = \App\Models\Invoice::whereBetween('date', [$startDate, $endDate])
            ->where('status', '!=', 'cancelled')
            ->count();

        $avgInvoice = $invoiceCount > 0 ? $revenue / $invoiceCount : 0;

        $newCustomers = \App\Models\Customer::whereBetween('created_at', [$startDate, $endDate])->count();

        $topCustomers = \App\Models\Customer::withSum([
            'invoices as total_spent' => function ($q) use ($startDate, $endDate) {
                $q->whereBetween('date', [$startDate, $endDate])->where('status', '!=', 'cancelled');
            }
        ], \Illuminate\Support\Facades\DB::raw('total * COALESCE(exchange_rate, 1)'))
            ->orderByDesc('total_spent')
            ->take(10)
            ->get();

        $salesPerformance = \App\Models\SalesPerson::withSum([
            'invoices as total_sales' => function ($q) use ($startDate, $endDate) {
                $q->whereBetween('date', [$startDate, $endDate])->where('status', '!=', 'cancelled');
            }
        ], \Illuminate\Support\Facades\DB::raw('total * COALESCE(exchange_rate, 1)'))
            ->orderByDesc('total_sales')
            ->get();

        return view('accounting.reports.sales_performance', compact('revenue', 'invoiceCount', 'avgInvoice', 'newCustomers', 'topCustomers', 'salesPerformance', 'startDate', 'endDate'));
    }

    public function inventoryReport()
    {
        // Since stock is now global in the products table, we'll group it under a virtual main warehouse
        // to maintain compatibility with the view which iterates over warehouses.
        $productsWithStock = \App\Models\Product::where('stock', '>', 0)->get();

        $warehouses = collect([
            (object) [
                'name' => 'Main Warehouse',
                'products' => $productsWithStock
            ]
        ]);

        $lowStockProducts = \App\Models\Product::whereRaw('stock <= min_stock')->get();

        $topProductsByVolume = \App\Models\InvoiceItem::select('product_id', \Illuminate\Support\Facades\DB::raw('SUM(quantity) as total_qty'))
            ->groupBy('product_id')
            ->with('product')
            ->orderByDesc('total_qty')
            ->take(10)
            ->get();

        return view('accounting.reports.inventory_report', compact('warehouses', 'lowStockProducts', 'topProductsByVolume'));
    }

    public function hrReport(Request $request)
    {
        $startDate = $request->get('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->get('end_date', Carbon::now()->endOfMonth()->toDateString());

        $totalSalaries = \App\Models\Payroll::whereBetween('payment_date', [$startDate, $endDate])
            ->where('status', 'paid')
            ->sum('net_salary');

        $employeeStats = \App\Models\Department::withCount('employees')->get();

        $attendanceRate = 0;
        $totalDays = Carbon::parse($startDate)->diffInDays(Carbon::parse($endDate)) + 1;
        $employeeCount = \App\Models\Employee::count();
        if ($employeeCount > 0 && $totalDays > 0) {
            $actualAttendance = \App\Models\Attendance::whereBetween('date', [$startDate, $endDate])->count();
            $potentialAttendance = $employeeCount * $totalDays;
            $attendanceRate = ($actualAttendance / $potentialAttendance) * 100;
        }

        return view('accounting.reports.hr_report', compact('totalSalaries', 'employeeStats', 'attendanceRate', 'startDate', 'endDate'));
    }

    public function operationsReport()
    {
        $ticketStats = \App\Models\Ticket::select('status', \Illuminate\Support\Facades\DB::raw('count(*) as count'))
            ->groupBy('status')
            ->get();

        $activeSubscriptions = \App\Models\Subscription::where('status', 'active')->count();
        $expiringSoon = \App\Models\Subscription::where('status', 'active')
            ->whereDate('next_due_date', '<=', Carbon::now()->addDays(30))
            ->count();

        return view('accounting.reports.operations_report', compact('ticketStats', 'activeSubscriptions', 'expiringSoon'));
    }
}
