<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ServicePurchaseReportController extends Controller
{
    protected string $module = 'Reports Management';

    public function __construct()
    {
        $module = $this->module;
    }

    public function index(Request $request)
    {
        $dateFrom   = $request->input('date_from', now()->startOfMonth()->toDateString());
        $dateTo     = $request->input('date_to',   now()->toDateString());
        $supplierId = $request->input('supplier_id');

        $reportData = null;

        if ($request->hasAny(['date_from', 'date_to', 'supplier_id'])) {
            $reportData = $this->buildReport($dateFrom, $dateTo, $supplierId);
        }

        $suppliers = DB::table('suppliers')
            ->select('id_supplier', 'supplier_name')
            ->orderBy('supplier_name')
            ->get();

        return view('reports.service_purchase_report', compact(
            'dateFrom', 'dateTo', 'supplierId', 'suppliers', 'reportData'
        ));
    }

    public function print(Request $request)
    {
        $dateFrom   = $request->input('date_from', now()->startOfMonth()->toDateString());
        $dateTo     = $request->input('date_to',   now()->toDateString());
        $supplierId = $request->input('supplier_id');

        $reportData = $this->buildReport($dateFrom, $dateTo, $supplierId);

        $supplierName = null;
        if ($supplierId) {
            $supplierName = DB::table('suppliers')
                ->where('id_supplier', $supplierId)
                ->value('supplier_name');
        }

        return view('reports.service_purchase_report_print_view', compact(
            'dateFrom', 'dateTo', 'supplierId', 'supplierName', 'reportData'
        ));
    }

    private function buildReport(
        string  $dateFrom,
        string  $dateTo,
        ?string $supplierId
    ): array {
        $query = DB::table('service_vouchers as sv')
            ->select(
                'sv.id',
                'sv.voucher_no',
                'sv.voucher_date',
                'sv.truck_no',
                'sv.bill_no',
                'sv.supplier_id',
                'sv.party_type',
                'sv.party_id',
                'sv.total_amount',
                'sv.description',
                // Get party name from either suppliers or purchasers table
                DB::raw('COALESCE(sup.supplier_name, pur.purchaser_name, sv.supplier_id) as party_name'),
            )
            ->leftJoin('suppliers as sup', function($join) {
                $join->on('sup.id_supplier', '=', 'sv.party_id')
                     ->where('sv.party_type', '=', 'Supplier');
            })
            ->leftJoin('purchasers as pur', function($join) {
                $join->on('pur.id_purchaser', '=', 'sv.party_id')
                     ->where('sv.party_type', '=', 'Purchaser');
            })
            ->whereBetween('sv.voucher_date', [$dateFrom, $dateTo]);

        if ($supplierId) {
            $query->where('sv.supplier_id', $supplierId);
        }

        $vouchers = $query
            ->orderBy('party_name')
            ->orderBy('sv.truck_no')
            ->orderBy('sv.voucher_date')
            ->get();

        if ($vouchers->isEmpty()) {
            return ['suppliers' => [], 'grandTotal' => $this->emptyTotals()];
        }

        $voucherIds = $vouchers->pluck('id')->unique()->toArray();

        // ── Load details and FORCE convert all stdClass to arrays ─────────────
        $detailsRaw = DB::table('service_voucher_details as svd')
            ->select(
                'svd.service_voucher_id',
                'svd.control_account_id',
                'svd.qty',
                'svd.unit',
                'svd.price',
                'svd.amount',
                'svd.narration',
                'ca.control_account_name as expense_account_name',
            )
            ->leftJoin('control_account as ca', 'ca.id_control_account', '=', 'svd.control_account_id')
            ->whereIn('svd.service_voucher_id', $voucherIds)
            ->get();

        // Force convert: Collection of stdClass -> nested arrays
        $details = json_decode(json_encode($detailsRaw->groupBy('service_voucher_id')), true);

        // ── Build party groups ──────────────────────────────────────────────
        $partiesList = [];
        $grandTotal  = $this->emptyTotals();

        // Group vouchers by party_name (resolved from party_type + party_id)
        $groupedByParty = $vouchers->groupBy(fn($v) => $v->party_name ?? 'Unknown');

        foreach ($groupedByParty as $partyName => $partyVouchers) {
            $partyTotals = $this->emptyTotals();
            $vehicles    = [];

            // Group party's vouchers by truck_no (vehicle)
            $groupedByVehicle = $partyVouchers->groupBy(fn($v) => $v->truck_no ?? 'N/A');

            foreach ($groupedByVehicle as $truckNo => $vehicleVouchers) {
                $vehicleTotals = $this->emptyTotals();
                $bills         = [];

                foreach ($vehicleVouchers as $voucher) {
                    $vid = (string) $voucher->id;
                    $voucherDetails = $details[$vid] ?? [];

                    $bill = [
                        'id'            => $voucher->id,
                        'date'          => $voucher->voucher_date,
                        'voucher_no'    => $voucher->voucher_no,
                        'bill_no'       => $voucher->bill_no,
                        'truck_no'      => $voucher->truck_no,
                        'party_name'    => $voucher->party_name,
                        'items'         => $voucherDetails,
                        'total_amount'  => (float) ($voucher->total_amount ?? 0),
                    ];

                    foreach ($voucherDetails as $item) {
                        $vehicleTotals['total_amount'] += (float) ($item['amount'] ?? 0);
                        $vehicleTotals['total_qty']    += (float) ($item['qty'] ?? 0);
                    }

                    $bills[] = $bill;
                }

                $this->addToTotals($partyTotals, $vehicleTotals);

                $vehicles[] = [
                    'truck_no'      => $truckNo,
                    'bills'         => $bills,
                    'vehicleTotals' => $vehicleTotals,
                ];
            }

            $this->addToTotals($grandTotal, $partyTotals);

            $partiesList[] = [
                'party_name'   => $partyName,
                'vehicles'       => $vehicles,
                'partyTotals'    => $partyTotals,
            ];
        }

        return [
            'parties'    => $partiesList,
            'grandTotal' => $grandTotal,
        ];
    }

    private function emptyTotals(): array
    {
        return [
            'total_qty'    => 0.0,
            'total_amount' => 0.0,
        ];
    }

    private function addToTotals(array &$totals, array $detail): void
    {
        foreach ($totals as $key => &$val) {
            if (isset($detail[$key])) {
                $val += $detail[$key];
            }
        }
    }
}
