<?php

namespace App\Http\Controllers;

use App\Models\ProcessingResultProcess;
use App\Models\ProcessingResultProcessDetail;
use App\Models\ProcessingPengeluaranBahan;
use App\Models\ProcessingPengeluaranBahanDetail;
use App\Models\ProcessingPlan;
use App\Models\Warehouse;
use App\Models\ProcessingPlanDetail;
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\ProcessingPenerimaanBahan;
use App\Models\ProcessingPenerimaanBahanDetail;
use App\Models\ItemDetail;
use App\Models\Periode;
use App\Models\ItemUnit;
use App\Models\PurchaseInvoice;
use App\Models\PurchaseInvoiceDetail;
use Illuminate\Http\Request;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Module;
use Carbon\Carbon;
use DB;

class ProcessingResultProcessController extends Controller
{
    public function index($dateStart, $dateEnd)
    {
        try {
            $resultProcesses = ProcessingResultProcess::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 $so) {
                $so->closed = Module::checkPeriodeBack($periods, $so->document_date);
                foreach ($so->details as $rp) {
                    if ($rp->pengeluaran_bahan_detail_id) {
                        $ppp = ProcessingPengeluaranBahanDetail::where("processing_pengeluaran_bahan_details.id", $rp->pengeluaran_bahan_detail_id)
                            ->join("processing_pengeluaran_bahans as x", "x.id", "=", "processing_pengeluaran_bahan_details.pengeluaran_bahan_id")
                            ->select("x.*")->first();
                        $rp->document_number = $ppp->pengeluaran_bahan_id;
                        $rp->document_date = $ppp->document_date;
                    }
                    if ($rp->penerimaan_bahan_detail_id) {
                        $ppp = ProcessingPenerimaanBahanDetail::where("processing_penerimaan_bahan_details.id", $rp->penerimaan_bahan_detail_id)
                            ->join("processing_penerimaan_bahan as x", "x.id", "=", "processing_penerimaan_bahan_details.penerimaan_bahan_id")
                            ->select("x.*")->first();
                        $rp->document_number = $ppp->penerimaan_bahan_id;
                        $rp->document_date = $ppp->document_date;
                    }
                }
            }

            return response()->json(["resultProcesses" => $resultProcesses, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Server error'], 500);
        }
    }

    public function show($id)
    {
        try {
            $resultProcess = ProcessingResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse', 'machine' => function ($query) {
                $query->select('id', 'asset_name');
            }])
                ->findOrFail($id);

            foreach ($resultProcess->details as $rp) {
                if ($rp->pengeluaran_bahan_detail_id) {
                    $ppp = ProcessingPengeluaranBahanDetail::where("processing_pengeluaran_bahan_details.id", $rp->pengeluaran_bahan_detail_id)
                        ->join("processing_pengeluaran_bahans as x", "x.id", "=", "processing_pengeluaran_bahan_details.pengeluaran_bahan_id")
                        ->select("x.*")->first();
                    $rp->document_number = $ppp->pengeluaran_bahan_id;
                    $rp->document_date = $ppp->document_date;
                }
                if ($rp->penerimaan_bahan_detail_id) {
                    $ppp = ProcessingPenerimaanBahanDetail::where("processing_penerimaan_bahan_details.id", $rp->penerimaan_bahan_detail_id)
                        ->join("processing_penerimaan_bahan as x", "x.id", "=", "processing_penerimaan_bahan_details.penerimaan_bahan_id")
                        ->select("x.*")->first();
                    $rp->document_number = $ppp->penerimaan_bahan_id;
                    $rp->document_date = $ppp->document_date;
                }
            }

