<?php
namespace App\Http\Controllers;

use App\Models\Job;
use App\Models\AppSetting;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;

class GrossProfitDetailController extends Controller
{
    public function show(Job $job)
    {
        $data = $this->buildData($job);
        return view('gross-profit.show', $data);
    }

    public function pdf(Job $job)
    {
        $data = $this->buildData($job);
        $pdf  = Pdf::loadView('gross-profit.pdf', $data)->setPaper('a4', 'portrait');
        return $pdf->download('gross-profit-' . $job->job_number . '.pdf');
    }

    private function buildData(Job $job): array
    {
        $directRoles = ['processor', 'factory_employee', 'lead_installer'];

        $job->load([
            'contact', 'manager', 'consultant',
            'quotes.sections.items',
            'poAllocations.purchaseOrder',
            'poAllocations.stock',
            'variants.items.materialType',
            'jobInvoices.creator',
            'worksOrders.faults',
        ]);

        // Labour: direct roles always counted; others need approved/paid invoice
        $job->load(['timeEntries' => fn($q) => $q->where('status', 'completed')
            ->with(['user.role', 'invoice'])]);

        // Manual trade invoices (approved/paid) for this job
        $manualTradeInvoices = \App\Models\StaffInvoice::where('job_id', $job->id)
            ->where('invoice_type', 'manual')
            ->whereIn('status', ['approved', 'paid'])
            ->with('user.role')
            ->get();

        // Revenue from latest accepted/converted quote
        $quote = $job->quotes()->whereIn('status', ['accepted','converted'])->latest()->first()
            ?? $job->quotes()->latest()->first();

        $allItems     = $quote ? $quote->sections->flatMap->items : collect();
        $quoteRevenue = $allItems->sum(fn($i) => (float)($i->total_retail ?? $i->total ?? 0));
        $matCost      = $allItems->sum(fn($i) => (float)($i->total_wsale ?? 0));

        // Accepted variants — calculate revenue from items' retail prices
        $acceptedVariants = $job->variants->where('status', 'accepted');

        // Build per-variant item lines for GP report display
        $variantItemLines = collect();
        $variantRevenue   = 0.0;
        $variantWsale     = 0.0;

        foreach ($acceptedVariants as $v) {
            $vRetail = 0.0;
            $vWsale  = 0.0;
            foreach ($v->items as $item) {
                $lineRetail = round((float)$item->qty * (float)$item->retail_price, 2);
                $lineWsale  = round((float)$item->qty * (float)$item->wsale_price, 2);
                $vRetail   += $lineRetail;
                $vWsale    += $lineWsale;
                $variantItemLines->push([
                    'variant_name'  => $v->name,
                    'variant_id'    => $v->id,
                    'description'   => $item->description,
                    'item_code'     => $item->item_code,
                    'unit'          => $item->unit,
                    'qty'           => (float) $item->qty,
                    'retail_price'  => (float) $item->retail_price,
                    'wsale_price'   => (float) $item->wsale_price,
                    'retail_total'  => $lineRetail,
                    'wsale_total'   => $lineWsale,
                    'profit'        => round($lineRetail - $lineWsale, 2),
                ]);
            }
            // Fallback: if variant has no items but has a price_adjustment, use that
            if ($v->items->count() === 0) {
                $adj = (float) $v->price_adjustment;
                $variantRevenue += $adj;
                $variantItemLines->push([
                    'variant_name' => $v->name,
                    'variant_id'   => $v->id,
                    'description'  => $v->name,
                    'item_code'    => null,
                    'unit'         => null,
                    'qty'          => 1,
                    'retail_price' => $adj,
                    'wsale_price'  => 0,
                    'retail_total' => $adj,
                    'wsale_total'  => 0,
                    'profit'       => $adj,
                ]);
            } else {
                $variantRevenue += $vRetail;
                $variantWsale   += $vWsale;
            }
        }

        // Net variant profit (retail - wsale) for display
        $variantProfit = round($variantRevenue - $variantWsale, 2);
        $variantRevenue = $variantProfit;
        // Job invoice deductions (reduce gross profit, not revenue)
        $invoiceLines = $job->jobInvoices->map(fn($inv) => [
            'invoice_number' => $inv->invoice_number ?? '—',
            'invoice_date'   => $inv->invoice_date?->format('d M Y') ?? '—',
            'amount'         => (float)($inv->invoice_amount ?? 0),
            'note'           => $inv->note ?? '',
            'added_by'       => $inv->creator?->name ?? '—',
        ]);
        $invoiceDeductions = $invoiceLines->sum('amount');

        $revenue = $quoteRevenue + $variantRevenue;

        // Labour: direct roles always count; trades/others need approved invoice
        $timeBasedLabourLines = $job->timeEntries->filter(function ($entry) use ($directRoles) {
            $role = $entry->user?->role?->name ?? '';
            if (in_array($role, $directRoles)) return true;
            return $entry->invoice && in_array($entry->invoice->status, ['approved', 'paid']);
        })->map(function ($entry) {
            $hours = round(($entry->duration_minutes ?? 0) / 60, 2);
            $rate  = (float)($entry->user?->hourly_rate ?? 0);
            return [
                'staff'       => $entry->user?->name ?? 'Unknown',
                'role'        => $entry->user?->role?->name ?? '',
                'hours'       => $hours,
                'rate'        => $rate,
                'cost'        => round($hours * $rate, 2),
                'date'        => optional($entry->started_at ?? $entry->created_at)->format('d M Y'),
                'type'        => 'time_based',
            ];
        })->filter(fn($r) => $r['cost'] > 0);

        // Manual trade invoice lines (approved/paid)
        $manualTradeLines = $manualTradeInvoices->map(function ($inv) {
            return [
                'staff'       => $inv->user?->name ?? 'Unknown',
                'role'        => $inv->user?->role?->name ?? 'trades',
                'hours'       => 0,
                'rate'        => 0,
                'cost'        => (float) $inv->total_amount,
                'date'        => $inv->created_at?->format('d M Y'),
                'type'        => 'manual',
                'invoice_ref' => $inv->invoice_number,
                'description' => $inv->description,
                'net_amount'  => (float) $inv->net_amount,
                'gst_amount'  => (float) $inv->gst_amount,
            ];
        });

        $labourLines = $timeBasedLabourLines->concat($manualTradeLines)->values();
        $labourCost  = $labourLines->sum('cost');

        // PO allocations
        $poLines = $job->poAllocations->map(fn($a) => [
            'description' => $a->description,
            'source'      => $a->purchaseOrder?->po_number ?? ($a->stock ? 'Stock: ' . $a->stock->sku : '—'),
            'qty'         => (float)$a->qty,
            'unit_cost'   => (float)$a->unit_cost,
            'total'       => (float)$a->total_cost,
        ]);
        $poCost = $poLines->sum('total');

        // Works order fault deductions
        $faultLines = $job->worksOrders->flatMap(function ($wo) {
            return $wo->faults->map(fn($f) => [
                'wo_number'  => $wo->order_number,
                'fault_num'  => $f->fault_number,
                'fault_type' => $f->fault_type ?? '—',
                'cost'       => (float) $f->cost,
                'approved'   => $wo->fault_approval_status,
            ]);
        })->filter(fn($f) => $f['cost'] > 0);
        $faultDeductions = $faultLines->sum('cost');

        $totalCost   = $matCost + $labourCost + $poCost;
        $grossProfit = $revenue - $totalCost - $invoiceDeductions - $faultDeductions;
        $margin      = $revenue > 0 ? round(($grossProfit / $revenue) * 100, 1) : 0;

        return compact(
            'job', 'quote', 'allItems', 'revenue', 'quoteRevenue', 'matCost',
            'acceptedVariants', 'variantRevenue', 'variantWsale', 'variantProfit', 'variantItemLines',
            'invoiceLines', 'invoiceDeductions',
            'labourLines', 'labourCost', 'poLines', 'poCost',
            'faultLines', 'faultDeductions',
            'totalCost', 'grossProfit', 'margin'
        );
    }
}
