<?php

namespace App\Http\Controllers;

use App\Models\ProcessingPlan;
use App\Models\ProcessingPlanDetail;
use App\Models\ItemDetail;
use App\Models\ItemUnit;
use App\Models\Item;
use App\Models\Process;
use App\Models\Company;
use App\Models\Department;
use App\Models\DeleteLog;
use App\Models\Warehouse;
use App\Http\Controllers\Module;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use PDF;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class ProcessingPlanController extends Controller
{
    public function index($dateStart,$dateEnd): JsonResponse
    {
        try {
            $Listdepartment = $this->getDepartment();
            $plans = ProcessingPlan::with([
                'item',
                'unit',
                'details.process',
                'createdBy',
                'updatedBy',
                'ProcessingPenerimaanBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingPengeluaranBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingResultProcess' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                }
            ])->whereBetween('production_start_date',[$dateStart,$dateEnd])
            ->whereIn('department_id',$Listdepartment)
                ->orderBy('plan_id')
                ->get();
            return response()->json(["plans" => $plans, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Failed to fetch processing plans', [
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ]);
            return response()->json(['error' => 'Failed to fetch processing plans', 'details' => $e->getMessage()], 500);
        }
    }

    public function statusIndex($dateStart,$dateEnd): JsonResponse
    {
        try {
            $plans = ProcessingPlan::with([
                'item',
                'unit',
                'details.process',
                'createdBy',
                'updatedBy',
                'ProcessingPenerimaanBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingPengeluaranBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingResultProcess' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                }
            ])->whereBetween('production_start_date',[$dateStart,$dateEnd])
                ->orderBy('plan_id')
                ->get();
            return response()->json(["plans" => $plans, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Failed to fetch processing plans for status', [
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ]);
            return response()->json(['error' => 'Failed to fetch processing plans for status', 'details' => $e->getMessage()], 500);
        }
    }

    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'production_start_date' => 'required|date',
            'production_end_date' => 'required|date|after_or_equal:production_start_date',
            'item_id' => 'required|exists:item_details,id',
            'processing_method' => 'nullable|string',
            'qty_prod' => 'required|numeric|min:1',
            'unit' => 'required|integer',
            'status' => 'nullable|string|in:Pending,In Progress,Completed',
            'processing_plan_details' => 'array',
            'processing_plan_details.*.process_id' => 'required|exists:process,id',
            'department_id' => 'required|exists:department,id',
        ]);

        try {
            DB::beginTransaction();

            $company = Company::first();
            $department = Department::find($request->department_id);
            $date = Carbon::now();
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "PPL", 1);

            $itemDetail = ItemDetail::where("id",$request->item_id)->first();
            $plan = ProcessingPlan::create([
                'plan_id' => $nobukti,
                'production_start_date' => $request->production_start_date,
                'production_end_date' => $request->production_end_date,
                'status' => $request->status ?? 'Pending',
                'processing_method' => $request->processing_method,
                'item_id' => $itemDetail->item_id,
                'qty_prod' => $request->qty_prod,
                'unit' => $request->unit,
                'base_qty' => $itemDetail->conversion,
                'department_id' => $request->department_id,
                'created_by' => auth()->id(),
                'updated_by' => auth()->id(),
            ]);

            if ($request->has('processing_plan_details')) {
                foreach ($request->processing_plan_details as $detail) {
                    ProcessingPlanDetail::create([
                        'plan_id' => $plan->id,
                        'process_id' => $detail['process_id'],
                        'status' => 'Pending',
                        'department_id' => $request->department_id,
                        'created_by' => auth()->id(),
                        'updated_by' => auth()->id(),
                    ]);
                }
            }

            DB::commit();

            $plan->load(['item', 'details.process']);
            return response()->json($plan, 201);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error($e->getMessage());
            return response()->json(['error' => 'Failed to create processing plan: ' . $e->getMessage()], 500);
        }
    }

    public function show($plan_id): JsonResponse
    {
        try {
            $plan = ProcessingPlan::with(['item', 'unit', 'details.process', 'createdBy', 'updatedBy'])
                ->where('id', $plan_id)
                ->firstOrFail();
            return response()->json($plan);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Processing plan not found'], 404);
        }
    }

    public function update(Request $request, $plan_id): JsonResponse
    {
        $validated = $request->validate([
            'production_start_date' => 'required|date',
            'production_end_date' => 'required|date|after_or_equal:production_start_date',
            'item_id' => 'required|exists:item_details,id',
            'processing_method' => 'nullable|string',
            'qty_prod' => 'required|numeric|min:1',
            'unit' => 'required|integer',
            'status' => 'nullable|string|in:Pending,In Progress,Completed',
            'processing_plan_details' => 'array',
            'processing_plan_details.*.process_id' => 'required|exists:process,id',
            'department_id' => 'required|exists:department,id',
        ]);

        try {
            DB::beginTransaction();

            $plan = ProcessingPlan::where('id', $plan_id)->firstOrFail();
            $itemDetail = ItemDetail::where("id", $request->item_id)->first();
            $plan->update([
                'production_start_date' => $request->production_start_date,
                'production_end_date' => $request->production_end_date,
                'status' => $request->status ?? $plan->status,
                'processing_method' => $request->processing_method,
                'item_id' => $itemDetail->item_id,
                'qty_prod' => $request->qty_prod,
                'unit' => $request->unit,
                'base_qty' => $itemDetail->conversion,
                'department_id' => $request->department_id,
                'updated_by' => auth()->id(),
            ]);

            if ($request->has('processing_plan_details')) {
                $existingDetailIds = $plan->details->pluck('id')->toArray();
                $submittedDetailIds = array_filter(array_column($request->processing_plan_details, 'id'));

                $toDelete = array_diff($existingDetailIds, $submittedDetailIds);
                ProcessingPlanDetail::whereIn('id', $toDelete)->delete();

                foreach ($request->processing_plan_details as $detail) {
                    if (isset($detail['id']) && in_array($detail['id'], $existingDetailIds)) {
                        ProcessingPlanDetail::find($detail['id'])->update([
                            'process_id' => $detail['process_id'],
                            'department_id' => $request->department_id,
                        ]);
                    } else {
                        ProcessingPlanDetail::create([
                            'plan_id' => $plan->id,
                            'process_id' => $detail['process_id'],
                            'status' => 'Pending',
                            'department_id' => $request->department_id,
                            'created_by' => $plan->created_by,
                            'updated_by' => auth()->id(),
                        ]);
                    }
                }
            }

            DB::commit();
            return response()->json(null);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => 'Failed to update processing plan: ' . $e->getMessage()], 500);
        }
    }

    public function destroy(Request $request, $plan_id): JsonResponse
    {
        try {
            DB::beginTransaction();
            $plan = ProcessingPlan::where('id', $plan_id)->firstOrFail();
            $plan->details()->delete();
            $plan->delete();

            DeleteLog::create([
                'document_number' => $plan->plan_id,
                'document_date' => now(),
                'delete_notes' => $request->delete_notes ?? 'No notes provided',
                'company_code' => null,
                'department_code' => null,
                'deleted_by' => Auth::check() ? Auth::user()->name : 'system',
                'type' => 'Processing Plan',
            ]);
            DB::commit();
            return response()->json(null, 204);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => 'Failed to delete processing plan'], 500);
        }
    }

    public function getMasterData(): JsonResponse
    {
        try {
            $company = Company::first();
            $date = Carbon::now();
            $dept = DB::table("department")->where("department_code","PRO001")->first();
            $nobukti = Module::generateDocumentNumber($company->companyCode, $dept->department_code, $date->month, $date->year, "PPL", 0);
            $processing = Process::where('department', 'PRO001')
                ->orderBy('process_code')
                ->get();
            $processing->each(function ($item) {
                $data = json_decode($item->output_item_id, true);
                if (is_array($data)) {
                    $ids = array_column($data, 'id');
                } else {
                    $ids = [];
                }
                $items = Item::whereIn('id', $ids)->pluck('item_name', 'id');
                $items = array_values($items->toArray());
                $item->output_item_ids = $ids;
                $item->output_item_names = $items;
            });

            $gudangUser = DB::table("user_warehouse")->where("user_id",Auth::user()->id)->select("warehouse_id")->get()->pluck("warehouse_id")->toArray();
            $warehouses = Warehouse::whereIn("id",$gudangUser)->pluck("id")->toArray();

            //$wh = DB::table("warehouse")->where("department",$dept->id)->pluck("id")->toArray();
            $it = Item::whereIn("warehouse_id",$warehouses)->pluck("id")->toArray();
            $data = [
                'item_details' => ItemDetail::with(['item', 'unit'])->whereIn("item_id",$it)->orderBy('id')->get(),
                'processes' => $processing,
                'processing_method' => array(
                (object)[
                    "id" => 'Steam',
                    "name" => 'Steam'
                ],(object)[
                    "id" => 'Non Steam',
                    "name" => 'Non Steam'
                ],(object)[
                    "id" => 'Campur',
                    "name" => 'Campur'
                ],(object)[
                    "id" => 'Manual',
                    "name" => 'Manual'
                ],(object)[
                    "id" => 'Lain - lain',
                    "name" => 'Lain - lain'
                ]),
                'departments' => Department::where("department_code","PRO001")->orderBy('id')->get(),
                'nobukti' => $nobukti,
                'role' => $this->getRole()
            ];
            return response()->json($data);
        } catch (\Exception $e) {
            Log::error('Master data fetch error: ' . $e->getMessage());
            return response()->json(['error' => 'Failed to fetch master data'], 500);
        }
    }

    public function print($id)
    {
        try {
            if (!is_numeric($id) || $id <= 0) {
                Log::warning('Invalid ID provided for PDF generation', [
                    'id' => $id,
                    'user_id' => Auth::id()
                ]);
                return response()->json(['error' => 'Invalid ID'], 400);
            }

            $plan = ProcessingPlan::with([
                'item',
                'unit',
                'details.process',
                'createdBy',
                'updatedBy',
                'ProcessingPenerimaanBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingPengeluaranBahan' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                },
                'ProcessingResultProcess' => function ($query) {
                    $query->with(['details.item', 'details.unit', 'warehouse', 'process']);
                }
            ])->where('id', $id)->firstOrFail();

            $iu = ItemUnit::get();
            $imagePath = storage_path('app/images/logo-only.png');

            if (!file_exists($imagePath)) {
                \Log::error('Logo image not found for ProductionPlan PDF', ['path' => $imagePath, 'user_id' => Auth::id()]);
                return response()->json(['error' => 'Logo image not found'], 500);
            }

            $imageData = file_get_contents($imagePath);
            if ($imageData === false) {
                \Log::error('Failed to read logo image for ProductionPlan PDF', ['path' => $imagePath, 'user_id' => Auth::id()]);
                return response()->json(['error' => 'Failed to read logo image'], 500);
            }

            $plan->unit_name = ItemUnit::where('id', $plan->unit)->first()->unit_name ?? 'Unknown';

            $plan->ProcessingPenerimaanBahan = $plan->ProcessingPenerimaanBahan ?? collect([]);
            $plan->ProcessingPengeluaranBahan = $plan->ProcessingPengeluaranBahan ?? collect([]);
            $plan->ProcessingResultProcess = $plan->ProcessingResultProcess ?? collect([]);

            foreach ($plan->ProcessingPenerimaanBahan as $penerimaan) {
                $penerimaan->details = $penerimaan->details ?? collect([]);
                foreach ($penerimaan->details as $detail) {
                    $unit = $iu->where('id', $detail->unit)->first();
                    $detail->unit_name = $unit ? $unit->unit_name : 'Unknown';
                }
            }

            foreach ($plan->ProcessingPengeluaranBahan as $pengeluaran) {
                $pengeluaran->details = $pengeluaran->details ?? collect([]);
                foreach ($pengeluaran->details as $detail) {
                    $unit = $iu->where('id', $detail->unit)->first();
                    $detail->unit_name = $unit ? $unit->unit_name : 'Unknown';
                }
            }

            foreach ($plan->ProcessingResultProcess as $result) {
                $result->details = $result->details ?? collect([]);
                foreach ($result->details as $detail) {
                    $unit = $iu->where('id', $detail->unit)->first();
                    $detail->unit_name = $unit ? $unit->unit_name : 'Unknown';
                }
            }
            $username = Auth::user()->name;
            $pdf = PDF::loadView('print.processing_status_pdf', [
                'plan' => $plan,
                'imageData' => $imageData,
                'penerimaanBahan' => $plan->ProcessingPenerimaanBahan,
                'pengeluaranBahan' => $plan->ProcessingPengeluaranBahan,
                'resultProcess' => $plan->ProcessingResultProcess,
                'username' => $username
            ])->setPaper('A5', 'landscape');

            Log::info('PDF generated successfully for ProcessingPlan', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return "data:application/pdf;base64," . base64_encode($pdf->output());
        } catch (ModelNotFoundException $e) {
            Log::error('Print Error: Processing plan not found', [
                'id' => $id,
                'user_id' => Auth::id()
            ]);
            return response()->json(['error' => 'Processing plan 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);
        }
    }


}
