<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Client;
use App\Models\ClientInvoice;
use App\Models\ClientReceipt;
use App\Models\CompanySettings;
use App\Models\Currency;
use Carbon\Carbon;
use Illuminate\Support\Facades\Schema;
use App\Services\ReportAuditService;

class ClientStatementController extends Controller
{
    private function binaryPdfResponse($pdf, string $filename)
    {
        while (ob_get_level() > 0) {
            ob_end_clean();
        }

        return response($pdf->output(), 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
            'Cache-Control' => 'private, max-age=0, must-revalidate',
            'Pragma' => 'public',
        ]);
    }

    private function buildStatementForClient(?Client $selectedClient, string $dateFrom, string $dateTo, string $currency): array
    {
        if (!$selectedClient) {
            return [
                'selectedClient' => null,
                'invoices' => collect(),
                'receipts' => collect(),
                'transactions' => collect(),
                'openingBalance' => 0.0,
                'metrics' => [
                    'totalInvoices' => 0.0,
                    'totalReceipts' => 0.0,
                    'balance' => 0.0,
                    'outstandingInvoices' => 0,
                    'paidInvoices' => 0,
                    'partiallyPaidInvoices' => 0,
                    'overdueInvoices' => 0,
                    'activeCases' => 0,
                    'lastPaymentDate' => null,
                ],
            ];
        }

        $invoices = ClientInvoice::where('client_id', $selectedClient->id)
            ->whereBetween('invoice_date', [$dateFrom, $dateTo])
            ->orderBy('invoice_date', 'asc')
            ->get();

        $receipts = ClientReceipt::where('client_id', $selectedClient->id)
            ->whereBetween('receipt_date', [$dateFrom, $dateTo])
            ->orderBy('receipt_date', 'asc')
            ->get();

        $totalInvoices = (float) $invoices->sum('total');
        $totalReceipts = (float) $receipts->sum('total_amount');
        $balance = $totalInvoices - $totalReceipts;

        $outstandingInvoices = $invoices->where('status', 'unpaid')->count();
        $paidInvoices = $invoices->where('status', 'paid')->count();
        $partiallyPaidInvoices = $invoices->where('status', 'sent')->count();
        $overdueInvoices = $invoices->where('status', 'overdue')->count();
        $activeCases = 0;
        $lastPaymentDate = optional($receipts->sortByDesc('receipt_date')->first())->receipt_date;

        $transactions = collect();
        foreach ($invoices as $invoice) {
            $transactions->push([
                'type' => 'invoice',
                'date' => $invoice->invoice_date,
                'reference' => $invoice->invoice_number,
                'description' => $invoice->description ?? 'Invoice',
                'debit' => (float) $invoice->total,
                'credit' => 0.0,
                'status' => $invoice->status,
            ]);
        }
        foreach ($receipts as $receipt) {
            $transactions->push([
                'type' => 'receipt',
                'date' => $receipt->receipt_date,
                'reference' => $receipt->receipt_number,
                'description' => 'Payment Received',
                'debit' => 0.0,
                'credit' => (float) $receipt->total_amount,
                'status' => $receipt->status,
            ]);
        }

        $transactions = $transactions
            ->sortBy('date')
            ->values();

        $runningBalance = 0.0;
        $transactions = $transactions->map(function ($t) use (&$runningBalance) {
            $runningBalance += ((float) ($t['debit'] ?? 0)) - ((float) ($t['credit'] ?? 0));
            $t['balance'] = $runningBalance;
            return $t;
        });

        $openingInvoices = (float) ClientInvoice::where('client_id', $selectedClient->id)
            ->where('invoice_date', '<', $dateFrom)
            ->sum('total');
        $openingReceipts = (float) ClientReceipt::where('client_id', $selectedClient->id)
            ->where('receipt_date', '<', $dateFrom)
            ->sum('total_amount');
        $openingBalance = $openingInvoices - $openingReceipts;

        return [
            'selectedClient' => $selectedClient,
            'invoices' => $invoices,
            'receipts' => $receipts,
            'transactions' => $transactions,
            'openingBalance' => $openingBalance,
            'metrics' => [
                'totalInvoices' => $totalInvoices,
                'totalReceipts' => $totalReceipts,
                'balance' => $balance,
                'outstandingInvoices' => $outstandingInvoices,
                'paidInvoices' => $paidInvoices,
                'partiallyPaidInvoices' => $partiallyPaidInvoices,
                'overdueInvoices' => $overdueInvoices,
                'activeCases' => $activeCases,
                'lastPaymentDate' => $lastPaymentDate,
            ],
        ];
    }

    public function index(Request $request)
    {
        // Get filter inputs from request
        $clientId = $request->input('client_id');
        $dateFrom = $request->input('date_from', date('Y-m-01')); // Default to first day of month
        $dateTo = $request->input('date_to', date('Y-m-d')); // Default to today
        $currency = $request->input('currency', 'USD'); // Default to USD
        
        // Fetch all clients for dropdown
        $clients = Client::all();
        
        // Fetch all currencies for dropdown
        $currencies = Currency::all();

        // Select client by id or default to first
        $selectedClientId = $clientId ?? $clients->first()->id ?? null;
        $selectedClient = ($selectedClientId && $selectedClientId !== 'all') ? Client::find($selectedClientId) : null;

        $statement = $this->buildStatementForClient($selectedClient, $dateFrom, $dateTo, $currency);
        $company = CompanySettings::query()->first();

        if (Schema::hasTable('report_audits')) {
            app(ReportAuditService::class)->log(
                'client-statement',
                'Client Statement',
                [
                    'client_id' => $selectedClientId,
                    'date_from' => $dateFrom,
                    'date_to' => $dateTo,
                    'currency' => $currency,
                ],
                [
                    'openingBalance' => $statement['openingBalance'] ?? 0,
                    'metrics' => $statement['metrics'] ?? [],
                    'transactions' => ($statement['transactions'] ?? collect())->take(500)->values()->all(),
                ],
                $selectedClient ? Client::class : null,
                $selectedClient ? (int) $selectedClient->id : null
            );
        }

        // Pass data to view
        return view('modules.reports.client-statement', [
            'company' => $company,
            'clients' => $clients,
            'currencies' => $currencies,
            'selectedClient' => $statement['selectedClient'],
            'invoices' => $statement['invoices'],
            'receipts' => $statement['receipts'],
            'transactions' => $statement['transactions'],
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
            'currency' => $currency,
            'openingBalance' => $statement['openingBalance'],
            'metrics' => $statement['metrics'],
        ]);
    }

    public function downloadPdf(Request $request)
    {
        $dateFrom = $request->query('date_from', date('Y-m-01'));
        $dateTo = $request->query('date_to', date('Y-m-d'));
        $currency = $request->query('currency', 'USD');
        $clientId = $request->query('client_id');

        if ($clientId === 'all') {
            return redirect()
                ->route('modules.reports.client-statement', $request->query())
                ->withErrors(['client_id' => 'Please select a single client for PDF download.']);
        }

        $selectedClient = null;
        if ($clientId) {
            $selectedClient = Client::find($clientId);
        } else {
            $selectedClient = Client::query()->orderBy('id')->first();
        }

        $statement = $this->buildStatementForClient($selectedClient, $dateFrom, $dateTo, $currency);
        $company = CompanySettings::query()->first();

        $currencyModel = Currency::query()
            ->where('currency_id', $currency)
            ->first();

        $pdf = \PDF::loadView('modules.reports.client-statement-pdf', [
            'company' => $company,
            'selectedClient' => $statement['selectedClient'],
            'invoices' => $statement['invoices'],
            'receipts' => $statement['receipts'],
            'transactions' => $statement['transactions'],
            'openingBalance' => $statement['openingBalance'],
            'metrics' => $statement['metrics'],
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
            'currency' => $currencyModel,
            'currencyId' => $currency,
        ]);

        $clientName = $statement['selectedClient'] ? ($statement['selectedClient']->fullName ?? $statement['selectedClient']->full_name ?? $statement['selectedClient']->name ?? 'client') : 'client';
        $safeClient = preg_replace('/[^A-Za-z0-9_-]+/', '_', (string) $clientName);
        $filename = 'client_statement_' . $safeClient . '_' . Carbon::parse($dateFrom)->format('Ymd') . '_to_' . Carbon::parse($dateTo)->format('Ymd') . '.pdf';

        return $this->binaryPdfResponse($pdf, $filename);
    }
}
