<?php

namespace App\Http\Controllers;

use App\Models\MutationIn;
use App\Models\MutationInDetail;
use App\Models\MutationOut;
use App\Models\Department;
use App\Models\ItemDetail;
use App\Models\Company;
use App\Models\Warehouse;
use App\Models\ItemUnit;
use App\Models\Item;
use App\Models\Periode;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\QueryException;
use App\Models\DeleteLog;
use App\Http\Controllers\Module;
use Carbon\Carbon;

class MutationInController extends Controller
{
    public function index($dateStart,$dateEnd)
    {
        try {
            $mutationIn = MutationIn::with('details.item','details.unit','warehouseOrigin','warehouseDestination','department')
            ->whereBetween('document_date',[$dateStart,$dateEnd])
            ->whereIn('department_id',$this->getDepartment())->get();
            $periods = Periode::all();
            foreach($mutationIn as $mi){
                $mi->closed =  Module::checkPeriodeBack($periods,$mi->document_date);
            }
            return response()->json(["mutationIn" => $mutationIn,"role" => $this->getRole()]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch mutation in'], 500);
        }
    }

    public function summary($dateStart, $dateEnd)
    {
        try {
            $mutationIn = MutationIn::with([
                'details' => function ($query) {
                    $query->with(['item' => function ($q) {
                        $q->with('itemDetails.unit');
                    }, 'unit']);
                },
                'warehouseOrigin',
                'warehouseDestination',
                'department'
            ])
                ->whereBetween('document_date', [$dateStart, $dateEnd])
                ->whereIn('department_id', $this->getDepartment())
                ->get();
            $periods = Periode::all();
            foreach ($mutationIn as $mi) {
                $mi->closed = Module::checkPeriodeBack($periods, $mi->document_date);
            }
            return response()->json(["mutationIn" => $mutationIn, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Failed to fetch mutation in summary'], 500);
        }
    }

    public function store(Request $request)
    {   
        $validated = $request->validate([
            'document_date' => 'required|date',
            'warehouse_origin_id' => 'required|integer|exists:warehouse,id',
            'warehouse_destination_id' => 'required|integer|exists:warehouse,id',
            'notes' => 'nullable|string',
            'department_id' => 'required|integer|exists:department,id',
            'details' => 'required|array|min:1',
            'details.*.item_id' => 'required|integer|exists:item_details,item_id',
            'details.*.qty' => 'required|numeric|min:0',
            'details.*.unit' => 'required|integer|exists:item_units,id',
            'details.*.description' => 'nullable|string',
            'details.*.item_date' => 'nullable|date',
        ]);

        DB::beginTransaction();
        try {
            $company = Company::first();
            $department = Department::find($request->department_id);
            $date = Carbon::parse($request->document_date);
            $nobukti = Module::generateDocumentNumber($company->companyCode,$department->department_code,$date->month,$date->year,"MUIN",1);

            $userId = Auth::user()->id;
            $mutationIn = MutationIn::create([
                'mutation_in_number' => $nobukti,
                'document_date' => $request->document_date,
                'warehouse_origin_id' => $request->warehouse_origin_id,
                'warehouse_destination_id' => $request->warehouse_destination_id,
                'status' => 'Not',
                'notes' => $request->notes ?? '',
                'department_id' => $request->department_id,
                'created_by' => $userId,
                'updated_by' => $userId
            ]);

            $prUpdates = [];
            foreach ($request->details as $detail) {
                $itemD = ItemDetail::with(["item"])->where("item_id",$detail['item_id'])->where("unit_id",$detail['unit'])->first();
                $mutationOutDetail = MutationInDetail::create([
                    'mutation_in_id' => $mutationIn->id,
                    'mutation_out_id' => $detail["mutation_out_id"],
                    'mutation_out_detail_id' => $detail["mutation_out_detail_id"],
                    'item_date' => $detail['item_date'],
                    'item_id' => $detail['item_id'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'base_qty' => $itemD->conversion,
                    'description' => $detail['description'] ?? '',
                    'department_id' => $mutationIn->department_id,
                    'qty_left' => $detail['qty'],
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                $cogs = Module::getCogs($mutationIn->document_date,$detail['item_id'],$company->companyCode,$mutationIn->department_id,$request->warehouse_origin_id);

                DB::table('inventory_details')->insert([
                    'document_number' => $mutationIn->mutation_in_number,
                    'document_date' => $request->document_date,
                    'transaction_type' => 'Mutation In',
                    'warehouse_id' => $request->warehouse_destination_id,
                    'item_id' => $detail['item_id'],
                    'quantity' => $detail['qty'],
                    'unit' => $detail['unit'] ?? null,
                    'base_quantity' => $itemD->conversion,
                    'unit_base' => $itemD->item->base_unit_id,
                    'department_id' => $mutationIn->department_id,
                    'company_code' => $company->companyCode,
                    'total' => $cogs,
                    'cogs' => ($cogs * $detail['qty'] * $itemD->conversion),
                    'qty_actual' => $detail['qty'],
                    'created_by' => $userId,
                    'updated_by' => $userId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                if ($detail['mutation_out_id']) {
                    $prId = $detail['mutation_out_id'];
                    $mutationOut = MutationOut::find($prId);
                    if ($mutationOut) {
                        $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                        $prDetail = $mutationOut->details()->where('id', $detail['mutation_out_detail_id'])->first();
                        if ($prDetail) {
                            $newQtyLeft = max(0, $prDetail->qty_left - $detail['qty']);
                            $prDetail->update(['qty_left' => $newQtyLeft]);
                            if (!isset($prUpdates[$prId])) {
                                $prUpdates[$prId] = $mutationOut;
                            }
                        }
                    }
                }
            }

            foreach ($prUpdates as $prId => $mutationOut) {
                $remainingQtyLeft = $mutationOut->details()->sum('qty_left');
                $newStatus = $remainingQtyLeft == 0 ? 'Completed' : 'partial';
                $mutationOut->update(['status' => $newStatus]);
            }

            DB::commit();
            return response()->json(null, 201);
        } catch (\Exception $e) {
            DB::rollback();
            dd($e->getTrace());
            return response()->json(['error' => $e->getMessage()], 422);
        }
    }
    public function show($id)
    {
        try {
            $mutationIn = MutationIn::with(['details.item', 'details.unit', 'department'])->findOrFail($id);
            return response()->json($mutationIn);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Mution out not found or failed to fetch'], 404);
        }
    }

    public function update(Request $request, $id)
    {
        DB::beginTransaction();
        try {
            $mutationIn = MutationIn::findOrFail($id);
            $validated = $request->validate([
                'document_date' => 'required|date',
                'warehouse_origin_id' => 'required|integer|exists:warehouse,id',
                'warehouse_destination_id' => 'required|integer|exists:warehouse,id',
                'notes' => 'nullable|string',
                'department_id' => 'required|integer|exists:department,id',
                'details' => 'required|array|min:1',
                'details.*.item_id' => 'required|integer|exists:item_details,item_id',
                'details.*.qty' => 'required|numeric|min:0',
                'details.*.unit' => 'required|integer|exists:item_units,id',
                'details.*.description' => 'nullable|string',
                'details.*.item_date' => 'nullable|date',
            ]);
            $company = Company::first();
            $date = Carbon::parse($request->document_date);
            $userId = Auth::user()->id;

            $oldDetails = $mutationIn->details()->get();
            $oldPRs = $oldDetails->pluck('mutation_out_id')->filter()->unique()->toArray();

            foreach ($oldDetails as $oldDetail) {
                if ($oldDetail->mutation_out_id) {
                    $pr = MutationOut::find($oldDetail->mutation_out_id);
                    if ($pr) {
                        $prDetail = $pr->details()->where('id', $oldDetail->mutation_out_detail_id)->first();
                        if ($prDetail) {
                            $prDetail->update(['qty_left' => $prDetail->qty_left + $oldDetail->qty]);
                        }
                    }
                }
            }

            foreach ($oldPRs as $prId) {
                $mutationOut = MutationOut::find($prId);
                if ($mutationOut) {
                    $remainingQtyLeft = $mutationOut->details()->sum('qty_left');
                    $newStatus = $remainingQtyLeft == $mutationOut->details()->sum('qty') ? 'Not' : 'partial';
                    $mutationOut->update(['status' => $newStatus]);
                }
            }

            $mutationIn->update([
                'status' => 'Not',
                'notes' => $request->notes ?? '',
                'department_id' => $request->department_id,
                'warehouse_origin_id' => $request->warehouse_origin_id,
                'warehouse_destination_id' => $request->warehouse_destination_id,
                'updated_by' => $userId,
            ]);

            
            $mutationIn->details()->delete();
            DB::table('inventory_details')->where("document_number",$mutationIn->mutation_in_number)->delete();

            // Proses setiap detail dari request
            foreach ($request->details as $detail) {
                $itemD = ItemDetail::with(["item"])->where("item_id",$detail['item_id'])->where("unit_id",$detail['unit'])->first();
                $cogs = Module::getCogs($mutationIn->document_date,$detail['item_id'],$company->companyCode,$mutationIn->department_id,$request->warehouse_origin_id);
                $mutationInDetail = MutationInDetail::create([
                    'mutation_in_id' => $mutationIn->id,
                    'mutation_out_id' => $detail["mutation_out_id"],
                    'mutation_out_detail_id' => $detail["mutation_out_detail_id"],
                    'item_date' => $detail['item_date'],
                    'item_id' => $detail['item_id'],
                    'qty' => $detail['qty'],
                    'unit' => $detail['unit'],
                    'base_qty' => $itemD->conversion,
                    'description' => $detail['description'] ?? '',
                    'department_id' => $mutationIn->department_id,
                    'qty_left' => $detail['qty'],
                    'created_by' => $mutationIn->created_by,
                    'updated_by' => $userId,
                ]);
                DB::table('inventory_details')->insert([
                    'document_number' => $mutationIn->mutation_in_number,
                    'document_date' => $request->document_date,
                    'transaction_type' => 'Mutation In',
                    'warehouse_id' => $request->warehouse_destination_id,
                    'item_id' => $detail['item_id'],
                    'quantity' => $detail['qty'],
                    'unit' => $detail['unit'] ?? null,
                    'base_quantity' => $itemD->conversion,
                    'unit_base' => $itemD->item->base_unit_id,
                    'department_id' => $mutationIn->department_id,
                    'company_code' => $company->companyCode,
                    'total' => $cogs,
                    'cogs' => ($cogs * $detail['qty'] * $itemD->conversion),
                    'qty_actual' => $detail['qty'],
                    'created_by' => $mutationIn->created_by,
                    'updated_by' => $userId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);

                if ($detail['mutation_out_id']) {
                    $prId = $detail['mutation_out_id'];
                    $mutationOut = MutationOut::find($prId);
                    if ($mutationOut) {
                        $itemDetail = ItemDetail::where('item_id', $detail['item_id'])->where('unit_id', $detail['unit'])->first();
                        $prDetail = $mutationOut->details()->where('id', $detail['mutation_out_detail_id'])->first();
                        if ($prDetail) {
                            $newQtyLeft = max(0, $prDetail->qty_left - $detail['qty']);
                            $prDetail->update(['qty_left' => $newQtyLeft]);
                            if (!isset($prUpdates[$prId])) {
                                $prUpdates[$prId] = $mutationOut;
                            }
                        }
                    }
                }
            }

            foreach ($prUpdates as $prId => $mutationOut) {
                $remainingQtyLeft = $mutationOut->details()->sum('qty_left');
                $newStatus = $remainingQtyLeft == 0 ? 'Completed' : 'partial';
                $mutationOut->update(['status' => $newStatus]);
            }

            DB::commit();
            return response()->json(null, 200);
        } catch (\Exception $e) {
            DB::rollback();
            dd($e);
            return response()->json(['error' => $e->getMessage()], 422);
        }
    }

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

            $mutationIn = MutationIn::findOrFail($id);

            $oldDetails = $mutationIn->details()->get();
            $oldPRs = $oldDetails->pluck('mutation_out_id')->filter()->unique()->toArray();

            foreach ($oldDetails as $oldDetail) {
                if ($oldDetail->mutation_out_id) {
                    $pr = MutationOut::find($oldDetail->mutation_out_id);
                    if ($pr) {
                        $prDetail = $pr->details()->where('id', $oldDetail->mutation_out_detail_id)->first();
                        if ($prDetail) {
                            $prDetail->update(['qty_left' => $prDetail->qty_left + $oldDetail->qty]);
                        }
                    }
                }
            }

            foreach ($oldPRs as $prId) {
                $mutationOut = MutationOut::find($prId);
                if ($mutationOut) {
                    $remainingQtyLeft = $mutationOut->details()->sum('qty_left');
                    $newStatus = $remainingQtyLeft == $mutationOut->details()->sum('qty') ? 'Not' : 'partial';
                    $mutationOut->update(['status' => $newStatus]);
                }
            }

            $mutationIn->details()->delete();
            $mutationIn->delete();
            DB::table('inventory_details')->where("document_number",$mutationIn->mutation_in_number)->delete();

            DeleteLog::create([
                'document_number' => $mutationIn->mutation_in_number,
                'document_date' => $mutationOut->document_date,
                'delete_notes' => $request->delete_notes ?? 'No notes provided',
                'company_code' => null,
                'department_code' => $mutationOut->department_id,
                'deleted_by' => Auth::check() ? Auth::user()->name : 'system',
                'type' => 'Mutation In',
            ]);

            DB::commit();
            return response()->json(null, 204);
        } catch (QueryException $e) {
            DB::rollBack();
            if ($e->getCode() === '23000') {
                return response()->json(['error' => 'Cannot delete mutation out because it is being used in other records'], 422);
            }
            return response()->json(['error' => 'Failed to delete mutation out due to database error'], 500);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => 'Failed to delete mutation out due to an unexpected error'], 500);
        }
    }

    public function getMasterData()
    {
        $Listdepartment = $this->getDepartment();
        //$departments = Department::whereIn("id",$Listdepartment)->get();
        //khusus mutasi tdk dibatasi saat input
        $departments = Department::get();
        $gudangUser = DB::table("user_warehouse")->where("user_id",Auth::user()->id)->select("warehouse_id")->get()->pluck("warehouse_id")->toArray();
        $warehouses = Warehouse::all();

        //khusus mutasi tdk dibatasi saat input
        //->whereIn("department_id",$Listdepartment)
        $mutationOut = MutationOut::with(['details.item','details.units','details'=> function($q){
            $q->where("qty_left",">",0);
        }])->whereRaw('id in (select distinct mutation_out_id from mutation_out_details where qty_left > 0)')->get();

        $items = Item::with(['itemDetails' => function($q) {
            $q->where("is_active",1);
        },'itemDetails.unit'])->get();
        $itemDetails = ItemDetail::with(['item'])->where("is_active",1)->get();
        $itemUnit = ItemUnit::get();

        $company = Company::first();
        $date = Carbon::now();
        $nobukti = Module::generateDocumentNumber($company->companyCode,$departments->first()->department_code,$date->month,$date->year,"MUIN",0);

        $response = [
            'departments' => $departments,
            'warehouses' => $warehouses,
            'gudangUser' => $gudangUser,
            'items' => $items,
            'item_unit' => $itemUnit,
            'item_details' => $itemDetails,
            'nobukti' => $nobukti,
            'mutationOut' => $mutationOut,
            "role" => $this->getRole()
        ];
        return response()->json($response);
    }

    public function getNomorBukti(Request $request)
    {
        $company = Company::first();
        $department = Department::find($request->department_id);
        $date = Carbon::parse($request->document_date);
        $nobukti = Module::generateDocumentNumber($company->companyCode,$department->department_code,$date->month,$date->year,"MUIN",0);
        return response()->json($nobukti);
    }
}