<?php

namespace App\Http\Controllers;

use App\Models\ResultProcess;
use App\Models\ResultProcessDetail;
use App\Models\ProductionPlan;
use App\Models\ProductionPlanDetail;
use App\Models\Company;
use App\Models\Department;
use App\Models\DeleteLog;
use App\Models\Process;
use App\Models\Asset;
use App\Models\Overhead;
use App\Models\CategoryEmployee;
use App\Models\Employee;
use App\Models\PenerimaanBahan;
use App\Models\PengeluaranBahan;
use App\Models\PengeluaranBahanDetail;
use App\Models\KasirPenerimaanBahan;
use App\Models\KasirPenerimaanBahanDetail;
use App\Models\KasirPengeluaranBahan;
use App\Models\KasirPengeluaranBahanDetail;
use App\Models\Periode;
use App\Models\Warehouse;
use App\Models\ItemUnit;
use App\Models\ItemDetail;
use App\Models\PurchaseInvoiceDetail;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Module;
use App\Http\Controllers\ProcessingResultProcessController;
use Carbon\Carbon;
use DB;
use Illuminate\Support\Facades\Log;

class ResultProcessController extends Controller
{
    public function index($dateStart, $dateEnd)
    {
        try {
            $resultProcesses = ResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse', 'machine' => function ($query) {
                $query->select('id', 'asset_name');
            }])->whereBetween('document_date', [$dateStart, $dateEnd])->get();
            $periods = Periode::all();
            foreach ($resultProcesses as $p) {
                $p->closed = Module::checkPeriodeBack($periods, $p->document_date);
            }
            return response()->json(["resultProcesses" => $resultProcesses, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Index Error', [
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => ResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse', 'machine' => function ($query) {
                    $query->select('id', 'asset_name');
                }])->get()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load result processes'], 500);
        }
    }

    public function pengeluaranBahanMetadata($dateStart, $dateEnd)
    {
        try {
            $pengeluaranBahans = PengeluaranBahan::with(['details.item', 'details.unit', 'plan', 'process', 'warehouse'])->whereBetween('document_date', [$dateStart, $dateEnd])->get();
            return response()->json(["pengeluaranBahans" => $pengeluaranBahans, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Pengeluaran Bahan Metadata Error', [
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => PengeluaranBahan::with(['details.item', 'details.unit', 'plan', 'process', 'warehouse'])->get()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load pengeluaran bahan metadata'], 500);
        }
    }

    public function show($id)
    {
        try {
            $resultProcess = ResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'machine' => function ($query) {
                $query->select('id', 'asset_name');
            }])->findOrFail($id);
            Log::info('Fetched Result Process', [
                'id' => $id,
                'data' => $resultProcess->toArray()
            ]);
            return response()->json($resultProcess);
        } catch (\Exception $e) {
            Log::error('Show Error', [
                'id' => $id,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => ResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'machine' => function ($query) {
                    $query->select('id', 'asset_name');
                }])->find($id)?->toArray() ?? []
            ]);
            return response()->json(['error' => 'Failed to load result process'], 500);
        }
    }

    public function store(Request $request)
    {
        try {
            $user = Auth::user();
            $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id, true) : [];
            $allDept = array_column($defaultDepartmentId, 'department_id');

            $categoryEmployeeCode = is_array($request->category_employee_code) ? ($request->category_employee_code[0] ?? null) : $request->category_employee_code;

            $employeeResult = $request->employee_result ?? [];
            if (!empty($employeeResult)) {
                foreach ($employeeResult as &$result) {
                    $result['category_employee_code'] = $result['category_employee_code'] ?? $categoryEmployeeCode;
                    $result['employee_id'] = (int) ($result['employee_id'] ?? 0);
                    $result['qty'] = (float) ($result['qty'] ?? 0);
                }
            }

            $overheadResult = $request->overhead_result ?? [];
            if (!empty($overheadResult)) {
                foreach ($overheadResult as &$result) {
                    $result['overhead_id'] = (int) ($result['overhead_id'] ?? 0);
                    $result['qty'] = (float) ($result['qty'] ?? 0);
                    $result['cost'] = (float) ($result['cost'] ?? 0);
                }
            }

            $details = $request->details ?? [];
            $pengeluaranBahanIds = [];
            $warehouseIds = [];
            // if (!empty($details)) {
            //     foreach ($details as &$detail) {
            //         $detail['pengeluaran_bahan_detail_id'] = (int) ($detail['pengeluaran_bahan_detail_id'] ?? 0);
            //         $detail['item_id'] = (int) ($detail['item_id'] ?? 0);
            //         $detail['qty'] = (float) ($detail['qty'] ?? 0);
            //         $detail['unit'] = (int) ($detail['unit'] ?? 0);
            //         $pengeluaranBahanDetail = PengeluaranBahanDetail::find($detail['pengeluaran_bahan_detail_id']);
            //         if ($pengeluaranBahanDetail) {
            //             $pengeluaranBahan = PengeluaranBahan::find($pengeluaranBahanDetail->pengeluaran_bahan_id);
            //             if ($pengeluaranBahan && $pengeluaranBahan->warehouse_id) {
            //                 $pengeluaranBahanIds[] = $pengeluaranBahan->id;
            //                 $warehouseIds[] = $pengeluaranBahan->warehouse_id;
            //             } else {
            //                 Log::warning('No PengeluaranBahan or warehouse_id found for pengeluaran_bahan_detail_id', [
            //                     'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id']
            //                 ]);
            //                 return response()->json(['errors' => ['details' => 'No PengeluaranBahan or warehouse_id found for pengeluaran_bahan_detail_id: ' . $detail['pengeluaran_bahan_detail_id']]], 422);
            //             }
            //         } else {
            //             Log::warning('Invalid pengeluaran_bahan_detail_id', [
            //                 'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id']
            //             ]);
            //             return response()->json(['errors' => ['details' => 'Invalid pengeluaran_bahan_detail_id: ' . $detail['pengeluaran_bahan_detail_id']]], 422);
            //         }
            //     }
            // }
            // $pengeluaranBahanIds = array_unique($pengeluaranBahanIds);
            // $warehouseIds = array_unique($warehouseIds);
            // if (count($warehouseIds) > 1) {
            //     Log::warning('Multiple warehouse_ids detected in details', [
            //         'warehouse_ids' => $warehouseIds
            //     ]);
            //     return response()->json(['errors' => ['details' => 'All details must reference the same warehouse_id']], 422);
            // }
            //$warehouseId = !empty($warehouseIds) ? $warehouseIds[0] : null;

            $validator = Validator::make(array_merge($request->all(), [
                'category_employee_code' => $categoryEmployeeCode,
                'employee_result' => $employeeResult,
                'overhead_result' => $overheadResult,
                'details' => $details,
                'document_date' => $request->document_date
            ]), [
                'plan_id' => 'required|integer|exists:production_plans,id',
                'process_id' => 'required|integer|exists:process,id',
                'machine' => 'nullable|integer|exists:assets,id',
                'kwh_consumption' => 'required|numeric|min:0',
                'employee_result' => 'nullable|array',
                'employee_result.*.employee_id' => 'required|integer|exists:employees,id',
                'employee_result.*.qty' => 'required|numeric|min:0',
                'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'overhead_result' => 'nullable|array',
                'overhead_result.*.overhead_id' => 'required|integer|exists:overheads,id',
                'overhead_result.*.qty' => 'required|numeric|min:0',
                'overhead_result.*.cost' => 'required|numeric|min:0',
                'details' => 'required|array|min:1',
                'details.*.kasir_pengeluaran_bahan_detail_id' => 'nullable|integer|exists:kasir_pengeluaran_bahan_detail,id',
                'details.*.pengeluaran_bahan_detail_id' => 'nullable|integer|exists:pengeluaran_bahan_detail,id',
                'details.*.item_id' => 'required|integer|exists:items,id',
                'details.*.qty' => 'required|numeric|min:0',
                'details.*.unit' => 'required|integer|exists:item_units,id',
                'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'document_date' => 'required|date',
                'warehouse_id' => 'required|integer|exists:warehouse,id',
            ]);

            if ($validator->fails()) {
                Log::warning('Validation failed for ResultProcess store', [
                    'errors' => $validator->errors(),
                    'request' => $request->all()
                ]);
                return response()->json(['errors' => $validator->errors()], 422);
            }

            if ($request->machine) {
                $asset = Asset::join('category_assets', 'assets.category_asset_id', '=', 'category_assets.id')
                    ->where('assets.id', $request->machine)
                    ->where('category_assets.category_asset_code', 'MAC001')
                    ->first();
                if (!$asset) {
                    Log::warning('Invalid machine category', [
                        'machine_id' => $request->machine,
                        'category_asset_code' => 'MAC001'
                    ]);
                    return response()->json(['errors' => ['machine' => 'Selected machine must have category MAC001']], 422);
                }
            }

            if ($categoryEmployeeCode && !empty($employeeResult)) {
                $category = CategoryEmployee::where('category_employee_code', $categoryEmployeeCode)->first();
                if ($category) {
                    $validEmployeeIds = Employee::where('category_employee', $categoryEmployeeCode)->pluck('id')->toArray();
                    foreach ($employeeResult as $er) {
                        if (!in_array($er['employee_id'], $validEmployeeIds)) {
                            Log::warning('Invalid employee for category', [
                                'employee_id' => $er['employee_id'],
                                'category_employee_code' => $categoryEmployeeCode
                            ]);
                            return response()->json(['errors' => ['employee_result' => 'All employees must belong to the selected category: ' . $categoryEmployeeCode]], 422);
                        }
                        if ($er['category_employee_code'] !== $categoryEmployeeCode) {
                            Log::warning('Category mismatch in employee_result', [
                                'employee_id' => $er['employee_id'],
                                'category_employee_code' => $er['category_employee_code'],
                                'expected' => $categoryEmployeeCode
                            ]);
                            return response()->json(['errors' => ['employee_result' => 'Category employee code in employee_result must match selected category: ' . $categoryEmployeeCode]], 422);
                        }
                    }
                } else {
                    Log::warning('Invalid category employee code', [
                        'category_employee_code' => $categoryEmployeeCode
                    ]);
                    return response()->json(['errors' => ['category_employee_code' => 'Invalid category employee code']], 422);
                }
            }

            if (!empty($overheadResult)) {
                $validOverheadIds = Overhead::pluck('id')->toArray();
                foreach ($overheadResult as $or) {
                    if (!in_array($or['overhead_id'], $validOverheadIds)) {
                        Log::warning('Invalid overhead ID', [
                            'overhead_id' => $or['overhead_id']
                        ]);
                        return response()->json(['errors' => ['overhead_result' => 'Invalid overhead ID: ' . $or['overhead_id']]], 422);
                    }
                }
            }

            DB::beginTransaction();
            $company = Company::first();
            $department = Department::first();
            if (!$company || !$department) {
                Log::error('Company or Department not found', [
                    'company' => $company,
                    'department' => $department
                ]);
                DB::rollback();
                return response()->json(['error' => 'Company or Department not found'], 500);
            }

            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, Carbon::parse($request->document_date)->month, Carbon::parse($request->document_date)->year, "RP", 1);
            if (!$nobukti) {
                Log::error('Failed to generate document number', [
                    'company_code' => $company->companyCode,
                    'department_code' => $department->department_code,
                    'month' => Carbon::parse($request->document_date)->month,
                    'year' => Carbon::parse($request->document_date)->year
                ]);
                DB::rollback();
                return response()->json(['error' => 'Failed to generate document number'], 500);
            }

            $resultProcess = ResultProcess::create([
                'result_process_id' => $nobukti,
                'document_date' => $request->document_date,
                'plan_id' => $request->plan_id,
                'process_id' => $request->process_id,
                'machine' => $request->machine ? (int) $request->machine : null,
                'employee_result' => json_encode($employeeResult),
                'overhead_result' => json_encode($overheadResult),
                'kwh_consumption' => (float) $request->kwh_consumption,
                'pengeluaran_bahan_ids' => json_encode($pengeluaranBahanIds),
                'warehouse_id' => $request->warehouse_id,
                'created_by' => auth()->id(),
                'updated_by' => auth()->id(),
            ]);

            $existingResult = ResultProcess::where('plan_id', $request->plan_id)
                ->where('process_id', $request->process_id)
                ->where('id', '!=', $resultProcess->id)
                ->exists();

            if (!$existingResult) {
                ProductionPlanDetail::where('plan_id', $request->plan_id)
                    ->where('process_id', $request->process_id)
                    ->update(['status' => 'Completed', 'completed_at' => $resultProcess->document_date]);
            }

            foreach ($details as $detail) {
                ResultProcessDetail::create([
                    'result_process_id' => $resultProcess->id,
                    'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id'],
                    'kasir_pengeluaran_bahan_detail_id' => $detail['kasir_pengeluaran_bahan_detail_id'],
                    'item_id' => $detail['item_id'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'created_by' => auth()->id(),
                    'updated_by' => auth()->id(),
                ]);
            }

            $allDetailsCompleted = ProductionPlanDetail::where('plan_id', $request->plan_id)
                ->where('status', '!=', 'Completed')
                ->doesntExist();

            if ($allDetailsCompleted) {
                ProductionPlan::where('id', $request->plan_id)
                    ->update(['status' => 'Completed', 'completed_at' => $resultProcess->document_date]);
            } else {
                ProductionPlan::where('id', $request->plan_id)
                    ->update(['status' => 'On Progress', 'completed_at' => null]);
            }

            DB::commit();
            return response()->json(null);
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Store Error', [
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'request' => $request->all()
            ]);
            return response()->json(['error' => 'Failed to create result process: ' . $e->getMessage()], 500);
        }
    }

    public function update(Request $request, $id)
    {
        try {
            $resultProcess = ResultProcess::findOrFail($id);

            $user = Auth::user();
            $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id, true) : [];
            $allDept = array_column($defaultDepartmentId, 'department_id');

            $categoryEmployeeCode = is_array($request->category_employee_code) ? ($request->category_employee_code[0] ?? null) : $request->category_employee_code;

            $employeeResult = $request->employee_result ?? [];
            if (!empty($employeeResult)) {
                foreach ($employeeResult as &$result) {
                    $result['category_employee_code'] = $result['category_employee_code'] ?? $categoryEmployeeCode;
                    $result['employee_id'] = (int) ($result['employee_id'] ?? 0);
                    $result['qty'] = (float) ($result['qty'] ?? 0);
                }
            }

            $overheadResult = $request->overhead_result ?? [];
            if (!empty($overheadResult)) {
                foreach ($overheadResult as &$result) {
                    $result['overhead_id'] = (int) ($result['overhead_id'] ?? 0);
                    $result['qty'] = (float) ($result['qty'] ?? 0);
                    $result['cost'] = (float) ($result['cost'] ?? 0);
                }
            }

            $details = $request->details ?? [];
            $pengeluaranBahanIds = [];
            $warehouseIds = [];
            // if (!empty($details)) {
            //     foreach ($details as &$detail) {
            //         $detail['pengeluaran_bahan_detail_id'] = (int) ($detail['pengeluaran_bahan_detail_id'] ?? 0);
            //         $detail['item_id'] = (int) ($detail['item_id'] ?? 0);
            //         $detail['qty'] = (float) ($detail['qty'] ?? 0);
            //         $detail['unit'] = (int) ($detail['unit'] ?? 0);
            //         $pengeluaranBahanDetail = PengeluaranBahanDetail::find($detail['pengeluaran_bahan_detail_id']);
            //         if ($pengeluaranBahanDetail) {
            //             $pengeluaranBahan = PengeluaranBahan::find($pengeluaranBahanDetail->pengeluaran_bahan_id);
            //             if ($pengeluaranBahan && $pengeluaranBahan->warehouse_id) {
            //                 $pengeluaranBahanIds[] = $pengeluaranBahan->id;
            //                 $warehouseIds[] = $pengeluaranBahan->warehouse_id;
            //             } else {
            //                 Log::warning('No PengeluaranBahan or warehouse_id found for pengeluaran_bahan_detail_id', [
            //                     'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id']
            //                 ]);
            //                 return response()->json(['errors' => ['details' => 'No PengeluaranBahan or warehouse_id found for pengeluaran_bahan_detail_id: ' . $detail['pengeluaran_bahan_detail_id']]], 422);
            //             }
            //         } else {
            //             Log::warning('Invalid pengeluaran_bahan_detail_id', [
            //                 'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id']
            //             ]);
            //             return response()->json(['errors' => ['details' => 'Invalid pengeluaran_bahan_detail_id: ' . $detail['pengeluaran_bahan_detail_id']]], 422);
            //         }
            //     }
            // }
            // $pengeluaranBahanIds = array_unique($pengeluaranBahanIds);
            // $warehouseIds = array_unique($warehouseIds);
            // if (count($warehouseIds) > 1) {
            //     Log::warning('Multiple warehouse_ids detected in details', [
            //         'warehouse_ids' => $warehouseIds
            //     ]);
            //     return response()->json(['errors' => ['details' => 'All details must reference the same warehouse_id']], 422);
            // }
            $warehouseId = !empty($warehouseIds) ? $warehouseIds[0] : null;

            $validator = Validator::make(array_merge($request->all(), [
                'category_employee_code' => $categoryEmployeeCode,
                'employee_result' => $employeeResult,
                'overhead_result' => $overheadResult,
                'details' => $details,
                'document_date' => $request->document_date
            ]), [
                'plan_id' => 'required|integer|exists:production_plans,id',
                'process_id' => 'required|integer|exists:process,id',
                'machine' => 'nullable|integer|exists:assets,id',
                'kwh_consumption' => 'required|numeric|min:0',
                'employee_result' => 'nullable|array',
                'employee_result.*.employee_id' => 'required|integer|exists:employees,id',
                'employee_result.*.qty' => 'required|numeric|min:0',
                'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'overhead_result' => 'nullable|array',
                'overhead_result.*.overhead_id' => 'required|integer|exists:overheads,id',
                'overhead_result.*.qty' => 'required|numeric|min:0',
                'overhead_result.*.cost' => 'required|numeric|min:0',
                'details' => 'required|array|min:1',
                'details.*.kasir_pengeluaran_bahan_detail_id' => 'nullable|integer|exists:kasir_pengeluaran_bahan_detail,id',
                'details.*.pengeluaran_bahan_detail_id' => 'nullable|integer|exists:pengeluaran_bahan_detail,id',
                'details.*.item_id' => 'required|integer|exists:items,id',
                'details.*.qty' => 'required|numeric|min:0',
                'details.*.unit' => 'required|integer|exists:item_units,id',
                'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'document_date' => 'required|date',
                'warehouse_id' => 'required|integer|exists:warehouse,id',
            ]);

            if ($validator->fails()) {
                Log::warning('Validation failed for ResultProcess update', [
                    'id' => $id,
                    'errors' => $validator->errors(),
                    'request' => $request->all()
                ]);
                return response()->json(['errors' => $validator->errors()], 422);
            }

            if ($request->machine) {
                $asset = Asset::join('category_assets', 'assets.category_asset_id', '=', 'category_assets.id')
                    ->where('assets.id', $request->machine)
                    ->where('category_assets.category_asset_code', 'MAC001')
                    ->first();
                if (!$asset) {
                    Log::warning('Invalid machine category', [
                        'machine_id' => $request->machine,
                        'category_asset_code' => 'MAC001'
                    ]);
                    return response()->json(['errors' => ['machine' => 'Selected machine must have category MAC001']], 422);
                }
            }

            if ($categoryEmployeeCode && !empty($employeeResult)) {
                $category = CategoryEmployee::where('category_employee_code', $categoryEmployeeCode)->first();
                if ($category) {
                    $validEmployeeIds = Employee::where('category_employee', $categoryEmployeeCode)->pluck('id')->toArray();
                    foreach ($employeeResult as $er) {
                        if (!in_array($er['employee_id'], $validEmployeeIds)) {
                            Log::warning('Invalid employee for category', [
                                'employee_id' => $er['employee_id'],
                                'category_employee_code' => $categoryEmployeeCode
                            ]);
                            return response()->json(['errors' => ['employee_result' => 'All employees must belong to the selected category: ' . $categoryEmployeeCode]], 422);
                        }
                        if ($er['category_employee_code'] !== $categoryEmployeeCode) {
                            Log::warning('Category mismatch in employee_result', [
                                'employee_id' => $er['employee_id'],
                                'category_employee_code' => $er['category_employee_code'],
                                'expected' => $categoryEmployeeCode
                            ]);
                            return response()->json(['errors' => ['employee_result' => 'Category employee code in employee_result must match selected category: ' . $categoryEmployeeCode]], 422);
                        }
                    }
                } else {
                    Log::warning('Invalid category employee code', [
                        'category_employee_code' => $categoryEmployeeCode
                    ]);
                    return response()->json(['errors' => ['category_employee_code' => 'Invalid category employee code']], 422);
                }
            }

            if (!empty($overheadResult)) {
                $validOverheadIds = Overhead::pluck('id')->toArray();
                foreach ($overheadResult as $or) {
                    if (!in_array($or['overhead_id'], $validOverheadIds)) {
                        Log::warning('Invalid overhead ID', [
                            'overhead_id' => $or['overhead_id']
                        ]);
                        return response()->json(['errors' => ['overhead_result' => 'Invalid overhead ID: ' . $or['overhead_id']]], 422);
                    }
                }
            }

            DB::beginTransaction();
            $resultProcess->update([
                'plan_id' => $request->plan_id,
                'process_id' => $request->process_id,
                'machine' => $request->machine ? (int) $request->machine : null,
                'employee_result' => json_encode($employeeResult),
                'overhead_result' => json_encode($overheadResult),
                'kwh_consumption' => (float) $request->kwh_consumption,
                'pengeluaran_bahan_ids' => json_encode($pengeluaranBahanIds),
                'warehouse_id' => $request->warehouse_id,
                'document_date' => $request->document_date,
                'updated_by' => auth()->id(),
            ]);

            $existingResult = ResultProcess::where('plan_id', $request->plan_id)
                ->where('process_id', $request->process_id)
                ->where('id', '!=', $resultProcess->id)
                ->exists();

            if (!$existingResult) {
                ProductionPlanDetail::where('plan_id', $request->plan_id)
                    ->where('process_id', $request->process_id)
                    ->update(['status' => 'Completed', 'completed_at' => $resultProcess->document_date]);
            }

            $resultProcess->details()->delete();

            foreach ($details as $detail) {
                ResultProcessDetail::create([
                    'result_process_id' => $resultProcess->id,
                    'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id'],
                    'item_id' => $detail['item_id'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'created_by' => $resultProcess->created_by,
                    'updated_by' => auth()->id(),
                ]);
            }

            $allDetailsCompleted = ProductionPlanDetail::where('plan_id', $request->plan_id)
                ->where('status', '!=', 'Completed')
                ->doesntExist();

            if ($allDetailsCompleted) {
                ProductionPlan::where('id', $request->plan_id)
                    ->update(['status' => 'Completed', 'completed_at' => $resultProcess->document_date]);
            } else {
                ProductionPlan::where('id', $request->plan_id)
                    ->update(['status' => 'On Progress', 'completed_at' => null]);
            }

            DB::commit();
            Log::info('Result Process Updated Successfully', [
                'result_process_id' => $resultProcess->id,
                'pengeluaran_bahan_ids' => $pengeluaranBahanIds,
                'warehouse_id' => $warehouseId,
                'data' => $resultProcess->toArray()
            ]);
            return response()->json($resultProcess->load('details'));
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Update Error', [
                'id' => $id,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'request' => $request->all()
            ]);
            return response()->json(['error' => 'Failed to update result process: ' . $e->getMessage()], 500);
        }
    }

    public function destroy(Request $request, $id)
    {
        try {
            DB::beginTransaction();
            $resultProcess = ResultProcess::findOrFail($id);

            $existingResult = ResultProcess::where('plan_id', $resultProcess->plan_id)
                ->where('process_id', $resultProcess->process_id)
                ->where('id', '!=', $resultProcess->id)
                ->exists();

            if (!$existingResult) {
                Log::info('Updating Production Plan Status', [
                    'id' => $id,
                    'plan_id' => $resultProcess->plan_id,
                    'process_id' => $resultProcess->process_id,
                    'status' => 'On Progress',
                    'data' => ProductionPlanDetail::where('plan_id', $resultProcess->plan_id)->where('process_id', $resultProcess->process_id)->get()->toArray()
                ]);
                ProductionPlanDetail::where('plan_id', $resultProcess->plan_id)
                    ->where('process_id', $resultProcess->process_id)
                    ->update(['status' => 'On Progress', 'completed_at' => null]);
                ProductionPlan::where('id', $resultProcess->plan_id)
                    ->update(['status' => 'On Progress', 'completed_at' => null]);
            }

            $resultProcess->details()->delete();
            $resultProcess->delete();

            DeleteLog::create([
                'document_number' => $resultProcess->result_process_id,
                'document_date' => $resultProcess->document_date,
                'delete_notes' => $request->input('delete_notes', 'No notes provided'),
                'company_code' => null,
                'department_code' => null,
                'deleted_by' => Auth::check() ? Auth::user()->name : 'system',
                'type' => 'Result Process',
            ]);

            DB::commit();
            Log::info('Destroy Completed Successfully', [
                'id' => $id,
                'user_id' => auth()->id(),
                'data' => $resultProcess->toArray()
            ]);
            return response()->json(null, 204);
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Destroy Error', [
                'id' => $id,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => ResultProcess::find($id)?->toArray() ?? []
            ]);
            return response()->json(['error' => 'Failed to delete result process: ' . $e->getMessage()], 500);
        }
    }

    public function getMasterData()
    {
        try {
            $user = Auth::user();
            $Listdepartment = $this->getDepartment();
            $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id, true) : [];
            $allDept = array_column($defaultDepartmentId, 'department_id');
            $plans = ProductionPlan::with([
                'item',
                'unit',
                'details.process',
                'createdBy',
                'updatedBy',
                'penerimaanBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'pengeluaranBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                }
            ])
            ->whereIn('department_id',$Listdepartment)
            ->where("status","<>","Completed")
                ->orderBy('plan_id')
                ->get();
            $assets = Asset::all();
            $machines = Asset::join('category_assets', 'assets.category_asset_id', '=', 'category_assets.id')
                ->where('category_assets.category_asset_code', 'MAC001')
                ->select('assets.*')
                ->get();
            $categoryEmployees = CategoryEmployee::all();
            $employees = Employee::all();
            $processes = Process::all();
            $itemUnits = ItemUnit::get();
            // $penerimaanBahans = PenerimaanBahan::with(['details.item', 'details.unit', 'plan', 'process'])->get();
            // $pengeluaranBahans = PengeluaranBahan::with(['details.item', 'details.unit', 'plan', 'process'])->get();
            $overhead = Overhead::all();
            $company = Company::first();
            $department = Department::first();
            $date = Carbon::now();
            $gudangUser = DB::table("user_warehouse")->where("user_id",Auth::user()->id)->select("warehouse_id")->get()->pluck("warehouse_id")->toArray();
            $warehouses = Warehouse::whereIn("id",$gudangUser)->get();
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "RP", 0);

            return response()->json([
                'assets' => $assets,
                'machines' => $machines,
                'overheads' => $overhead,
                'category_employees' => $categoryEmployees,
                'nobukti' => $nobukti,
                'employees' => $employees,
                'processes' => $processes,
                // 'penerimaan_bahans' => $penerimaanBahans,
                // 'pengeluaran_bahans' => $pengeluaranBahans,
                'item_units' => $itemUnits,
                'warehouses' => $warehouses,
                'plans' => $plans,
                'role' => $this->getRole(),
            ]);
        } catch (\Exception $e) {
            Log::error('Master Data Error', [
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => [
                    'machines' => Asset::join('category_assets', 'assets.category_asset_id', '=', 'category_assets.id')
                        ->where('category_assets.category_asset_code', 'MAC001')
                        ->select('assets.*')
                        ->get()->toArray(),
                    'category_employees' => CategoryEmployee::all()->toArray(),
                    'penerimaan_bahans' => PenerimaanBahan::with(['details.item', 'details.unit', 'plan', 'process'])->get()->toArray(),
                    'pengeluaran_bahans' => PengeluaranBahan::with(['details.item', 'details.unit', 'plan', 'process'])->get()->toArray()
                ]
            ]);
            return response()->json(['error' => 'Failed to load master data: ' . $e->getMessage()], 500);
        }
    }

    public function getProductionPlans()
    {
        try {
            $productionPlans = ProductionPlan::with(["item"])->whereIn('status', ['Pending', 'On Progress'])->get();
            return response()->json($productionPlans);
        } catch (\Exception $e) {
            Log::error('Production Plans Error', [
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => ProductionPlan::all()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load production plans: ' . $e->getMessage()], 500);
        }
    }

    public function getProcessesForPlan($planId)
    {
        try {
            if (!is_numeric($planId) || $planId <= 0) {
                Log::warning('Invalid Plan ID', [
                    'plan_id' => $planId,
                    'data' => []
                ]);
                return response()->json(['error' => 'Invalid plan_id'], 400);
            }
            $processes = ProductionPlanDetail::with('process')
                ->where('plan_id', $planId)
                ->get()
                ->pluck('process')
                ->filter();
            Log::info('Fetched Processes for Plan', [
                'plan_id' => $planId,
                'count' => $processes->count(),
                'data' => $processes->toArray()
            ]);
            return response()->json($processes);
        } catch (\Exception $e) {
            Log::error('Processes for Plan Error', [
                'plan_id' => $planId,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => ProductionPlanDetail::with('process')->where('plan_id', $planId)->get()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load processes: ' . $e->getMessage()], 500);
        }
    }

    public function getItemsForProcessAndPlan($planId, $processId)
    {
        try {
            if (!is_numeric($planId) || $planId <= 0 || !is_numeric($processId) || $processId <= 0) {
                Log::warning('Invalid Plan or Process ID', [
                    'plan_id' => $planId,
                    'process_id' => $processId,
                    'data' => []
                ]);
                return response()->json(['error' => 'Invalid plan_id or process_id'], 400);
            }
            $kasirpengeluaranBahans = DB::table("kasir_pengeluaran_bahan_detail as x")
            ->join("kasir_pengeluaran_bahan as y","y.id","=","x.kasir_pengeluaran_bahan_id")
            ->join("items as i","i.id","=","x.item_id")
            ->where('y.plan_id', $planId)
            ->where('y.process_id', $processId)
            ->select(DB::raw("cast(null as bigint) as pengeluaran_bahan_detail_id"),"x.id as kasir_pengeluaran_bahan_detail_id","x.item_id","i.item_code","i.item_name","x.unit","x.qty");

            $pengeluaranBahans = DB::table("pengeluaran_bahan_detail as x")
            ->join("pengeluaran_bahan as y","y.id","=","x.pengeluaran_bahan_id")
            ->join("items as i","i.id","=","x.item_id")
            ->where('y.plan_id', $planId)
            ->where('y.process_id', $processId)
            ->select("x.id as pengeluaran_bahan_detail_id",DB::raw("cast(null as bigint) as kasir_pengeluaran_bahan_detail_id"),"x.item_id","i.item_code","i.item_name","x.unit","x.qty")
            ->union($kasirpengeluaranBahans)
            ->get();
            // $pengeluaranBahans = PengeluaranBahan::with(['details.item', 'details.unit'])
            //     ->where('plan_id', $planId)
            //     ->where('process_id', $processId)
            //     ->get();
            $details = $pengeluaranBahans->map(function ($pengeluaranBahan) {
                return [
                    'pengeluaran_bahan_detail_id' => $pengeluaranBahan->pengeluaran_bahan_detail_id,
                    'kasir_pengeluaran_bahan_detail_id' => $pengeluaranBahan->kasir_pengeluaran_bahan_detail_id,
                    'item_id' => $pengeluaranBahan->item_id,
                    'item_code' => $pengeluaranBahan->item_code,
                    'item_name' => $pengeluaranBahan->item_name,
                    'qty' => $pengeluaranBahan->qty,
                    'unit' => $pengeluaranBahan->unit,
                ];
            });
            return response()->json($details);
        } catch (\Exception $e) {
            Log::error('Items for Process and Plan Error', [
                'plan_id' => $planId,
                'process_id' => $processId,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => PengeluaranBahan::with(['details.item', 'details.unit'])
                    ->where('plan_id', $planId)
                    ->where('process_id', $processId)
                    ->get()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load items: ' . $e->getMessage()], 500);
        }
    }

    public function getEmployeesForCategory($categoryCode)
    {
        try {
            if (empty($categoryCode)) {
                Log::warning('Empty category_employee_code provided', [
                    'category_code' => $categoryCode,
                    'data' => []
                ]);
                return response()->json(['error' => 'Invalid category_employee_code'], 400);
            }
            Log::info('Fetching employees for category_code: ' . $categoryCode);
            $category = CategoryEmployee::whereRaw('LOWER(category_employee_code) = ?', [strtolower($categoryCode)])->first();
            if (!$category) {
                Log::warning('Category not found for code: ' . $categoryCode, [
                    'data' => CategoryEmployee::whereRaw('LOWER(category_employee_code) = ?', [strtolower($categoryCode)])->get()->toArray()
                ]);
                return response()->json(['error' => 'Category not found for code: ' . $categoryCode], 404);
            }
            $employees = Employee::where('category_employee', $category->category_employee_code)->get();
            if ($employees->isEmpty()) {
                Log::warning('No employees found for category: ' . $categoryCode, [
                    'category_id' => $category->id,
                    'data' => $employees->toArray()
                ]);
            }
            Log::info('Found employees for category', [
                'category_code' => $categoryCode,
                'count' => $employees->count(),
                'data' => $employees->toArray()
            ]);
            return response()->json($employees);
        } catch (\Exception $e) {
            Log::error('Employees for Category Error', [
                'category_code' => $categoryCode,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'data' => Employee::where('category_employee', $categoryCode)->get()->toArray()
            ]);
            return response()->json(['error' => 'Failed to load employees: ' . $e->getMessage()], 500);
        }
    }

    public function cogmProduction($date)
    {
        try {
            $selectedDate = Carbon::parse($date)->endOfDay();
            $periods = Periode::all();

            $processingController = new ProcessingResultProcessController();
            $cogmProcessingResponse = $processingController->cogmProcessing($date);
            if ($cogmProcessingResponse->getStatusCode() !== 200) {
                throw new \Exception('Failed to fetch COGM Processing data');
            }
            $cogmProcessingData = json_decode($cogmProcessingResponse->getContent(), true);
            $cogmProcessingDetails = $cogmProcessingData['cogmProcessingDetails'] ?? [];

            $avgCogmByItem = [];
            foreach ($cogmProcessingDetails as $planResultItem => $details) {
                $totalQty = array_sum(array_column($details, 'qty'));
                $totalCogm = array_sum(array_column($details, 'cogm'));
                $avgCogmByItem[$planResultItem] = $totalQty > 0 ? $totalCogm / $totalQty : 0;
            }

            $itemDetails = ItemDetail::with('item')->select('item_id', 'unit_id')->get()->keyBy(fn($item) => "{$item->item_id}-{$item->unit_id}");
            $itemUnits = ItemUnit::select('id', 'unit_name')->get()->keyBy('id');
            $warehouses = Warehouse::select('id', 'warehouse_name')->get()->keyBy('id');
            $plans = ProductionPlan::with(['item' => fn($query) => $query->select('id', 'item_name')])->select('id', 'plan_id', 'item_id', 'status')->get()->keyBy('id');
            $processes = Process::select('id', 'process_name')->get()->keyBy('id');
            $purchaseInvoiceDetails = PurchaseInvoiceDetail::select('item_id', 'unit', 'price')->get()->keyBy(fn($item) => "{$item->item_id}-{$item->unit}");

            $penerimaanQuery = DB::table('penerimaan_bahan as pb')
                ->join('penerimaan_bahan_detail as pbd', 'pb.id', '=', 'pbd.penerimaan_bahan_id')
                ->join('items as i', 'pbd.item_id', '=', 'i.id')
                ->join('item_units as iu', function ($join) {
                    $join->on(DB::raw('pbd.unit::bigint'), '=', 'iu.id');
                })
                ->join('production_plans as pp', 'pb.plan_id', '=', 'pp.id')
                ->join('process as pr', 'pb.process_id', '=', 'pr.id')
                ->join('warehouse as w', 'pb.warehouse_id', '=', 'w.id')
                ->select(
                    'pb.document_date',
                    'pb.plan_id',
                    'pb.process_id',
                    'pb.warehouse_id',
                    'pbd.item_id',
                    'pbd.unit as unit_id',
                    DB::raw('SUM(pbd.qty) as total_qty'),
                    'i.item_name',
                    'iu.unit_name',
                    'w.warehouse_name',
                    'pp.item_id as plan_item_id',
                    'pp.plan_id as plan_code',
                    'pp.status as plan_status',
                    'pr.process_name'
                )
                ->where('pb.document_date', '<=', $selectedDate)
                ->groupBy('pb.document_date', 'pb.plan_id', 'pb.process_id', 'pb.warehouse_id', 'pbd.item_id', 'pbd.unit', 'i.item_name', 'iu.unit_name', 'w.warehouse_name', 'pp.item_id', 'pp.plan_id', 'pp.status', 'pr.process_name');

            $kasirPenerimaanQuery = DB::table('kasir_penerimaan_bahan as kpb')
                ->join('kasir_penerimaan_bahan_detail as kpbd', 'kpb.id', '=', 'kpbd.kasir_penerimaan_bahan_id')
                ->join('items as i', 'kpbd.item_id', '=', 'i.id')
                ->join('item_units as iu', function ($join) {
                    $join->on(DB::raw('kpbd.unit::bigint'), '=', 'iu.id');
                })
                ->join('production_plans as pp', 'kpb.plan_id', '=', 'pp.id')
                ->join('process as pr', 'kpb.process_id', '=', 'pr.id')
                ->join('warehouse as w', 'kpb.warehouse_id', '=', 'w.id')
                ->select(
                    'kpb.document_date',
                    'kpb.plan_id',
                    'kpb.process_id',
                    'kpb.warehouse_id',
                    'kpbd.item_id',
                    'kpbd.unit as unit_id',
                    DB::raw('SUM(kpbd.qty) as total_qty'),
                    'i.item_name',
                    'iu.unit_name',
                    'w.warehouse_name',
                    'pp.item_id as plan_item_id',
                    'pp.plan_id as plan_code',
                    'pp.status as plan_status',
                    'pr.process_name'
                )
                ->where('kpb.document_date', '<=', $selectedDate)
                ->groupBy('kpb.document_date', 'kpb.plan_id', 'kpb.process_id', 'kpb.warehouse_id', 'kpbd.item_id', 'kpbd.unit', 'i.item_name', 'iu.unit_name', 'w.warehouse_name', 'pp.item_id', 'pp.plan_id', 'pp.status', 'pr.process_name');

            $pengeluaranQuery = DB::table('pengeluaran_bahan as pb')
                ->join('pengeluaran_bahan_detail as pbd', 'pb.id', '=', 'pbd.pengeluaran_bahan_id')
                ->join('items as i', 'pbd.item_id', '=', 'i.id')
                ->join('item_units as iu', function ($join) {
                    $join->on(DB::raw('pbd.unit::bigint'), '=', 'iu.id');
                })
                ->join('production_plans as pp', 'pb.plan_id', '=', 'pp.id')
                ->join('process as pr', 'pb.process_id', '=', 'pr.id')
                ->join('warehouse as w', 'pb.warehouse_id', '=', 'w.id')
                ->select(
                    'pb.document_date',
                    'pb.plan_id',
                    'pb.process_id',
                    'pb.warehouse_id',
                    'pbd.item_id',
                    'pbd.unit as unit_id',
                    DB::raw('SUM(pbd.qty) as total_qty'),
                    'i.item_name',
                    'iu.unit_name',
                    'w.warehouse_name',
                    'pp.item_id as plan_item_id',
                    'pp.plan_id as plan_code',
                    'pp.status as plan_status',
                    'pr.process_name'
                )
                ->where('pb.document_date', '<=', $selectedDate)
                ->groupBy('pb.document_date', 'pb.plan_id', 'pb.process_id', 'pb.warehouse_id', 'pbd.item_id', 'pbd.unit', 'i.item_name', 'iu.unit_name', 'w.warehouse_name', 'pp.item_id', 'pp.plan_id', 'pp.status', 'pr.process_name');

            $kasirPengeluaranQuery = DB::table('kasir_pengeluaran_bahan as kpb')
                ->join('kasir_pengeluaran_bahan_detail as kpbd', 'kpb.id', '=', 'kpbd.kasir_pengeluaran_bahan_id')
                ->join('items as i', 'kpbd.item_id', '=', 'i.id')
                ->join('item_units as iu', function ($join) {
                    $join->on(DB::raw('kpbd.unit::bigint'), '=', 'iu.id');
                })
                ->join('production_plans as pp', 'kpb.plan_id', '=', 'pp.id')
                ->join('process as pr', 'kpb.process_id', '=', 'pr.id')
                ->join('warehouse as w', 'kpb.warehouse_id', '=', 'w.id')
                ->select(
                    'kpb.document_date',
                    'kpb.plan_id',
                    'kpb.process_id',
                    'kpb.warehouse_id',
                    'kpbd.item_id',
                    'kpbd.unit as unit_id',
                    DB::raw('SUM(kpbd.qty) as total_qty'),
                    'i.item_name',
                    'iu.unit_name',
                    'w.warehouse_name',
                    'pp.item_id as plan_item_id',
                    'pp.plan_id as plan_code',
                    'pp.status as plan_status',
                    'pr.process_name'
                )
                ->where('kpb.document_date', '<=', $selectedDate)
                ->groupBy('kpb.document_date', 'kpb.plan_id', 'kpb.process_id', 'kpb.warehouse_id', 'kpbd.item_id', 'kpbd.unit', 'i.item_name', 'iu.unit_name', 'w.warehouse_name', 'pp.item_id', 'pp.plan_id', 'pp.status', 'pr.process_name');

            $penerimaanData = $penerimaanQuery->union($kasirPenerimaanQuery)->get();
            $pengeluaranData = $pengeluaranQuery->union($kasirPengeluaranQuery)->get();

            $penerimaanQtyByItemWarehouse = [];
            $pengeluaranQtyByItemWarehouse = [];
            $pengeluaranTotalsByDatePlan = [];

            foreach ($penerimaanData as $record) {
                $key = "{$record->item_id}-{$record->warehouse_id}-{$record->unit_id}-{$record->plan_id}";
                $penerimaanQtyByItemWarehouse[$key][$record->document_date] = ($penerimaanQtyByItemWarehouse[$key][$record->document_date] ?? 0) + $record->total_qty;
            }

            foreach ($pengeluaranData as $record) {
                $key = "{$record->item_id}-{$record->warehouse_id}-{$record->unit_id}-{$record->plan_id}";
                $datePlanKey = "{$record->document_date}-{$record->plan_id}";
                $pengeluaranQtyByItemWarehouse[$key][$record->document_date] = ($pengeluaranQtyByItemWarehouse[$key][$record->document_date] ?? 0) + $record->total_qty;

                $planResultItem = $plans[$record->plan_id]->item->item_name ?? 'N/A';
                $unitPrice = $avgCogmByItem[$planResultItem] ?? ($purchaseInvoiceDetails["{$record->item_id}-{$record->unit_id}"]->price ?? 0);
                $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'] = ($pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'] ?? 0) + $record->total_qty;
                $pengeluaranTotalsByDatePlan[$datePlanKey]['total_price'] = ($pengeluaranTotalsByDatePlan[$datePlanKey]['total_price'] ?? 0) + ($record->total_qty * $unitPrice);
            }

            $uniqueKeys = array_unique(array_merge(
                array_keys($penerimaanQtyByItemWarehouse),
                array_keys($pengeluaranQtyByItemWarehouse)
            ));

            $cogmProductionDetailsByItem = [];
            $cogmProduction = [];
            $productionReport = [];
            $itemTotalsByPlanResult = [];

            foreach ($uniqueKeys as $key) {
                list($item_id, $warehouse_id, $unit_id, $plan_id) = explode('-', $key);
                $item = $itemDetails["{$item_id}-{$unit_id}"] ?? null;
                $unit = $itemUnits[$unit_id] ?? null;
                $warehouse = $warehouses[$warehouse_id] ?? null;
                $plan = $plans[$plan_id] ?? null;
                $planResultItem = $plan && $plan->item ? $plan->item->item_name : 'N/A';

                $penerimaanDates = array_keys($penerimaanQtyByItemWarehouse[$key] ?? []);
                $pengeluaranDates = array_keys($pengeluaranQtyByItemWarehouse[$key] ?? []);
                $allDates = array_unique(array_merge($penerimaanDates, $pengeluaranDates));
                sort($allDates);

                if (!isset($cogmProductionDetailsByItem[$planResultItem])) {
                    $cogmProductionDetailsByItem[$planResultItem] = [];
                }
                if (!isset($itemTotalsByPlanResult[$planResultItem])) {
                    $itemTotalsByPlanResult[$planResultItem] = ['total_qty' => 0, 'total_cogm' => 0, 'unit' => $unit ? $unit->unit_name : 'N/A', 'latest_date' => null];
                }

                foreach ($allDates as $docDate) {
                    if (Carbon::parse($docDate)->gt($selectedDate)) {
                        continue;
                    }
                    $totalPenerimaanQty = $penerimaanQtyByItemWarehouse[$key][$docDate] ?? 0;
                    $totalPengeluaranQty = $pengeluaranQtyByItemWarehouse[$key][$docDate] ?? 0;
                    $itemName = $item && $item->item ? $item->item->item_name : 'N/A';
                    $unitPricePengeluaran = $avgCogmByItem[$planResultItem] ?? ($purchaseInvoiceDetails["{$item_id}-{$unit_id}"]->price ?? 0);
                    $datePlanKey = "{$docDate}-{$plan_id}";
                    $unitPricePenerimaan = $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'] ?? 0 > 0
                        ? $pengeluaranTotalsByDatePlan[$datePlanKey]['total_price'] / $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty']
                        : 0;

                    $penerimaanCogm = $totalPenerimaanQty * $unitPricePenerimaan;
                    $pengeluaranCogm = $totalPengeluaranQty * $unitPricePengeluaran;
                    $variance = $penerimaanCogm - $pengeluaranCogm;
                    $evaporationCost = abs($variance);
                    $form = $totalPenerimaanQty > 0 ? 'Penerimaan Bahan' : 'Pengeluaran Bahan';

                    $processRecord = $penerimaanData->where('document_date', $docDate)->where('plan_id', $plan_id)->first()
                        ?? $pengeluaranData->where('document_date', $docDate)->where('plan_id', $plan_id)->first();
                    $process = $processes[$processRecord->process_id ?? null] ?? null;
                    $resultProcess = ResultProcess::select('machine')
                        ->where('plan_id', $plan_id)
                        ->where('process_id', $processRecord->process_id ?? null)
                        ->where('document_date', '<=', $selectedDate)
                        ->orderBy('document_date', 'desc')
                        ->first();

                    $productionReport[] = [
                        'plan_id' => $plan->plan_code ?? $plan_id,
                        'result_item' => $planResultItem,
                        'machine_id' => $resultProcess->machine ?? null,
                        'process_name' => $process ? $process->process_name : 'N/A',
                        'plan_status' => $plan ? $plan->status : 'N/A',
                        'document_date' => $docDate,
                        'form' => $form,
                        'item_name' => $itemName,
                        'warehouse' => $warehouse ? $warehouse->warehouse_name : 'N/A',
                        'pengeluaran' => $form === 'Pengeluaran Bahan' ? [
                            'qty' => $totalPengeluaranQty,
                            'unit' => $unit ? $unit->unit_name : 'N/A',
                            'unit_price' => $unitPricePengeluaran,
                            'total_price' => $totalPengeluaranQty * $unitPricePengeluaran,
                        ] : [],
                        'penerimaan' => $form === 'Penerimaan Bahan' ? [
                            'qty' => $totalPenerimaanQty,
                            'unit' => $unit ? $unit->unit_name : 'N/A',
                            'unit_price' => $unitPricePenerimaan,
                            'total_price' => $totalPenerimaanQty * $unitPricePenerimaan,
                        ] : [],
                        'variance' => $variance,
                        'evaporation_cost' => $evaporationCost,
                    ];

                    if ($totalPenerimaanQty > 0) {
                        $cogmProductionDetailsByItem[$planResultItem][] = [
                            'tanggal' => $docDate,
                            'form' => 'Penerimaan Bahan',
                            'plan_id' => $plan->plan_code ?? $plan_id,
                            'plan_result_item' => $planResultItem,
                            'qty' => $totalPenerimaanQty,
                            'unit' => $unit ? $unit->unit_name : 'N/A',
                            'price' => $unitPricePenerimaan,
                            'cogm' => $penerimaanCogm,
                            'avg_cogm' => $unitPricePenerimaan,
                        ];

                        $itemTotalsByPlanResult[$planResultItem]['total_qty'] += $totalPenerimaanQty;
                        $itemTotalsByPlanResult[$planResultItem]['total_cogm'] += $penerimaanCogm;
                        if (!$itemTotalsByPlanResult[$planResultItem]['latest_date'] || Carbon::parse($docDate)->gt(Carbon::parse($itemTotalsByPlanResult[$planResultItem]['latest_date']))) {
                            $itemTotalsByPlanResult[$planResultItem]['latest_date'] = $docDate;
                        }
                    }
                }
            }

            $cogmProduction = [];
            foreach ($cogmProductionDetailsByItem as $planResultItem => $details) {
                $totalQty = $itemTotalsByPlanResult[$planResultItem]['total_qty'];
                $totalCogm = $itemTotalsByPlanResult[$planResultItem]['total_cogm'];
                $unit = $itemTotalsByPlanResult[$planResultItem]['unit'];
                $latestDate = $itemTotalsByPlanResult[$planResultItem]['latest_date'];
                $avgCogm = $totalQty > 0 ? $totalCogm / $totalQty : 0;

                $cogmProductionDetailsByItem[$planResultItem] = array_map(function ($detail) use ($avgCogm, $latestDate) {
                    if ($detail['tanggal'] === $latestDate) {
                        $detail['avg_cogm'] = $avgCogm;
                    }
                    return $detail;
                }, $details);

                $cogmProduction[] = [
                    'date' => $selectedDate->format('Y-m-d'),
                    'item_name' => $planResultItem,
                    'total_qty' => $totalQty,
                    'unit' => $unit,
                    'avg_cogm' => $avgCogm,
                    'status' => Module::checkPeriodeBack($periods, $selectedDate) ? 'Closed' : 'Open',
                    'nilai_persediaan' => $totalCogm,
                ];
            }

            return response()->json([
                'cogmProduction' => $cogmProduction,
                'cogmProductionDetails' => $cogmProductionDetailsByItem,
                'productionReport' => $productionReport,
                'role' => $this->getRole()
            ]);
        } catch (\Exception $e) {
            Log::error('COGM Production Error', [
                'date' => $date,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString()
            ]);
            return response()->json(['error' => 'Server error: ' . $e->getMessage()], 500);
        }
    }
}