<?php

namespace App\Http\Controllers;

use DB;
use Carbon\Carbon;
use App\Models\Item;
use App\Models\Company;
use App\Models\Periode;
use App\Models\Process;
use App\Models\Employee;
use App\Models\ItemUnit;
use App\Models\DeleteLog;
use App\Models\Warehouse;
use App\Models\Department;
use App\Models\ItemDetail;
use App\Models\Journal;
use Illuminate\Http\Request;
use App\Models\ProcessingPlan;
use App\Http\Controllers\Module;
use App\Models\CategoryEmployee;
use App\Models\ProcessingPlanDetail;
use Illuminate\Support\Facades\Auth;
use App\Models\ProcessingResultProcess;
use Illuminate\Support\Facades\Validator;
use App\Models\ProcessingPengeluaranBahan;
use App\Models\ProcessingPengeluaranBahanDetail;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class ProcessingPengeluaranBahanController extends Controller
{
    public function index($dateStart,$dateEnd)
    {
        try {
            $Listdepartment = $this->getDepartment();
            $pengeluaranBahans = [];
            if(in_array(4,$Listdepartment)){
                $pengeluaranBahans = ProcessingPengeluaranBahan::with(['details', 'plan.item', 'details.item', 'details.unit', 'process', 'warehouse'])
                ->whereBetween('document_date',[$dateStart,$dateEnd])->get();
            }else{
                $pengeluaranBahans = ProcessingPengeluaranBahan::whereRaw("1 <> 1")->get();
            }
            
            $periods = Periode::all();
            foreach($pengeluaranBahans as $pb){
                $pb->closed =  Module::checkPeriodeBack($periods,$pb->document_date);
            }
            return response()->json(["pengeluaranBahans" => $pengeluaranBahans, "role" => $this->getRole()], 200);
        } catch (\Exception $e) {
            \Log::error('Index Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to fetch material releases'], 500);
        }
    }

    public function show($id)
    {
        try {
            if (!is_numeric($id) || $id <= 0) {
                return response()->json(['error' => 'Invalid ID'], 400);
            }
            $pengeluaranBahan = ProcessingPengeluaranBahan::with(['details.item', 'details.unit', 'plan.item', 'process', 'warehouse'])->findOrFail($id);
            return response()->json($pengeluaranBahan, 200);
        } catch (ModelNotFoundException $e) {
            \Log::error('Show Error: Record not found', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Material release not found'], 404);
        } catch (\Exception $e) {
            \Log::error('Show Error', [
                'id' => $id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to fetch material release'], 500);
        }
    }

    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;
            }
        }

        $validator = Validator::make(array_merge($request->all(), [
            'category_employee_code' => $categoryEmployeeCode,
            'employee_result' => $employeeResult
        ]), [
            '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.');
                        }
                    }
                },
            ],
            'plan_id' => 'required|exists:processing_plans,id',
            'process_id' => 'required|exists:process,id',
            'mutation_in_id' => 'nullable|exists:mutation_ins,id',
            'is_top' => 'nullable|boolean',
            'is_casing' => 'nullable|boolean',
            'details' => 'required|array|min:1',
            'details.*.item_id' => 'required|exists:items,id',
            'details.*.qty' => 'required|numeric|min:0.001',
            'details.*.unit' => 'required|exists:item_units,id',
            'employee_result' => 'nullable|array',
            'employee_result.*.employee_id' => 'required|exists:employees,id',
            'employee_result.*.qty' => 'required|numeric|min:0',
            'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
            'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
        ]);

        if ($validator->fails()) {
            \Log::warning('Validation Failed', [
                'errors' => $validator->errors()->toArray(),
                'request_data' => $request->all(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['errors' => $validator->errors()], 422);
        }

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

        DB::beginTransaction();
        try {
            $company = Company::first();
            $department = Department::where('department_code','PRO001')->first();
            $date = Carbon::now();
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "PMK", 1);

            $pengeluaranBahan = ProcessingPengeluaranBahan::create([
                'pengeluaran_bahan_id' => $nobukti,
                'document_date' => $request->document_date,
                'warehouse_id' => $request->warehouse_id,
                'plan_id' => $request->plan_id,
                'mutation_in_id' => $request->mutation_in_id,
                'process_id' => $request->process_id,
                'employee_result' => json_encode($employeeResult),
                'is_top' => $request->is_top ?? false,
                'is_casing' => $request->is_casing ?? false,
                'created_by' => Auth::id() ?? 0,
                'updated_by' => Auth::id() ?? 0,
            ]);

            $existingIssuance = ProcessingPengeluaranBahan::where('plan_id', $request->plan_id)
                ->where('process_id', $request->process_id)
                ->where('id', '!=', $pengeluaranBahan->id)
                ->exists();

            if (!$existingIssuance) {
                ProcessingPlan::where('id', $request->plan_id)
                    ->update(['status' => 'On Progress']);
                ProcessingPlanDetail::where('plan_id', $request->plan_id)
                    ->where('process_id', $request->process_id)
                    ->where('status', 'Pending')
                    ->update(['status' => 'On Progress']);
            }

            foreach ($request->details as $detail) {
                $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                if (!$itemDetail) {
                    \Log::error('Store Error: Item detail not found', [
                        'item_id' => $detail['item_id'],
                        'unit_id' => $detail['unit'],
                        'user_id' => Auth::id()
                    ]);
                    DB::rollback();
                    return response()->json(['error' => 'Item detail not found for item_id: ' . $detail['item_id']], 422);
                }
                ProcessingPengeluaranBahanDetail::create([
                    'pengeluaran_bahan_id' => $pengeluaranBahan->id,
                    'warehouse_id' => $request->warehouse_id,
                    'item_id' => $detail['item_id'],
                    'item_date' => $detail['item_date'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'base_qty' => $itemDetail->conversion,
                    'created_by' => Auth::id() ?? 0,
                    'updated_by' => Auth::id() ?? 0,
                ]);

                $cogs = Module::getCogs($pengeluaranBahan->document_date,$detail['item_id'],$company->companyCode,$department->id,$pengeluaranBahan->warehouse_id);
                DB::table('inventory_details')->insert([
                    'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                    'document_date' => $pengeluaranBahan->document_date,
                    'purchase_date' => $detail['item_date'],
                    'transaction_type' => 'Processing Penggunaan Bahan',
                    'warehouse_id' => $pengeluaranBahan->warehouse_id,
                    'item_id' => $detail['item_id'],
                    'quantity' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'base_quantity' => $itemDetail->conversion,
                    'unit_base' => $itemDetail->item->base_unit_id,
                    'department_id' => $department->id,
                    'company_code' => $company->companyCode,
                    'total' => $cogs * $detail['qty'] * $itemDetail->conversion,
                    'cogs' => -1 * ($cogs * $detail['qty'] * $itemDetail->conversion),
                    'qty_actual' => -1 * $detail['qty'],
                    'created_by' => Auth::user()->id,
                    'updated_by' => Auth::user()->id,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                $it = Item::find($detail['item_id']);
                if($it){
                    $accWip = $it->categoryItem->acc_number_wip;
                    Journal::create([
                        'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                        'document_date' => $pengeluaranBahan->document_date,
                        'account_number' => $accWip,
                        'notes' => 'Persediaan dalam WIP: ' . $it->item_name,
                        'debet_nominal' => $cogs * $detail['qty'] * $itemDetail->conversion,
                        'credit_nominal' => 0,
                        'debet_nominal_base' => $cogs * $detail['qty'] * $itemDetail->conversion,
                        'credit_nominal_base' => 0,
                        'company_code' => $company->companyCode,
                        'department_id' => $department->id,
                        'created_by' => Auth::user()->id,
                        'updated_by' => Auth::user()->id,
                    ]);
                    
                    Journal::create([
                        'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                        'document_date' => $pengeluaranBahan->document_date,
                        'account_number' => $it->categoryItem->account_inventory,
                        'notes' => 'Persediaan: ' . $it->item_name,
                        'debet_nominal' => 0,
                        'credit_nominal' => $cogs * $detail['qty'] * $itemDetail->conversion,
                        'debet_nominal_base' => 0,
                        'credit_nominal_base' => $cogs * $detail['qty'] * $itemDetail->conversion,
                        'company_code' => $company->companyCode,
                        'department_id' => $department->id,
                        'created_by' => Auth::user()->id,
                        'updated_by' => Auth::user()->id,
                    ]);
                }
            }

            DB::commit();
            return response()->json($pengeluaranBahan->load('details'), 201);
        } catch (\Exception $e) {
            DB::rollback();
            \Log::error('Store Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'request_data' => $request->all(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to create material release'], 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 {
            if (!is_numeric($id) || $id <= 0) {
                return response()->json(['error' => 'Invalid ID'], 400);
            }
            $pengeluaranBahan = ProcessingPengeluaranBahan::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;
                }
            }

            $validator = Validator::make(array_merge($request->all(), [
                'category_employee_code' => $categoryEmployeeCode,
                'employee_result' => $employeeResult
            ]), [
                '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.');
                            }
                        }
                    },
                ],
                'plan_id' => 'required|exists:processing_plans,id',
                'process_id' => 'required|exists:process,id',
                'mutation_in_id' => 'nullable|exists:mutation_ins,id',
                'is_top' => 'nullable|boolean',
                'is_casing' => 'nullable|boolean',
                'details' => 'required|array|min:1',
                'details.*.item_id' => 'required|exists:items,id',
                'details.*.qty' => 'required|numeric|min:0.001',
                'details.*.unit' => 'required|exists:item_units,id',
                'employee_result' => 'nullable|array',
                'employee_result.*.employee_id' => 'required|exists:employees,id',
                'employee_result.*.qty' => 'required|numeric|min:0',
                'employee_result.*.category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
                'category_employee_code' => 'nullable|exists:category_employees,category_employee_code',
            ]);

            if ($validator->fails()) {
                \Log::warning('Validation Failed', [
                    'id' => $id,
                    'errors' => $validator->errors()->toArray(),
                    'request_data' => $request->all(),
                    'user_id' => Auth::id()
                ]);
                return response()->json(['errors' => $validator->errors()], 422);
            }

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

            DB::beginTransaction();
            try {
                $pengeluaranBahan->update([
                    'warehouse_id' => $request->warehouse_id,
                    'plan_id' => $request->plan_id,
                    'process_id' => $request->process_id,
                    'mutation_in_id' => $request->mutation_in_id,
                    'employee_result' => json_encode($employeeResult),
                    'is_top' => $request->is_top ?? false,
                    'is_casing' => $request->is_casing ?? false,
                    'updated_by' => Auth::id() ?? 0,
                ]);

                $existingIssuance = ProcessingPengeluaranBahan::where('plan_id', $request->plan_id)
                    ->where('process_id', $request->process_id)
                    ->where('id', '!=', $pengeluaranBahan->id)
                    ->exists();

                if (!$existingIssuance) {
                    ProcessingPlan::where('id', $request->plan_id)
                        ->update(['status' => 'On Progress']);
                    ProcessingPlanDetail::where('plan_id', $request->plan_id)
                        ->where('process_id', $request->process_id)
                        ->where('status', 'Pending')
                        ->update(['status' => 'On Progress']);
                }

                $pengeluaranBahan->details()->delete();
                DB::table('inventory_details')->where("document_number",$pengeluaranBahan->pengeluaran_bahan_id)->delete();
                Journal::where("document_number",$pengeluaranBahan->pengeluaran_bahan_id)->delete();

                $company = Company::first();
                $department = Department::where('department_code','PRO001')->first();

                foreach ($request->details as $detail) {
                    $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                    if (!$itemDetail) {
                        \Log::error('Update Error: Item detail not found', [
                            'id' => $id,
                            'item_id' => $detail['item_id'],
                            'unit_id' => $detail['unit'],
                            'user_id' => Auth::id()
                        ]);
                        DB::rollback();
                        return response()->json(['error' => 'Item detail not found for item_id: ' . $detail['item_id']], 422);
                    }
                    ProcessingPengeluaranBahanDetail::create([
                        'pengeluaran_bahan_id' => $pengeluaranBahan->id,
                        'warehouse_id' => $request->warehouse_id,
                        'item_id' => $detail['item_id'],
                        'item_date' => $detail['item_date'],
                        'qty' => $detail['qty'],
                        'unit' => $detail['unit'],
                        'base_qty' => $itemDetail->conversion,
                        'created_by' => $pengeluaranBahan->created_by ?? Auth::id() ?? 0,
                        'updated_by' => Auth::id() ?? 0,
                    ]);

                    $cogs = Module::getCogs($pengeluaranBahan->document_date,$detail['item_id'],$company->companyCode,$department->id,$pengeluaranBahan->warehouse_id);
                    DB::table('inventory_details')->insert([
                        'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                        'document_date' => $pengeluaranBahan->document_date,
                        'purchase_date' => $detail['item_date'],
                        'transaction_type' => 'Processing Penggunaan Bahan',
                        'warehouse_id' => $pengeluaranBahan->warehouse_id,
                        'item_id' => $detail['item_id'],
                        'quantity' => $detail['qty'],
                        'unit' => $detail['unit'],
                        'base_quantity' => $itemDetail->conversion,
                        'unit_base' => $itemDetail->item->base_unit_id,
                        'department_id' => $department->id,
                        'company_code' => $company->companyCode,
                        'total' => $cogs * $detail['qty'] * $itemDetail->conversion,
                        'cogs' => -1 * ($cogs * $detail['qty'] * $itemDetail->conversion),
                        'qty_actual' => -1 * $detail['qty'],
                        'created_by' => Auth::user()->id,
                        'updated_by' => Auth::user()->id,
                        'created_at' => now(),
                        'updated_at' => now(),
                    ]);

                    $it = Item::find($detail['item_id']);
                    if($it){
                        $accWip = $it->categoryItem->acc_number_wip;
                        Journal::create([
                            'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                            'document_date' => $pengeluaranBahan->document_date,
                            'account_number' => $accWip,
                            'notes' => 'Persediaan dalam WIP: ' . $it->item_name,
                            'debet_nominal' => $cogs * $detail['qty'] * $itemDetail->conversion,
                            'credit_nominal' => 0,
                            'debet_nominal_base' => $cogs * $detail['qty'] * $itemDetail->conversion,
                            'credit_nominal_base' => 0,
                            'company_code' => $company->companyCode,
                            'department_id' => $department->id,
                            'created_by' => Auth::user()->id,
                            'updated_by' => Auth::user()->id,
                        ]);
                        
                        Journal::create([
                            'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                            'document_date' => $pengeluaranBahan->document_date,
                            'account_number' => $it->categoryItem->account_inventory,
                            'notes' => 'Persediaan: ' . $it->item_name,
                            'debet_nominal' => 0,
                            'credit_nominal' => $cogs * $detail['qty'] * $itemDetail->conversion,
                            'debet_nominal_base' => 0,
                            'credit_nominal_base' => $cogs * $detail['qty'] * $itemDetail->conversion,
                            'company_code' => $company->companyCode,
                            'department_id' => $department->id,
                            'created_by' => Auth::user()->id,
                            'updated_by' => Auth::user()->id,
                        ]);
                    }
                }

                DB::commit();
                return response()->json(['message' => 'Material release updated successfully'], 200);
            } catch (\Exception $e) {
                DB::rollback();
                \Log::error('Update Error', [
                    'id' => $id,
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                    'request_data' => $request->all(),
                    'user_id' => Auth::id()
                ]);
                return response()->json(['error' => 'Failed to update material release'], 500);
            }
        } catch (ModelNotFoundException $e) {
            \Log::error('Update Error: Record not found', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Material release not found'], 404);
        }
    }

    public function destroy(Request $request, $id)
    {
        DB::beginTransaction();
        try {
            if (!is_numeric($id) || $id <= 0) {
                return response()->json(['error' => 'Invalid ID'], 400);
            }
            $pengeluaranBahan = ProcessingPengeluaranBahan::findOrFail($id);
            $pengeluaranBahan->details()->delete();
            $pengeluaranBahan->delete();
            DB::table('inventory_details')->where("document_number",$pengeluaranBahan->pengeluaran_bahan_id)->delete();

            DeleteLog::create([
                'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                'document_date' => $pengeluaranBahan->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' => 'ProcessingPengeluaranBahan',
            ]);

            DB::commit();
            return response()->json(['message' => 'Material release deleted successfully'], 204);
        } catch (ModelNotFoundException $e) {
            DB::rollback();
            \Log::error('Destroy Error: Record not found', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Material release not found'], 404);
        } catch (\Exception $e) {
            DB::rollback();
            \Log::error('Destroy Error', [
                'id' => $id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to delete material release'], 500);
        }
    }

    public function getMasterData()
    {
        try {
            $user = Auth::user();
            // $defaultDepartmentId = $user->default_department_id ? json_decode($user->default_department_id) : [];
            // $allDept = [];
            // foreach($defaultDepartmentId as $d){
            //     $allDept[] = $d->department_id;
            // }
            $processingPlans = ProcessingPlan::with([
                'details' => function ($query) {
                    $query->with(['process.resultItem']);
                },
                '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");

                $plan->details->each(function ($detail) {
                    $process = $detail->process;

                    if ($process) {
                        $data = json_decode($process->output_item_id, true);
                        $ids = is_array($data) ? array_column($data, 'id') : [];
                        if(count($ids) == 1){
                            if(!is_null($ids[0])){
                                $items = Item::whereIn('id', $ids)->pluck('item_name', 'id');
                                $process->output_item_ids = $ids;                            
                                $process->output_item_names = $ids ? array_values($items->only($ids)->toArray()) : null;
                            }
                        }
                    }
                });
            });

            // 4 = department Processing
            $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();
            $resultProcess = ProcessingResultProcess::with('details.item', 'details.unit')->get();
            $itemDetails = ItemDetail::with('item', 'unit')->get();
            $categoryEmployees = CategoryEmployee::all();
            $employees = Employee::all();

            $company = Company::first();
            $dept = DB::table("department")->where("department_code","PRO001")->first();
            $date = Carbon::now();
            $dateStart = Carbon::now()->subDays(60);
            $nobukti = Module::generateDocumentNumber($company->companyCode, $dept->department_code, $date->month, $date->year, "PMK", 0);

            $mi =  DB::select("select w.id,w.mutation_in_number from mutation_in_details x
                join mutation_ins w on w.id = x.mutation_in_id
                join mutation_out_details y on x.mutation_out_detail_id = y.id
                join mutation_outs z on z.id = y.mutation_out_id
                join warehouse wh on wh.id = w.warehouse_destination_id
                where (wh.department = 4 or y.processing_id is not null)
                and w.document_date between ? and ?
                group by w.id,w.mutation_in_number",[$dateStart->format('Y-m-d'),$date->format('Y-m-d')]);

            return response()->json([
                'processing_plans' => $processingPlans,
                'result_process' => $resultProcess,
                'warehouses' => $warehouses,
                'item_details' => $itemDetails,
                'category_employees' => $categoryEmployees,
                'mutation_ins' => $mi,
                'employees' => $employees,
                'nobukti' => $nobukti,
                'role' => $this->getRole(),
            ], 200);
        } catch (\Exception $e) {
            \Log::error('Master Data Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to load master data'], 500);
        }
    }

    public function getItemsForProcess($processId)
    {
        try {
            \Log::info('Fetching items for process', ['process_id' => $processId, 'user_id' => Auth::id()]);

            if (!is_numeric($processId) || $processId <= 0) {
                \Log::warning('Invalid process ID provided', ['process_id' => $processId, 'user_id' => Auth::id()]);
                return response()->json(['error' => 'Invalid process ID'], 400);
            }

            $process = Process::findOrFail($processId);

            $itemIds = [];
            $itemOIds = [];

            if (!empty($process->input_item_id)) {
                $outputData = is_string($process->input_item_id) ? json_decode($process->input_item_id, true) : $process->input_item_id;

                if (json_last_error() === JSON_ERROR_NONE && is_array($outputData)) {
                    foreach ($outputData as $item) {
                        if (isset($item['id']) && !empty($item['id'])) {
                            $itemIds[] = (int) $item['id'];
                        } elseif (is_numeric($item) && !empty($item)) {
                            $itemIds[] = (int) $item;
                        }
                    }
                } else {
                    \Log::warning('Failed to decode input_item_id JSON', [
                        'process_id' => $processId,
                        'input_item_id' => $process->input_item_id,
                        'error' => json_last_error_msg(),
                        'user_id' => Auth::id()
                    ]);
                    return response()->json(['error' => 'Invalid output item data'], 422);
                }
            }

            $itemIds = array_unique($itemIds);
            \Log::info($itemIds);

            if (empty($itemIds)) {
                \Log::info('No items found for process', ['process_id' => $processId, 'user_id' => Auth::id()]);
                return response()->json([], 200);
            }

            $outputItemData = is_string($process->output_item_id) ? json_decode($process->output_item_id, true) : $process->output_item_id;

            if (json_last_error() === JSON_ERROR_NONE && is_array($outputItemData)) {
                foreach ($outputItemData as $item) {
                    if (isset($item['id']) && !empty($item['id'])) {
                        $itemOIds[] = (int) $item['id'];
                    } elseif (is_numeric($item) && !empty($item)) {
                        $itemOIds[] = (int) $item;
                    }
                }
            } else {
                \Log::warning('Failed to decode input_item_id JSON', [
                    'process_id' => $processId,
                    'input_item_id' => $process->input_item_id,
                    'error' => json_last_error_msg(),
                    'user_id' => Auth::id()
                ]);
                return response()->json(['error' => 'Invalid output item data'], 422);
            }

            $itemOIds = array_unique($itemOIds);
            
            //item TOP / Casing 
            if($process->is_casing == true){
                $casing = DB::table("category_items as x")->join("items as y",DB::raw("cast(y.category as bigint)"),"=","x.id")
                ->where("x.category_item_code","=","CASING")
                ->select("y.id")->pluck("id")->toArray();
                $itemIds = array_merge($itemIds,$casing);
            }
            if($process->is_top == true){
                $top = DB::table("category_items as x")->join("items as y",DB::raw("cast(y.category as bigint)"),"=","x.id")
                ->where("x.category_item_code","=","TOP")
                ->select("y.id")->pluck("id")->toArray();
                $itemIds = array_merge($itemIds,$top);
            }

            $itemIds = array_unique($itemIds);
            
            $itemDetails = ItemDetail::whereExists(function ($query) use($itemIds) {
                    $query->fromSub(function ($query2) use($itemIds) {
                        $query2->from('item_details')->select('item_id',DB::raw('min(conversion) as conversion'))->whereIn('item_id',$itemIds)->groupBy('item_id');
                    }, 'b')->whereColumn('b.item_id', 'item_details.item_id')->whereColumn('b.conversion', 'item_details.conversion');
                })
                ->with('item', 'unit')
                ->get();

            $itemOutputs = ItemDetail::whereExists(function ($query) use($itemOIds) {
                    $query->fromSub(function ($query2) use($itemOIds) {
                        $query2->from('item_details')->select('item_id',DB::raw('min(conversion) as conversion'))->whereIn('item_id',$itemOIds)->groupBy('item_id');
                    }, 'b')->whereColumn('b.item_id', 'item_details.item_id')->whereColumn('b.conversion', 'item_details.conversion');
                })
                ->with('item', 'unit')
                ->first();

            \Log::info('Items fetched successfully', ['process_id' => $processId, 'count' => $itemDetails->count(), 'user_id' => Auth::id()]);
            \Log::info($itemOutputs);
            return response()->json(['input_items' => $itemDetails, 'output_item' => $itemOutputs], 200);
        } catch (ModelNotFoundException $e) {
            \Log::error('Process not found', [
                'process_id' => $processId,
                'error' => $e->getMessage(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Process not found'], 404);
        } catch (\Exception $e) {
            dd($e->getMessage());
            \Log::error('Failed to fetch items for process', [
                'process_id' => $processId,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to load items for process'], 500);
        }
    }

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

    public function print($id)
    {
        try {
            if (!is_numeric($id) || $id <= 0) {
                return response()->json(['error' => 'Invalid ID'], 400);
            }
            $pengeluaranBahan = ProcessingPengeluaranBahan::with(['details.item'])->where('id', $id)->firstOrFail();
            $iu = ItemUnit::get();
            $imagePath = storage_path('app/images/logo-only.png');
            if (!file_exists($imagePath)) {
                \Log::error('Print Error: Logo image not found', [
                    'id' => $id,
                    'path' => $imagePath,
                    'user_id' => Auth::id()
                ]);
                return response()->json(['error' => 'Logo image not found'], 500);
            }
            $imageData = file_get_contents($imagePath);

            foreach ($pengeluaranBahan->details as $detail) {
                $unit = $iu->where('id', $detail->unit)->first();
                $detail->unit = $unit ? $unit->unit_name : 'Unknown';
            }
            $username = Auth::user()->name;
            $pdf = \PDF::loadView('print.processing_material_release_pdf', compact('pengeluaranBahan', 'imageData','username'))->setPaper('A5', 'landscape');
            return ["data" => "data:application/pdf;base64,".base64_encode($pdf->stream()),"role" => $this->getRole()];
        } catch (ModelNotFoundException $e) {
            \Log::error('Print Error: Record not found', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Material release not found'], 404);
        } catch (\Exception $e) {
            \Log::error('Print Error', [
                'id' => $id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to generate PDF'], 500);
        }
    }

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

    public function summary($dateStart, $dateEnd)
    {
        try {
            $pengeluaranBahans = DB::table("processing_pengeluaran_bahan_details as x")
            ->join("processing_pengeluaran_bahans as y","x.pengeluaran_bahan_id","=","y.id")
            ->join("processing_plans as pp","pp.id", "=", "y.plan_id")
            ->join("process as pr","pr.id", "=", "y.process_id")
            ->join("items as i","i.id", "=", "x.item_id")
            ->join("item_units as iu","iu.id", "=", DB::raw("cast(x.unit as bigint)"))
            ->whereBetween("y.document_date",[$dateStart, $dateEnd])
            ->select("i.item_name",DB::raw("sum(x.qty) qty"),"iu.unit_name",
            "pp.plan_id","pr.process_name","pp.production_start_date","pp.production_end_date")
            ->groupBy("i.item_name","iu.unit_name",
            "pp.plan_id","pr.process_name","pp.production_start_date","pp.production_end_date")
            ->get();
            
            return response()->json(["pengeluaranBahans" => $pengeluaranBahans, "role" => $this->getRole()], 200);
        } catch (\Exception $e) {
            \Log::error('Summary Detail Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to fetch material releases detail summary'], 500);
        }
    }

    public function summaryDetail($dateStart, $dateEnd)
    {
        try {
            $pengeluaranBahanDetails = DB::table("processing_pengeluaran_bahan_details as x")
            ->join("processing_pengeluaran_bahans as y","x.pengeluaran_bahan_id","=","y.id")
            ->join("processing_plans as pp","pp.id", "=", "y.plan_id")
            ->join("process as pr","pr.id", "=", "y.process_id")
            ->join("items as i","i.id", "=", "x.item_id")
            ->join("item_units as iu","iu.id", "=", DB::raw("cast(x.unit as bigint)"))
            ->join("warehouse as wh","wh.id", "=", "y.warehouse_id")
            ->whereBetween("y.document_date",[$dateStart, $dateEnd])
            ->select("y.pengeluaran_bahan_id as document_number","y.document_date","i.item_name","x.qty","iu.unit_name",
            "pp.plan_id","pr.process_name","wh.warehouse_name")
            ->get();
            
            return response()->json(["pengeluaranBahanDetails" => $pengeluaranBahanDetails, "role" => $this->getRole()], 200);
        } catch (\Exception $e) {
            \Log::error('Summary Detail Error', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Failed to fetch material releases detail summary'], 500);
        }
    }

    public function reCalc(){
        $data = DB::table("processing_pengeluaran_bahans")->get();
        DB::beginTransaction();
        try {
            $company = Company::first();
            $department = Department::where('department_code','PRO001')->first();
            foreach($data as $dat){
                $pengeluaranBahan = ProcessingPengeluaranBahan::find($dat->id);

                $det = DB::table("processing_pengeluaran_bahan_details")->where("pengeluaran_bahan_id",$pengeluaranBahan->id)->get();
                Journal::where("document_number",$pengeluaranBahan->pengeluaran_bahan_id)->delete();

                foreach ($det as $detail) {
                    $itemDetail = ItemDetail::where("item_id", $detail->item_id)->where("unit_id", $detail->unit)->first();

                    //$cogs = Module::getCogs($pengeluaranBahan->document_date,$detail->item_id,$company->companyCode,$department->id,$pengeluaranBahan->warehouse_id);
                    // DB::table('inventory_details')->insert([
                    //     'document_number' => $kasirPengeluaranBahan->kasir_pengeluaran_bahan_number,
                    //     'document_date' => $kasirPengeluaranBahan->document_date,
                    //     'transaction_type' => 'Kasir Production Penggunaan Bahan',
                    //     'warehouse_id' => $kasirPengeluaranBahan->warehouse_id,
                    //     'item_id' => $detail->item_id,
                    //     'quantity' => $detail->qty,
                    //     'unit' => $detail->unit,
                    //     'base_quantity' => $itemDetail->conversion,
                    //     'unit_base' => $itemDetail->item->base_unit_id,
                    //     'department_id' => $department->id,
                    //     'company_code' => $company->companyCode,
                    //     'total' => $cogs * $detail->qty * $itemDetail->conversion,
                    //     'cogs' => -1 * ($cogs * $detail->qty * $itemDetail->conversion),
                    //     'qty_actual' => -1 * $detail->qty,
                    //     'created_by' => Auth::user()->id,
                    //     'updated_by' => Auth::user()->id,
                    //     'created_at' => now(),
                    //     'updated_at' => now(),
                    // ]);

                    $ambilCogs = DB::table("inventory_details")->where("document_number",$pengeluaranBahan->pengeluaran_bahan_id)
                    ->where("item_id",$detail->item_id)->where("unit",$detail->unit)
                    ->where("base_quantity",$itemDetail->conversion)->first();

                    $it = Item::find($detail->item_id);
                    if($it){
                        $accWip = $it->categoryItem->acc_number_wip;
                        Journal::create([
                            'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                            'document_date' => $pengeluaranBahan->document_date,
                            'account_number' => $accWip,
                            'notes' => 'Persediaan dalam WIP: ' . $it->item_name,
                            'debet_nominal' => $ambilCogs->cogs * -1,
                            'credit_nominal' => 0,
                            'debet_nominal_base' => $ambilCogs->cogs * -1,
                            'credit_nominal_base' => 0,
                            'company_code' => $company->companyCode,
                            'department_id' => $department->id,
                            'created_by' => Auth::user()->id,
                            'updated_by' => Auth::user()->id,
                        ]);
                        
                        Journal::create([
                            'document_number' => $pengeluaranBahan->pengeluaran_bahan_id,
                            'document_date' => $pengeluaranBahan->document_date,
                            'account_number' => $it->categoryItem->account_inventory,
                            'notes' => 'Persediaan: ' . $it->item_name,
                            'debet_nominal' => 0,
                            'credit_nominal' => $ambilCogs->cogs * -1,
                            'debet_nominal_base' => 0,
                            'credit_nominal_base' => $ambilCogs->cogs * -1,
                            'company_code' => $company->companyCode,
                            'department_id' => $department->id,
                            'created_by' => Auth::user()->id,
                            'updated_by' => Auth::user()->id,
                        ]);
                    }
                }
            }
            DB::commit();
            return response()->json(null);
        } catch (\Exception $e) {
            DB::rollback();
            return response()->json(['error' => 'Server error'], 500);
        }
    }
}