            return response()->json($resultProcess);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Result Process not found'], 404);
        }
    }

    public function store(Request $request)
    {
        $user = Auth::user();
        $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id) : [];
        $allDept = [];
        foreach ($defaultDepartmentId as $d) {
            $allDept[] = $d->department_id;
        }

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

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

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

        $validator = Validator::make($request->all() + [
            'category_employee_code' => $categoryEmployeeCode,
            'employee_result' => $employeeResult,
            'overhead_result' => $overheadResult,
            'document_date' => $request->document_date
        ], [
            'plan_id' => 'required|exists:processing_plans,id',
            'process_id' => 'required|exists:process,id',
            'warehouse_id' => [
                'required',
                'exists:warehouse,id',
                function ($attribute, $value, $fail) use ($allDept) {
                    if ($allDept) {
                        $warehouse = Warehouse::where('id', $value)->whereIn('department', $allDept)->first();
                        if (!$warehouse) {
                            $fail('The selected warehouse is not in the user\'s default department.');
                        }
                    }
                },
            ],
            'machine' => 'nullable|exists:assets,id',
            'kwh_consumption' => 'required|numeric|gte:0',
            'employee_result' => 'nullable|array',
            'employee_result.*.employee_id' => 'required|exists:employees,id',
            'employee_result.*.qty' => 'required|numeric|gte:0',
            'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
            'overhead_result' => 'nullable|array',
            'overhead_result.*.overhead_id' => 'required|exists:overheads,id',
            'overhead_result.*.qty' => 'required|numeric|gte:0',
            'overhead_result.*.cost' => 'required|numeric|gte:0',
            'details' => 'required|array|min:1',
            'details.*.pengeluaran_bahan_detail_id' => 'nullable|exists:processing_pengeluaran_bahan_details,id',
            'details.*.penerimaan_bahan_detail_id' => 'nullable|exists:processing_penerimaan_bahan_details,id',
            'details.*.item_id' => 'required|exists:items,id',
            'details.*.qty' => 'required|numeric|gt:0',
            'details.*.unit' => 'required|exists:item_units,id',
            'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
            'document_date' => 'required|date'
        ]);

        if ($validator->fails()) {
            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) {
                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)) {
                        return response()->json(['errors' => ['employee_result' => 'All employees must belong to the selected category: ' . $categoryEmployeeCode]], 422);
                    }
                    if ($er['category_employee_code'] !== $categoryEmployeeCode) {
                        return response()->json(['errors' => ['employee_result' => 'Category employee code in employee_result must match selected category: ' . $categoryEmployeeCode]], 422);
                    }
                }
            } else {
                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)) {
                    return response()->json(['errors' => ['overhead_result' => 'Invalid overhead ID: ' . $or['overhead_id']]], 422);
                }
            }
        }

        DB::beginTransaction();
        try {
            $company = Company::first();
            $department = Department::first();
            if (!$company || !$department) {
                DB::rollBack();
                return response()->json(['error' => 'Company or Department not found'], 422);
            }
            $date = Carbon::parse($request->document_date);
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "PRP", 1);

            $resultProcess = ProcessingResultProcess::create([
                'result_process_id' => $nobukti,
                'document_date' => $date->format("Y-m-d"),
                'plan_id' => $request->plan_id,
                'process_id' => $request->process_id,
                'warehouse_id' => $request->warehouse_id,
                'pengeluaran_bahan_ids' => json_encode($request->pengeluaran_bahan_ids),
                'machine' => $request->machine,
                'employee_result' => json_encode($employeeResult),
                'overhead_result' => json_encode($overheadResult),
                'kwh_consumption' => $request->kwh_consumption,
                'created_by' => Auth::id() ?? null,
                'updated_by' => Auth::id() ?? null,
            ]);

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

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

            foreach ($request->details as $detail) {
                $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                if (!$itemDetail) {
                    DB::rollBack();
                    return response()->json(['error' => "ItemDetail not found for item_id: {$detail['item_id']}, unit_id: {$detail['unit']}"], 422);
                }

                ProcessingResultProcessDetail::create([
                    'result_process_id' => $resultProcess->id,
                    'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id'],
                    'penerimaan_bahan_detail_id' => $detail['penerimaan_bahan_detail_id'],
                    'item_id' => $detail['item_id'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'base_qty' => $itemDetail->conversion ?? 1,
                    'created_by' => Auth::id() ?? null,
                    'updated_by' => Auth::id() ?? null,
                ]);
            }

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

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

            DB::commit();
            return response()->json(['result_process' => $resultProcess], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => 'Server error'], 500);
        }
    }

    public function update(Request $request, $id)
    {
        $user = Auth::user();
        $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id) : [];
        $allDept = [];
        foreach ($defaultDepartmentId as $d) {
            $allDept[] = $d->department_id;
        }

        try {
            $resultProcess = ProcessingResultProcess::findOrFail($id);

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

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

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

            $validator = Validator::make($request->all() + [
                'category_employee_code' => $categoryEmployeeCode,
                'employee_result' => $employeeResult,
                'overhead_result' => $overheadResult,
                'document_date' => $request->document_date
            ], [
                'plan_id' => 'required|exists:processing_plans,id',
                'process_id' => 'required|exists:process,id',
                'warehouse_id' => [
                    'required',
                    'exists:warehouse,id',
                    function ($attribute, $value, $fail) use ($allDept) {
                        if ($allDept) {
                            $warehouse = Warehouse::where('id', $value)->whereIn('department', $allDept)->first();
                            if (!$warehouse) {
                                $fail('The selected warehouse is not in the user\'s default department.');
                            }
                        }
                    },
                ],
                'machine' => 'nullable|exists:assets,id',
                'kwh_consumption' => 'required|numeric|gte:0',
                'employee_result' => 'nullable|array',
                'employee_result.*.employee_id' => 'required|exists:employees,id',
                'employee_result.*.qty' => 'required|numeric|gte:0',
                'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'overhead_result' => 'nullable|array',
                'overhead_result.*.overhead_id' => 'required|exists:overheads,id',
                'overhead_result.*.qty' => 'required|numeric|gte:0',
                'overhead_result.*.cost' => 'required|numeric|gte:0',
                'details' => 'required|array|min:1',
                'details.*.pengeluaran_bahan_detail_id' => 'nullable|exists:processing_pengeluaran_bahan_details,id',
                'details.*.penerimaan_bahan_detail_id' => 'nullable|exists:processing_penerimaan_bahan_details,id',
                'details.*.item_id' => 'required|exists:items,id',
                'details.*.qty' => 'required|numeric|gt:0',
                'details.*.unit' => 'required|exists:item_units,id',
                'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'document_date' => 'required|date'
            ]);

            if ($validator->fails()) {
                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) {
                    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)) {
                            return response()->json(['errors' => ['employee_result' => 'All employees must belong to the selected category: ' . $categoryEmployeeCode]], 422);
                        }
                        if ($er['category_employee_code'] !== $categoryEmployeeCode) {
                            return response()->json(['errors' => ['employee_result' => 'Category employee code in employee_result must match selected category: ' . $categoryEmployeeCode]], 422);
                        }
                    }
                } else {
                    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)) {
                        return response()->json(['errors' => ['overhead_result' => 'Invalid overhead ID: ' . $or['overhead_id']]], 422);
                    }
                }
            }

            DB::beginTransaction();
            try {
                $company = Company::first();
                $department = Department::first();
                if (!$company || !$department) {
                    DB::rollBack();
                    return response()->json(['error' => 'Company or Department not found'], 422);
                }
                $date = Carbon::parse($request->document_date);
                $nobukti = $resultProcess->result_process_id;

                $resultProcess->update([
                    'plan_id' => $request->plan_id,
                    'process_id' => $request->process_id,
                    'warehouse_id' => $request->warehouse_id,
                    'pengeluaran_bahan_ids' => json_encode($request->pengeluaran_bahan_ids),
                    'machine' => $request->machine,
                    'employee_result' => json_encode($employeeResult),
                    'overhead_result' => json_encode($overheadResult),
                    'kwh_consumption' => $request->kwh_consumption,
                    'document_date' => $date->format("Y-m-d"),
                    'updated_by' => Auth::id() ?? null,
                ]);

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

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

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

                foreach ($request->details as $detail) {
                    $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                    if (!$itemDetail) {
                        DB::rollBack();
                        return response()->json(['error' => "ItemDetail not found for item_id: {$detail['item_id']}, unit_id: {$detail['unit']}"], 422);
                    }

                    ProcessingResultProcessDetail::create([
                        'result_process_id' => $resultProcess->id,
                        'pengeluaran_bahan_detail_id' => $detail['pengeluaran_bahan_detail_id'],
                        'penerimaan_bahan_detail_id' => $detail['penerimaan_bahan_detail_id'],
                        'item_id' => $detail['item_id'],
                        'qty' => $detail['qty'],
                        'unit' => $detail['unit'],
                        'base_qty' => $itemDetail->conversion ?? 1,
                        'created_by' => $resultProcess->created_by,
                        'updated_by' => Auth::id() ?? null,
                    ]);
                }

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

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

                DB::commit();
                return response()->json($resultProcess->load('details'));
            } catch (\Exception $e) {
                DB::rollBack();
                return response()->json(['error' => 'Server error'], 500);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => 'Result Process not found'], 404);
        }
    }

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

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

            if (!$existingResult) {
                ProcessingPlanDetail::where('plan_id', $resultProcess->plan_id)
                    ->where('process_id', $resultProcess->process_id)
                    ->update(['status' => 'On Progress', 'completed_at' => null]);
                ProcessingPlan::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' => 'ProcessingResultProcess',
            ]);

            DB::commit();
            return response()->json(null, 204);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => 'Server error'], 500);
        }
    }

    public function getMasterData()
    {
        try {
            $user = Auth::user();
            $assets = Asset::all();
            $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();
            $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();
            $penerimaanBahans = ProcessingPenerimaanBahan::with(['details.item', 'details.unit', 'plan', 'process', 'warehouse'])->get();

            $overheads = Overhead::all();
            $company = Company::first();
            $department = Department::first();
            $itemUnits = ItemUnit::all();
            $purchaseInvoices = PurchaseInvoice::with(['details.item', 'details.unit'])->get();

            if (!$company || !$department) {
                return response()->json(['error' => 'Company or Department not found'], 422);
            }

            $date = Carbon::now();
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "PRP", 0);

            return response()->json([
                'warehouses' => $warehouses,
                'assets' => $assets,
                'machines' => $machines,
                'overheads' => $overheads,
                'category_employees' => $categoryEmployees,
                'nobukti' => $nobukti,
                'employees' => $employees,
                'processes' => $processes,
                'penerimaan_bahans' => $penerimaanBahans,
                'item_units' => $itemUnits,
                'purchase_invoices' => $purchaseInvoices,
                'role' => $this->getRole(),
            ]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load master data'], 500);
        }
    }

    public function getProcessingPlans()
    {
        try {
            $processingPlans = ProcessingPlan::with(["item"])->whereIn('status', ['Pending', 'On Progress'])->get();
            $processingPlans->each(function ($plan) {
                $tgl = Carbon::parse($plan->production_start_date);
                $plan->production_start_date = $tgl->format("d-m-Y");
            });
            return response()->json($processingPlans);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load processing plans'], 500);
        }
    }

    public function getProcessesForPlan($planId)
    {
        try {
            if (!is_numeric($planId) || $planId <= 0) {
                return response()->json(['error' => 'Invalid plan_id'], 400);
            }
            $processes = ProcessingPlanDetail::with('process')
                ->where('plan_id', $planId)
                ->get()
                ->pluck('process')
                ->filter();
            return response()->json($processes);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load processes'], 500);
        }
    }

    public function getPengeluaranBahanForProcessAndWarehouse($planId, $processId, $warehouseId)
    {
        try {
            if (!is_numeric($processId) || $processId <= 0 || !is_numeric($warehouseId) || $warehouseId <= 0) {
                return response()->json(['error' => 'Invalid process_id or warehouse_id'], 400);
            }
            $pengeluaranBahans = ProcessingPengeluaranBahan::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse'])
                ->where('plan_id', $planId)
                ->where('process_id', $processId)
                ->where('warehouse_id', $warehouseId)
                ->get();

            return response()->json($pengeluaranBahans);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load material issuances'], 500);
        }
    }

    public function getItemsForPengeluaranBahan(Request $request)
    {
        try {
            $pengeluaranBahans = ProcessingPengeluaranBahan::with(['details.item', 'details.unit'])
                ->where('plan_id', $request->plan_id)
                ->where('process_id', $request->process_id)
                ->get();

            $penerimaanBahans = ProcessingPenerimaanBahan::with(['details.item', 'details.unit'])
                ->where('plan_id', $request->plan_id)
                ->where('process_id', $request->process_id)
                ->get();
            foreach ($penerimaanBahans as $penerimaanBahan) {
                Log::info('ProcessingPenerimaanBahan Plan Relation', [
                    'penerimaan_bahan_id' => $penerimaanBahan->id,
                    'plan_id' => $penerimaanBahan->plan_id,
                    'plan' => $penerimaanBahan->plan ? $penerimaanBahan->plan->toArray() : null
                ]);
            }

            $detailPengeluarans = $pengeluaranBahans->flatMap(function ($pengeluaranBahan) {
                return $pengeluaranBahan->details->map(function ($detail) use ($pengeluaranBahan) {
                    $unit = ItemUnit::where('id', $detail->unit)->first();
                    return [
                        'id' => $detail->id,
                        'pengeluaran_bahan_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                        'pengeluaran_bahan_id' => $pengeluaranBahan->id,
                        'document_date' => $pengeluaranBahan->document_date,
                        'item_id' => $detail->item_id,
                        'item' => $detail->item,
                        'qty' => $detail->qty,
                        'unit' => $unit ? $unit->unit_name : 'N/A',
                        'unit_id' => $unit->id,
                    ];
                });
            });

            $detailPenerimaans = $penerimaanBahans->flatMap(function ($penerimaanBahan) {
                return $penerimaanBahan->details->map(function ($detail) use ($penerimaanBahan) {
                    $unit = ItemUnit::where('id', $detail->unit)->first();
                    return [
                        'id' => $detail->id,
                        'penerimaan_bahan_number' => $penerimaanBahan->penerimaan_bahan_id,
                        'penerimaan_bahan_id' => $penerimaanBahan->id,
                        'document_date' => $penerimaanBahan->document_date,
                        'item_id' => $detail->item_id,
                        'item' => $detail->item,
                        'qty' => $detail->qty,
                        'unit' => $unit ? $unit->unit_name : 'N/A',
                        'unit_id' => $unit->id,
                    ];
                });
            });

            return response()->json(["detailPengeluarans" => $detailPengeluarans, "detailPenerimaans" => $detailPenerimaans]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load items'], 500);
        }
    }

    public function getPengeluaranBahanMetadata(Request $request)
    {
        try {
            $pengeluaranBahanIds = $request->input('pengeluaran_bahan_ids', []);
            if (empty($pengeluaranBahanIds) || !is_array($pengeluaranBahanIds)) {
                return response()->json(['error' => 'Invalid rnd_pengeluaran_bahan_ids'], 400);
            }
            $pengeluaranBahans = ProcessingPengeluaranBahan::select('id', 'pengeluaran_bahan_id')
                ->whereIn('id', $pengeluaranBahanIds)
                ->get();
            return response()->json($pengeluaranBahans);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load metadata'], 500);
        }
    }

    public function getEmployeesForCategory($categoryCode)
    {
        try {
            if (empty($categoryCode)) {
                return response()->json(['error' => 'Invalid category_employee_code'], 400);
            }
            $category = CategoryEmployee::whereRaw('LOWER(category_employee_code) = ?', [strtolower($categoryCode)])->first();
            if (!$category) {
                return response()->json(['error' => 'Category not found for code: ' . $categoryCode], 404);
            }
            $employees = Employee::where('category_employee', $category->category_employee_code)->get();
            return response()->json($employees);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to load employees'], 500);
        }
    }

    public function cogmProcessing($date)
    {
        try {
            $periods = Periode::all();
            $selectedDate = Carbon::parse($date)->endOfDay();
            $penerimaanBahans = ProcessingPenerimaanBahan::with(['details.item', 'details.unit', 'plan', 'process', 'warehouse'])
                ->where('document_date', '<=', $selectedDate)
                ->orderBy('document_date', 'desc')
                ->get();
            
            $pengeluaranBahans = ProcessingPengeluaranBahan::with(['details.item', 'details.unit', 'plan', 'process', 'warehouse'])
                ->where('document_date', '<=', $selectedDate)
                ->orderBy('document_date', 'desc')
                ->get();

            $cogmProcessingDetailsByItem = [];
            $cogmProcessing = [];
            $processReport = [];

            $penerimaanQtyByItemWarehouse = [];
            $pengeluaranPriceByItemWarehouse = [];
            $pengeluaranQtyByItemWarehouse = [];

            foreach ($penerimaanBahans as $penerimaanBahan) {
                foreach ($penerimaanBahan->details as $detail) {
                    $key = $detail->item_id . '-' . $penerimaanBahan->warehouse_id . '-' . $detail->unit . '-' . $penerimaanBahan->plan_id;
                    if (!isset($penerimaanQtyByItemWarehouse[$key])) {
                        $penerimaanQtyByItemWarehouse[$key] = [];
                    }
                    if (!isset($penerimaanQtyByItemWarehouse[$key][$penerimaanBahan->document_date])) {
                        $penerimaanQtyByItemWarehouse[$key][$penerimaanBahan->document_date] = 0;
                    }
                    $penerimaanQtyByItemWarehouse[$key][$penerimaanBahan->document_date] += $detail->qty;
                }
            }

            $pengeluaranAveragePrices = DB::table('processing_pengeluaran_bahans as ppb')
                ->join('processing_pengeluaran_bahan_details as ppbd', 'ppb.id', '=', 'ppbd.pengeluaran_bahan_id')
                ->join('purchase_invoices as pi', 'pi.id', '=', 'pi.id')
                ->join('purchase_invoice_details as pid', function ($join) {
                    $join->on('pi.id', '=', 'pid.purchase_invoice_id')
                        ->on('pid.item_id', '=', 'ppbd.item_id')
                        ->on('pid.unit', '=', DB::raw('CAST(ppbd.unit AS BIGINT)'));
                })
                ->select(
                    'ppbd.item_id',
                    'ppb.warehouse_id',
                    'ppbd.unit',
                    'ppb.plan_id',
                    'ppb.document_date',
                    DB::raw('SUM(pid.price * ppbd.qty) / SUM(ppbd.qty) as avg_price')
                )
                ->where('ppb.document_date', '<=', $selectedDate)
                ->groupBy('ppbd.item_id', 'ppb.warehouse_id', 'ppbd.unit', 'ppb.plan_id', 'ppb.document_date')
                ->havingRaw('SUM(ppbd.qty) > 0')
                ->get();

            foreach ($pengeluaranAveragePrices as $price) {
                $key = $price->item_id . '-' . $price->warehouse_id . '-' . $price->unit . '-' . $price->plan_id;
                if (!isset($pengeluaranPriceByItemWarehouse[$key])) {
                    $pengeluaranPriceByItemWarehouse[$key] = [];
                }
                $pengeluaranPriceByItemWarehouse[$key][$price->document_date] = $price->avg_price ?: 0;
            }

            foreach ($pengeluaranBahans as $pengeluaranBahan) {
                foreach ($pengeluaranBahan->details as $detail) {
                    $key = $detail->item_id . '-' . $pengeluaranBahan->warehouse_id . '-' . $detail->unit . '-' . $pengeluaranBahan->plan_id;
                    if (!isset($pengeluaranQtyByItemWarehouse[$key])) {
                        $pengeluaranQtyByItemWarehouse[$key] = [];
                    }
                    if (!isset($pengeluaranQtyByItemWarehouse[$key][$pengeluaranBahan->document_date])) {
                        $pengeluaranQtyByItemWarehouse[$key][$pengeluaranBahan->document_date] = 0;
                    }
                    $pengeluaranQtyByItemWarehouse[$key][$pengeluaranBahan->document_date] += $detail->qty;
                }
            }

            $pengeluaranTotalsByDatePlan = [];
            foreach ($pengeluaranBahans as $pengeluaranBahan) {
                foreach ($pengeluaranBahan->details as $detail) {
                    $key = $detail->item_id . '-' . $pengeluaranBahan->warehouse_id . '-' . $detail->unit . '-' . $pengeluaranBahan->plan_id;
                    $datePlanKey = $pengeluaranBahan->document_date . '-' . $pengeluaranBahan->plan_id;
                    if (!isset($pengeluaranTotalsByDatePlan[$datePlanKey])) {
                        $pengeluaranTotalsByDatePlan[$datePlanKey] = ['total_qty' => 0, 'total_price' => 0];
                    }
                    $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'] += $detail->qty;
                    $unit_price = isset($pengeluaranPriceByItemWarehouse[$key][$pengeluaranBahan->document_date]) ? $pengeluaranPriceByItemWarehouse[$key][$pengeluaranBahan->document_date] : 0;
                    $pengeluaranTotalsByDatePlan[$datePlanKey]['total_price'] += $detail->qty * $unit_price;
                }
            }

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

            $itemTotalsByPlanResult = [];
            $cogmProcessingDetailsByItemTemp = [];

            foreach ($uniqueKeys as $key) {
                list($item_id, $warehouse_id, $unit_id, $plan_id) = explode('-', $key);
                $item = ItemDetail::where('item_id', $item_id)->where('unit_id', $unit_id)->first();
                $unit = ItemUnit::where('id', $unit_id)->first();
                $warehouse = Warehouse::where('id', $warehouse_id)->first();
                $plan = ProcessingPlan::where('id', $plan_id)->first();
                $planResultItem = $plan->item->item_name ?? 'N/A';

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

                if (!isset($cogmProcessingDetailsByItemTemp[$planResultItem])) {
                    $cogmProcessingDetailsByItemTemp[$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;
                    $unitPricePengeluaran = isset($pengeluaranPriceByItemWarehouse[$key][$docDate]) ? $pengeluaranPriceByItemWarehouse[$key][$docDate] : 0;

                    $datePlanKey = $docDate . '-' . $plan_id;
                    $unitPricePenerimaan = 0;
                    if (isset($pengeluaranTotalsByDatePlan[$datePlanKey]) && $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'] > 0) {
                        $unitPricePenerimaan = $pengeluaranTotalsByDatePlan[$datePlanKey]['total_price'] / $pengeluaranTotalsByDatePlan[$datePlanKey]['total_qty'];
                    }

                    $penerimaanCogm = $totalPenerimaanQty * $unitPricePenerimaan;
                    $pengeluaranCogm = $totalPengeluaranQty * $unitPricePengeluaran;
                    $variance = $penerimaanCogm - $pengeluaranCogm;
                    $evaporationCost = abs($variance);

                    $form = $totalPenerimaanQty > 0 ? 'Processing Penerimaan Bahan' : 'Processing Penggunaan Bahan';

                    $penerimaanBahan = $penerimaanBahans->where('document_date', $docDate)->where('plan_id', $plan_id)->first();
                    $pengeluaranBahan = $pengeluaranBahans->where('document_date', $docDate)->where('plan_id', $plan_id)->first();
                    $process = Process::where('id', $penerimaanBahan->process_id ?? $pengeluaranBahan->process_id ?? null)->first();
                    $resultProcess = ProcessingResultProcess::where('plan_id', $plan_id)
                        ->where('process_id', $process->id ?? null)
                        ->where('document_date', '<=', $selectedDate)
                        ->orderBy('document_date', 'desc')
                        ->first();

                    $processReport[] = [
                        'plan_id' => $plan->plan_id ?? $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' => $item ? $item->item->item_name : 'N/A',
                        'warehouse' => $warehouse ? $warehouse->warehouse_name : 'N/A',
                        'penggunaan' => $form === 'Processing Penggunaan Bahan' ? [
                            'qty' => $totalPengeluaranQty,
                            'unit' => $unit ? $unit->unit_name : 'N/A',
                            'unit_price' => $unitPricePengeluaran,
                            'total_price' => $totalPengeluaranQty * $unitPricePengeluaran,
                        ] : [],
                        'penyerahan' => $form === 'Processing 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) {
                        $cogmProcessingDetailsByItemTemp[$planResultItem][] = [
                            'tanggal' => $docDate,
                            'form' => 'Processing Penerimaan Bahan',
                            'plan_id' => $plan->plan_id ?? $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;
                        }
                    }
                }
            }

            foreach ($cogmProcessingDetailsByItemTemp 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;

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

                $cogmProcessing[] = [
                    '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([
                'cogmProcessing' => $cogmProcessing,
                'cogmProcessingDetails' => $cogmProcessingDetailsByItem,
                'processReport' => $processReport,
                'role' => $this->getRole()
            ]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Server error: ' . $e->getMessage()], 500);
        }
    }

    public function print($id)
    {
        try {
            $resultProcess = ProcessingResultProcess::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse', 'machine' => function ($query) {
                $query->select('id', 'asset_name');
            }])
                ->findOrFail($id);

            foreach ($resultProcess->details as $rp) {
                if ($rp->pengeluaran_bahan_detail_id) {
                    $ppp = ProcessingPengeluaranBahanDetail::where("processing_pengeluaran_bahan_details.id", $rp->pengeluaran_bahan_detail_id)
                        ->join("processing_pengeluaran_bahans as x", "x.id", "=", "processing_pengeluaran_bahan_details.pengeluaran_bahan_id")
                        ->select("x.*")->first();
                    $rp->document_number = $ppp->pengeluaran_bahan_id;
                    $rp->document_date = $ppp->document_date;
                    $rp->item_date = $ppp->item_date;
                    $rp->is_casing_or_top = $rp->item->category == "240" || $rp->item->category == "241" ? 1 : 0;
                    $rp->is_casing = $ppp->is_casing;
                    $rp->is_top = $ppp->is_top;
                }
                if ($rp->penerimaan_bahan_detail_id) {
                    $ppp = ProcessingPenerimaanBahanDetail::where("processing_penerimaan_bahan_details.id", $rp->penerimaan_bahan_detail_id)
                        ->join("processing_penerimaan_bahan as x", "x.id", "=", "processing_penerimaan_bahan_details.penerimaan_bahan_id")
                        ->select("x.*")->first();
                    Log::info('ProcessingPenerimaanBahan Plan Relation', [
                        'penerimaan_bahan_id' => $ppp->id,
                        'plan_id' => $ppp->plan_id,
                        'plan' => $ppp->plan ? $ppp->plan->toArray() : null
                    ]);
                    $rp->document_number = $ppp->penerimaan_bahan_id;
                    $rp->document_date = $ppp->document_date;
                    $rp->item_date = $ppp->item_date;
                    $rp->is_casing_or_top = $rp->item->category == "240" || $rp->item->category == "241" ? 1 : 0;
                    $rp->is_casing = $ppp->is_casing;
                    $rp->is_top = $ppp->is_top;
                }
            }
            $tgl_top = "";
            $tgl_casing = "";
            foreach ($resultProcess->details as $rp) {
                if ($rp->is_casing) {
                    $tgl_casing = $rp->document_date;
                }
                if ($rp->is_top) {
                    $tgl_top = $rp->document_date;
                }
            }

            $imagePath = storage_path('app/images/logo-only.png');
            if (!file_exists($imagePath)) {
                throw new \Exception('Logo image not found');
            }
            $imageData = file_get_contents($imagePath);
            $username = Auth::user()->name;
            $pdf = Pdf::loadView('print.processing_result_process_pdf', [
                'resultProcess' => $resultProcess,
                'imageData' => $imageData,
                'totalHuruf' => '-',
                'username' => $username,
                'tgl_top' => $tgl_top,
                'tgl_casing' => $tgl_casing
            ])->setPaper('A5', 'landscape');
            return ["data" => "data:application/pdf;base64," . base64_encode($pdf->stream()), "role" => $this->getRole()];
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to generate PDF: ' . $e->getMessage()], 500);
        }
    }

    public function increasePrintNumber($id)
    {
        $so = ProcessingResultProcess::find($id);
        $so->print_number = ($so->print_number ?? 0) + 1;
        $so->save();
        return response()->json(null);
    }
}