<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\productQuotationMaster;
use App\Models\WorkOrderDetail;
use App\Models\WorkOrderMaster;
use App\Models\WorkOrderMerge;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;

class WorkOrderController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $workOrders = WorkOrderMaster::with('workOrderDetails', 'quotation', 'client', 'user')
            ->orderBy('id', 'desc')
            ->get();

        if (request()->wantsJson()) {
            return response()->json([
                'workOrders' => $workOrders,
            ]);
        }

        return Inertia::render('WorkOrder/WorkOrder', [
            'workOrders' => $workOrders,
        ]);
    }

    /**
     * Get paginated work orders with search (for server-side pagination)
     */
    public function view(Request $request)
    {
        $search = $request->input('search', '');
        $perPage = $request->input('perPage', 10);
        $page = $request->input('page', 1);

        $query = WorkOrderMaster::with([
            'workOrderDetails' => function ($query) {
                $query->with('attribute.product');
            },
            'quotation',
            'client',
            'user',
            'approval',
        ])
            ->orderBy('id', 'desc');

        // Apply search if provided
        if (! empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('work_order_no', 'like', "%{$search}%")
                    ->orWhere('date', 'like', "%{$search}%")
                    ->orWhere('note', 'like', "%{$search}%")
                    ->orWhereHas('client', function ($subQuery) use ($search) {
                        $subQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('code', 'like', "%{$search}%");
                    })
                    ->orWhereHas('quotation', function ($subQuery) use ($search) {
                        $subQuery->where('quotation_number', 'like', "%{$search}%");
                    });
            });
        }

        // Get paginated results
        $workOrders = $query->paginate($perPage, ['*'], 'page', $page);

        return response()->json([
            'workOrder' => $workOrders,
        ]);
    }

    /**
     * Get quotations for dropdown
     */
    public function getQuotations()
    {
        $quotations = productQuotationMaster::with('client')
            ->orderBy('id', 'desc')
            ->get()
            ->map(function ($quotation) {
                $customerName = $quotation->client ? $quotation->client->name : 'N/A';

                return [
                    'id' => $quotation->id,
                    'quotation_number' => $quotation->quotation_number,
                    'date' => $quotation->date,
                    'customer_name' => $customerName,
                    'label' => "QTN-{$quotation->quotation_number} - {$customerName} ({$quotation->date})",
                ];
            });

        return response()->json($quotations);
    }

    /**
     * Get quotation details with products
     */
    public function getQuotationDetails($id)
    {
        $quotation = productQuotationMaster::with('productQuotationDetails.attribute.product', 'productQuotationDetails.attribute.warehouse', 'client')
            ->findOrFail($id);

        return response()->json([
            'quotation' => $quotation,
            'details' => $quotation->productQuotationDetails->map(function ($detail) {
                $productName = ($detail->attribute && $detail->attribute->product)
                    ? $detail->attribute->product->name
                    : $detail->product_name;
                $sku = ($detail->attribute) ? $detail->attribute->sku : '';
                $stock = ($detail->attribute && $detail->attribute->warehouse)
                    ? $detail->attribute->warehouse->quantity
                    : 0;
                $unit = ($detail->attribute && $detail->attribute->unit)
                    ? $detail->attribute->unit->name
                    : '';

                return [
                    'product_id' => $detail->product_id,
                    'attribute_id' => $detail->attribute_id,
                    'product_name' => $productName,
                    'sku' => $sku,
                    'quantity' => $detail->quantity,
                    'price' => $detail->unit_price,
                    'stock' => $stock,
                    'unit' => $unit,
                ];
            }),
            'client' => $quotation->client,
            'payment_term' => $quotation->payment_term,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $request->validate([
            'date' => 'required|date',
            'quotation_id' => 'nullable|exists:product_quotation_masters,id',
            'client_id' => 'nullable|exists:clients,id',
            'total' => 'required|numeric',
            'grand_total' => 'required|numeric',
            'list' => 'required|array|min:1',
            'list.*.product_id' => 'required|exists:products,id',
            'list.*.attribute_id' => 'required|exists:product_attributes,id',
            'list.*.quantity' => 'required|numeric|min:0.01',
            'list.*.price' => 'required|numeric|min:0',
            'list.*.total' => 'required|numeric|min:0',
        ]);

        DB::transaction(function () use ($request) {
            // Generate work order number (wo-0001, wo-0002, ...)
            $lastOrder = WorkOrderMaster::orderBy('id', 'desc')->first();
            if ($lastOrder) {
                $lastNo = $lastOrder->work_order_no;
                $num = preg_match('/^wo-(\d+)$/i', $lastNo, $m) ? (int) $m[1] : ((int) preg_replace('/\D/', '', $lastNo) ?: 0);
                $workOrderNo = 'wo-'.sprintf('%04d', $num + 1);
            } else {
                $workOrderNo = 'wo-0001';
            }

            $total = $request->total;

            // Create work order master
            $workOrder = WorkOrderMaster::create([
                'work_order_no' => $workOrderNo,
                'date' => $request->date,
                'quotation_id' => $request->quotation_id,
                'client_id' => $request->client_id ?? ($request->quotation_id ? productQuotationMaster::find($request->quotation_id)->customer_id : null),
                'user_id' => Auth::id(),
                'total' => $total,
                'discount_first' => 0,
                'discount_second' => 0,
                'total_discount' => 0,
                'grand_total' => $request->grand_total,
                'status' => 'pending',
                'note' => $request->note ?? null,
                'payment_term' => $request->payment_term ?? null,
            ]);

            // Create work order details
            foreach ($request->list as $item) {
                WorkOrderDetail::create([
                    'work_order_master_id' => $workOrder->id,
                    'product_id' => $item['product_id'],
                    'attribute_id' => $item['attribute_id'],
                    'product_name' => $item['product_name'],
                    'quantity' => $item['quantity'],
                    'price' => $item['price'],
                    'discount' => $item['discount'] ?? 0,
                    'total_discount' => $item['discount'] ?? 0,
                    'total' => $item['total'],
                    'note' => $item['note'] ?? null,
                ]);
            }
        });

        return response()->json([
            'success' => 'Work Order created successfully',
        ]);
    }

    /**
     * Display the specified resource.
     */
    public function show($id)
    {
        $workOrder = WorkOrderMaster::with([
            'workOrderDetails' => function ($query) {
                $query->with('attribute.product', 'attribute.brand', 'attribute.color', 'attribute.size', 'attribute.origin', 'attribute.unit');
            },
            'quotation',
            'client',
            'user',
            'approval.assignments.user',
            'approval.history.user',
        ])
            ->findOrFail($id);

        // Check if current user has an approval assignment for this work order
        $userApprovalAssignment = null;
        if ($workOrder->approval) {
            $userApprovalAssignment = $workOrder->approval->assignments()
                ->where('user_id', Auth::id())
                ->first();
        }

        if (request()->wantsJson()) {
            return response()->json($workOrder);
        }

        return Inertia::render('WorkOrder/WorkOrderSingleView', [
            'workOrder' => $workOrder,
            'userApprovalAssignment' => $userApprovalAssignment ? [
                'approval_id' => $workOrder->approval->id,
                'assignment_id' => $userApprovalAssignment->id,
                'module_name' => 'WorkOrder',
                'reference_id' => $workOrder->work_order_no,
                'assignment_status' => $userApprovalAssignment->status,
                'is_final' => $userApprovalAssignment->is_final ?? false,
                'has_final_approver' => $workOrder->approval->assignments()->where('is_final', true)->exists(),
                'can_reassign' => ($userApprovalAssignment->status === 'approved' && ! $userApprovalAssignment->is_final && $workOrder->approval->status === 'pending') ||
                                  ($userApprovalAssignment->status === 'pending' && ! $userApprovalAssignment->is_final),
                'note' => $workOrder->approval->note,
                'history' => $workOrder->approval->history->map(function ($h) {
                    return [
                        'action' => $h->action,
                        'user' => $h->user->name ?? 'Unknown',
                        'comment' => $h->comment,
                        'created_at' => $h->created_at->format('Y-m-d H:i:s'),
                    ];
                }),
            ] : null,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, $id)
    {
        $request->merge([
            'client_id' => $request->input('client_id') ?: null,
            'quotation_id' => $request->input('quotation_id') ?: null,
        ]);

        $request->validate([
            'date' => 'required|date',
            'quotation_id' => 'nullable|exists:product_quotation_masters,id',
            'client_id' => 'nullable|exists:clients,id',
            'total' => 'required|numeric',
            'grand_total' => 'required|numeric',
            'list' => 'required|array|min:1',
            'list.*.product_id' => 'required|exists:products,id',
            'list.*.attribute_id' => 'required|exists:product_attributes,id',
            'list.*.quantity' => 'required|numeric|min:0.01',
            'list.*.price' => 'required|numeric|min:0',
            'list.*.total' => 'required|numeric|min:0',
        ]);

        DB::transaction(function () use ($request, $id) {
            $workOrder = WorkOrderMaster::findOrFail($id);

            $total = $request->total;

            // Update work order master
            $workOrder->update([
                'date' => $request->date,
                'quotation_id' => $request->quotation_id,
                'client_id' => $request->client_id,
                'total' => $total,
                'discount_first' => 0,
                'discount_second' => 0,
                'total_discount' => 0,
                'grand_total' => $request->grand_total,
                'note' => $request->note ?? null,
                'payment_term' => $request->payment_term ?? null,
            ]);

            // Delete existing details
            WorkOrderDetail::where('work_order_master_id', $id)->delete();

            // Create new details
            foreach ($request->list as $item) {
                WorkOrderDetail::create([
                    'work_order_master_id' => $workOrder->id,
                    'product_id' => $item['product_id'],
                    'attribute_id' => $item['attribute_id'],
                    'product_name' => $item['product_name'],
                    'quantity' => $item['quantity'],
                    'price' => $item['price'],
                    'discount' => $item['discount'] ?? 0,
                    'total_discount' => $item['discount'] ?? 0,
                    'total' => $item['total'],
                    'note' => $item['note'] ?? null,
                ]);
            }
        });

        return response()->json([
            'success' => 'Work Order updated successfully',
        ]);
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id)
    {
        WorkOrderMaster::findOrFail($id)->delete();

        return response()->json([
            'success' => 'Work Order deleted successfully',
        ]);
    }

    /**
     * Get merge data for editing (source work orders, date, note).
     */
    public function mergeEdit($id)
    {
        $merge = WorkOrderMerge::findOrFail($id);
        $sourceIds = $merge->source_work_order_ids ?? [];
        $sourceWorkOrders = WorkOrderMaster::with('client')
            ->whereIn('id', $sourceIds)
            ->orderBy('id')
            ->get();

        return response()->json([
            'merge' => [
                'id' => $merge->id,
                'merged_work_order_id' => $merge->merged_work_order_id,
                'source_work_order_ids' => $sourceIds,
            ],
            'merged_work_order' => [
                'date' => $merge->date ? $merge->date->format('Y-m-d') : ($merge->mergedWorkOrder?->date?->format('Y-m-d')),
                'note' => $merge->note ?? $merge->mergedWorkOrder?->note,
            ],
            'source_work_orders' => $sourceWorkOrders,
        ]);
    }

    /**
     * Update a merge: only update merge record (source work orders, date, note). No work order master/details.
     */
    public function mergeUpdate(Request $request, $id)
    {
        $request->validate([
            'work_order_ids' => 'required|array|min:1',
            'work_order_ids.*' => 'required|exists:work_order_masters,id',
            'date' => 'required|date',
            'note' => 'nullable|string',
        ]);

        $merge = WorkOrderMerge::findOrFail($id);
        $merge->update([
            'source_work_order_ids' => $request->work_order_ids,
            'date' => $request->date,
            'note' => $request->note ? trim($request->note) : null,
        ]);

        return response()->json([
            'success' => 'Merge updated successfully.',
        ]);
    }

    /**
     * Delete a merge record only. Does not touch work order master/details.
     */
    public function mergeDestroy($id)
    {
        WorkOrderMerge::findOrFail($id)->delete();

        return response()->json([
            'success' => 'Merge deleted successfully.',
        ]);
    }

    /**
     * Show the Work Order Merger page.
     */
    public function merge()
    {
        return Inertia::render('WorkOrder/WorkOrderMerge');
    }

    /**
     * Get list of work order merges (for merge list table).
     */
    public function mergeList(Request $request)
    {
        $perPage = $request->input('perPage', 10);
        $page = $request->input('page', 1);
        $search = $request->input('search', '');

        $query = WorkOrderMerge::with(['mergedWorkOrder'])
            ->orderBy('id', 'desc');

        if (! empty($search)) {
            $query->where(function ($q) use ($search) {
                $q->where('merge_work_order_no', 'like', '%'.$search.'%')
                    ->orWhereHas('mergedWorkOrder', function ($sub) use ($search) {
                        $sub->where('work_order_no', 'like', '%'.$search.'%');
                    });
            });
        }

        $merges = $query->paginate($perPage, ['*'], 'page', $page);

        $sourceNumbers = WorkOrderMaster::withoutGlobalScope('typeScope')
            ->whereIn('id', $merges->pluck('source_work_order_ids')->flatten()->unique()->values()->all())
            ->pluck('work_order_no', 'id');

        $items = $merges->getCollection()->map(function ($merge) use ($sourceNumbers) {
            $merged = $merge->mergedWorkOrder;
            $sourceNos = array_map(function ($id) use ($sourceNumbers) {
                return $sourceNumbers[$id] ?? '#'.$id;
            }, $merge->source_work_order_ids ?? []);

            $grandTotal = $merged
                ? (float) $merged->grand_total
                : $this->computeMergedGrandTotal($merge->source_work_order_ids ?? []);

            return [
                'id' => $merge->id,
                'merge_work_order_no' => $merge->merge_work_order_no ?? ('mwo-'.sprintf('%04d', $merge->id)),
                'merged_work_order_id' => $merge->merged_work_order_id,
                'merged_work_order_no' => $merged ? $merged->work_order_no : null,
                'merged_date' => $merge->date ?? $merged?->date,
                'merged_grand_total' => $grandTotal,
                'source_work_order_nos' => $sourceNos,
                'source_work_order_ids' => $merge->source_work_order_ids ?? [],
                'created_at' => $merge->created_at ? $merge->created_at->format('Y-m-d H:i:s') : null,
            ];
        });

        return response()->json([
            'mergeList' => [
                'data' => $items,
                'total' => $merges->total(),
                'current_page' => $merges->currentPage(),
                'per_page' => $merges->perPage(),
            ],
        ]);
    }

    /**
     * Compute grand total of merged lines for given source work order IDs (same logic as mergePreview).
     */
    private function computeMergedGrandTotal(array $sourceWorkOrderIds): float
    {
        if (count($sourceWorkOrderIds) < 1) {
            return 0.0;
        }

        $workOrders = WorkOrderMaster::withoutGlobalScope('typeScope')
            ->with(['workOrderDetails'])
            ->whereIn('id', $sourceWorkOrderIds)
            ->orderBy('id')
            ->get();

        $merged = [];
        foreach ($workOrders as $wo) {
            foreach ($wo->workOrderDetails as $detail) {
                $key = $detail->product_id.'_'.$detail->attribute_id;
                if (! isset($merged[$key])) {
                    $merged[$key] = [
                        'quantity' => (float) $detail->quantity,
                        'price' => (float) $detail->price,
                        'total' => round((float) $detail->quantity * (float) $detail->price, 2),
                    ];
                } else {
                    $merged[$key]['quantity'] += (float) $detail->quantity;
                    $merged[$key]['total'] = round($merged[$key]['quantity'] * $merged[$key]['price'], 2);
                }
            }
        }

        return round((float) array_sum(array_column($merged, 'total')), 2);
    }

    /**
     * Get merged preview (product lines with summed quantities) for selected work order IDs.
     */
    public function mergePreview(Request $request)
    {
        $ids = $request->input('ids', []);
        if (is_string($ids)) {
            $ids = array_filter(array_map('intval', explode(',', $ids)));
        }
        if (count($ids) < 1) {
            return response()->json(['merged' => [], 'grand_total' => 0]);
        }

        $workOrders = WorkOrderMaster::withoutGlobalScope('typeScope')
            ->with(['workOrderDetails'])
            ->whereIn('id', $ids)
            ->orderBy('id')
            ->get();

        $merged = [];
        foreach ($workOrders as $wo) {
            foreach ($wo->workOrderDetails as $detail) {
                $key = $detail->product_id.'_'.$detail->attribute_id;
                if (! isset($merged[$key])) {
                    $merged[$key] = [
                        'product_id' => $detail->product_id,
                        'attribute_id' => $detail->attribute_id,
                        'product_name' => $detail->product_name,
                        'quantity' => (float) $detail->quantity,
                        'price' => (float) $detail->price,
                        'total' => round((float) $detail->quantity * (float) $detail->price, 2),
                    ];
                } else {
                    $merged[$key]['quantity'] += (float) $detail->quantity;
                    $merged[$key]['total'] = round($merged[$key]['quantity'] * $merged[$key]['price'], 2);
                }
            }
        }

        $merged = array_values($merged);
        $grandTotal = array_sum(array_column($merged, 'total'));

        return response()->json([
            'merged' => $merged,
            'grand_total' => round($grandTotal, 2),
        ]);
    }

    /**
     * Merge multiple work orders into one (combine same product/attribute quantities).
     */
    public function mergeStore(Request $request)
    {
        $request->validate([
            'work_order_ids' => 'required|array|min:1',
            'work_order_ids.*' => 'required|exists:work_order_masters,id',
            'date' => 'required|date',
            'note' => 'nullable|string',
        ]);

        $workOrderIds = $request->work_order_ids;
        $workOrders = WorkOrderMaster::whereIn('id', $workOrderIds)->get();

        if ($workOrders->count() < 1) {
            return response()->json([
                'message' => 'At least one work order is required.',
            ], 422);
        }

        // Only create merge record. Do not create work order master or details.
        $lastMerge = WorkOrderMerge::orderBy('id', 'desc')->first();
        $mergeNo = $lastMerge && preg_match('/^mwo-(\d+)$/i', $lastMerge->merge_work_order_no ?? '', $m)
            ? 'mwo-'.sprintf('%04d', (int) $m[1] + 1)
            : 'mwo-0001';

        WorkOrderMerge::create([
            'merge_work_order_no' => $mergeNo,
            'merged_work_order_id' => null,
            'source_work_order_ids' => $workOrderIds,
            'date' => $request->date,
            'note' => $request->note ? trim($request->note) : null,
        ]);

        return response()->json([
            'success' => 'Merge saved successfully.',
        ]);
    }
}
