<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Expense;
use App\Models\Income;
use Dompdf\Dompdf;
use Dompdf\Options;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class AccountingReportController extends Controller
{
    public function index(Request $request): View
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));

        $totalIncome = Income::whereBetween('income_date', [$dateFrom, $dateTo])->sum('total');
        $totalExpenses = Expense::whereBetween('expense_date', [$dateFrom, $dateTo])->sum('total');

        return view('admin.reports.accounting.index', [
            'totalIncome' => $totalIncome,
            'totalExpenses' => $totalExpenses,
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
        ]);
    }

    /**
     * API endpoint to fetch income data
     */
    public function getIncomeData(Request $request): JsonResponse
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Income::with(['account', 'customer'])
            ->whereBetween('income_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('income_number', 'like', "%{$search}%")
                    ->orWhereHas('customer', function ($customerQuery) use ($search) {
                        $customerQuery->where('name', 'like', "%{$search}%");
                    });
            });
        }

        $incomes = $query->orderBy('income_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($income) {
                return [
                    'id' => $income->id,
                    'income_number' => $income->income_number ?? 'N/A',
                    'description' => $income->description ?? 'N/A',
                    'category' => $income->category ?? 'N/A',
                    'income_date' => $income->income_date->format('M d, Y'),
                    'amount' => number_format($income->total, 2),
                ];
            });

        $totalIncome = Income::whereBetween('income_date', [$dateFrom, $dateTo])
            ->when($category && $category !== 'all', fn ($q) => $q->where('category', $category))
            ->when($search, function ($q) use ($search) {
                $q->where(function ($query) use ($search) {
                    $query->where('description', 'like', "%{$search}%")
                        ->orWhere('income_number', 'like', "%{$search}%");
                });
            })
            ->sum('total');

        return response()->json([
            'success' => true,
            'data' => $incomes,
            'totalIncome' => $totalIncome,
        ]);
    }

    /**
     * API endpoint to fetch expense data
     */
    public function getExpenseData(Request $request): JsonResponse
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Expense::with(['account', 'vendor'])
            ->whereBetween('expense_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('expense_number', 'like', "%{$search}%")
                    ->orWhereHas('vendor', function ($vendorQuery) use ($search) {
                        $vendorQuery->where('name', 'like', "%{$search}%");
                    });
            });
        }

        $expenses = $query->orderBy('expense_date', 'desc')
            ->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($expense) {
                return [
                    'id' => $expense->id,
                    'expense_number' => $expense->expense_number ?? 'N/A',
                    'description' => $expense->description ?? 'N/A',
                    'category' => $expense->category ?? 'N/A',
                    'expense_date' => $expense->expense_date->format('M d, Y'),
                    'amount' => number_format($expense->total, 2),
                ];
            });

        $totalExpenses = Expense::whereBetween('expense_date', [$dateFrom, $dateTo])
            ->when($category && $category !== 'all', fn ($q) => $q->where('category', $category))
            ->when($search, function ($q) use ($search) {
                $q->where(function ($query) use ($search) {
                    $query->where('description', 'like', "%{$search}%")
                        ->orWhere('expense_number', 'like', "%{$search}%");
                });
            })
            ->sum('total');

        return response()->json([
            'success' => true,
            'data' => $expenses,
            'totalExpenses' => $totalExpenses,
        ]);
    }

    /**
     * Export income data to CSV
     */
    public function exportIncomeCsv(Request $request): StreamedResponse
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Income::with(['account', 'customer'])
            ->whereBetween('income_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('income_number', 'like', "%{$search}%");
            });
        }

        $incomes = $query->orderBy('income_date', 'desc')->get();

        $filename = 'income_report_'.$dateFrom.'_to_'.$dateTo.'.csv';
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="'.$filename.'"',
        ];

        $callback = function () use ($incomes) {
            $file = fopen('php://output', 'w');
            fputcsv($file, ['#', 'Income Number', 'Description', 'Category', 'Date', 'Amount']);

            foreach ($incomes as $index => $income) {
                fputcsv($file, [
                    $index + 1,
                    $income->income_number ?? 'N/A',
                    $income->description ?? 'N/A',
                    $income->category ?? 'N/A',
                    $income->income_date->format('Y-m-d'),
                    number_format($income->total, 2),
                ]);
            }

            fclose($file);
        };

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

    /**
     * Export expense data to CSV
     */
    public function exportExpenseCsv(Request $request): StreamedResponse
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Expense::with(['account', 'vendor'])
            ->whereBetween('expense_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('expense_number', 'like', "%{$search}%");
            });
        }

        $expenses = $query->orderBy('expense_date', 'desc')->get();

        $filename = 'expense_report_'.$dateFrom.'_to_'.$dateTo.'.csv';
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="'.$filename.'"',
        ];

        $callback = function () use ($expenses) {
            $file = fopen('php://output', 'w');
            fputcsv($file, ['#', 'Expense Number', 'Description', 'Category', 'Date', 'Amount']);

            foreach ($expenses as $index => $expense) {
                fputcsv($file, [
                    $index + 1,
                    $expense->expense_number ?? 'N/A',
                    $expense->description ?? 'N/A',
                    $expense->category ?? 'N/A',
                    $expense->expense_date->format('Y-m-d'),
                    number_format($expense->total, 2),
                ]);
            }

            fclose($file);
        };

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

    /**
     * Export income data to PDF
     */
    public function exportIncomePdf(Request $request)
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Income::with(['account', 'customer'])
            ->whereBetween('income_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('income_number', 'like', "%{$search}%");
            });
        }

        $incomes = $query->orderBy('income_date', 'desc')->get();
        $totalIncome = $incomes->sum('total');

        $html = view('admin.reports.accounting.income-pdf', [
            'incomes' => $incomes,
            'totalIncome' => $totalIncome,
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
        ])->render();

        $options = new Options;
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isRemoteEnabled', true);
        $options->set('defaultFont', 'Arial');

        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'landscape');
        $dompdf->render();

        $filename = 'income_report_'.$dateFrom.'_to_'.$dateTo.'.pdf';

        return $dompdf->stream($filename);
    }

    /**
     * Export expense data to PDF
     */
    public function exportExpensePdf(Request $request)
    {
        $dateFrom = $request->get('date_from', now()->startOfMonth()->format('Y-m-d'));
        $dateTo = $request->get('date_to', now()->format('Y-m-d'));
        $category = $request->get('category');
        $search = $request->get('search');

        $query = Expense::with(['account', 'vendor'])
            ->whereBetween('expense_date', [$dateFrom, $dateTo]);

        if ($category && $category !== 'all') {
            $query->where('category', $category);
        }

        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                    ->orWhere('expense_number', 'like', "%{$search}%");
            });
        }

        $expenses = $query->orderBy('expense_date', 'desc')->get();
        $totalExpenses = $expenses->sum('total');

        $html = view('admin.reports.accounting.expense-pdf', [
            'expenses' => $expenses,
            'totalExpenses' => $totalExpenses,
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
        ])->render();

        $options = new Options;
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isRemoteEnabled', true);
        $options->set('defaultFont', 'Arial');

        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'landscape');
        $dompdf->render();

        $filename = 'expense_report_'.$dateFrom.'_to_'.$dateTo.'.pdf';

        return $dompdf->stream($filename);
    }

    public function trialBalance(): View
    {
        return view('admin.accounting.reports.trial-balance');
    }

    public function profitLoss(): View
    {
        return view('admin.accounting.reports.profit-loss');
    }

    public function taxReport(): View
    {
        return view('admin.accounting.reports.tax-report');
    }
}
