<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Department;
use App\Models\Warehouse;
use App\Models\Coa;
use App\Models\Item;
use App\Models\ItemUnit;
use App\Models\ItemDetail;
use App\Models\Company;
use App\Models\Correction;
use App\Models\CorrectionDetail;
use App\Models\CategoryItem;
use App\Models\Journal;
use App\Models\Periode;
use App\Models\DeleteLog;
use DB;
use Auth;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class CorrectionController extends Controller
{
    public function index($dateStart,$dateEnd)
    {
        try {
            $correction = DB::table("corrections as x")
            ->join("correction_details as y","x.id","=","y.correction_id")
            ->join("items as i","i.id","=","y.item_id")
            ->join("item_units as iu","iu.id","=","y.unit_id")
            ->join("department as d","d.id","=","x.department_id")
            ->join("warehouse as w","w.id","=","y.warehouse_id")
            ->whereBetween('x.document_date',[$dateStart,$dateEnd])
            ->whereIn('x.department_id',$this->getDepartment())
            ->select("x.id","x.correction_number","x.document_date","i.item_name","i.item_code","iu.unit_name","y.qty_in","y.qty_out","y.qty",
            "d.department_name","w.warehouse_name","y.notes as detail_notes")->get();
            $periods = Periode::all();
            foreach($correction as $pp){
                $pp->closed =  Module::checkPeriodeBack($periods,$pp->document_date);
            }
            return response()->json(["correction" => $correction,"role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Failed to fetch correction', ['error' => $e->getMessage()]);
            return response()->json(['error' => 'Failed to fetch correction'], 500);
        }
    }

    public function store(Request $request)
    {
        $request->validate([
            'document_date' => 'required|date',
            'coa_id' => 'nullable|integer|exists:coa,id',
            'notes' => 'nullable|string',
            'department_id' => 'required|integer|exists:department,id',
            'details' => 'required|array|min:1',
            'details.*.item_date' => 'nullable|date',
            'details.*.item_id' => 'required|integer|exists:items,id',
            'details.*.unit_id' => 'required|integer|exists:item_units,id',
            'details.*.warehouse_id' => 'required|integer|exists:warehouse,id',
            'details.*.qty_in' => 'required|numeric|min:0',
            'details.*.qty_out' => 'required|numeric|min:0',
            'details.*.qty' => 'required|numeric',
            'details.*.description' => 'nullable|string',
        ]);

        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, "SC", 1);

            $userId = Auth::user()->id;
            $correction = Correction::create([
                'correction_number' => $nobukti,
                'document_date' => $request->document_date,
                'coa_id' => $request->coa_id,
                'notes' => $request->notes ?? '',
                'department_id' => $request->department_id,
                'created_by' => $userId ?? null,
                'updated_by' => $userId ?? null
            ]);

            $this->saveDetail($request->details,$correction,$company);
            DB::commit();
            return response()->json($correction->load('details'), 201);
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Error creating correction', ['error' => $e->getMessage(), 'data' => $request->all(), 'user' => Auth::user()->id ?? 'system']);
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    public function update(Request $request, $id){
        $request->validate([
            'coa_id' => 'nullable|integer|exists:coa,id',
            'notes' => 'nullable|string',
            'department_id' => 'required|integer|exists:department,id',
            'details' => 'required|array|min:1',
            'details.*.item_date' => 'nullable|date',
            'details.*.item_id' => 'required|integer|exists:items,id',
            'details.*.unit_id' => 'required|integer|exists:item_units,id',
            'details.*.warehouse_id' => 'required|integer|exists:warehouse,id',
            'details.*.qty_in' => 'required|numeric|min:0',
            'details.*.qty_out' => 'required|numeric|min:0',
            'details.*.qty' => 'required|numeric',
            'details.*.description' => 'nullable|string',
        ]);

        DB::beginTransaction();
        try {
            $company = Company::first();
            $department = Department::find($request->department_id);
            $correction = Correction::findOrFail($id);
            $userId = Auth::user()->id;
            
            $correction->coa_id = $request->coa_id;
            $correction->notes = $request->notes ?? '';
            $correction->updated_by = $userId;
            $correction->save();
            
            $correction->details()->delete();
            DB::table('inventory_details')->where('document_number', $correction->correction_number)->delete();
            Journal::where('document_number',$correction->correction_number)->delete();

            $this->saveDetail($request->details,$correction,$company);
            DB::commit();
            return response()->json(null, 201);
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Error update correction', ['error' => $e->getMessage(), 'data' => $request->all(), 'user' => Auth::user()->id ?? 'system']);
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    public function destroy($id, Request $request){
        DB::beginTransaction();
        try {
            $correction = Correction::findOrFail($id);
            $correction->details()->delete();
            $correction->delete();

            DB::table('inventory_details')->where('document_number', $correction->correction_number)->delete();
            Journal::where('document_number',$correction->correction_number)->delete();

            DeleteLog::create([
                'document_number' => $correction->correction_number,
                'document_date' => $correction->document_date,
                'delete_notes' => $request->delete_notes ?? 'No notes provided',
                'company_code' => null,
                'department_code' => $correction->department_id,
                'deleted_by' => Auth::check() ? Auth::user()->id : null,
                'type' => 'Correction',
            ]);

            DB::commit();
            return response()->json(null, 204);
        } catch (\Exception $e) {
            DB::rollback();
            Log::error('Error deleting correction', ['id' => $id, 'error' => $e->getMessage(), 'user' => Auth::check() ? Auth::user()->id : 'system']);
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    private function saveDetail($details,$header,$company){
        $totalNominal = 0;
        $userId = Auth::user()->id;
        foreach ($details as $detail) {
            $itemDetail = ItemDetail::where("item_id", $detail['item_id'])->where("unit_id", $detail['unit_id'])->first();
            $it = Item::find($detail['item_id']);
            $category = CategoryItem::find($it->category);

            CorrectionDetail::create([
                'correction_id' => $header->id,
                'item_id' => $detail['item_id'],
                'item_date' => $detail['item_date'],
                'unit_id' => $detail['unit_id'],
                'warehouse_id' => $detail['warehouse_id'],
                'base_qty' => $itemDetail->conversion,
                'qty_in' => $detail['qty_in'],
                'qty_out' => $detail['qty_out'],
                'qty' => $detail['qty'],
                'notes' => $detail['description'] ?? '',
                'created_by' => $userId ?? null,
                'updated_by' => $userId ?? null
            ]);

            $cogs = Module::getCogs($header->document_date,$detail['item_id'],$company->companyCode,$header->department_id,$detail['warehouse_id']);
            $nominal = ($cogs * $detail['qty'] * $itemDetail->conversion);
            $totalNominal += $nominal;
            if($detail['qty_in'] > 0){
                DB::table('inventory_details')->insert([
                    'document_number' => $header->correction_number,
                    'document_date' => $header->document_date,
                    'transaction_type' => 'Correction In',
                    'warehouse_id' => $detail['warehouse_id'],
                    'item_id' => $detail['item_id'],
                    'quantity' => $detail['qty_in'],
                    'unit' => $detail['unit_id'],
                    'base_quantity' => $itemDetail->conversion,
                    'unit_base' => $it->base_unit_id ?? null,
                    'department_id' => $header->department_id,
                    'company_code' => $company->companyCode,
                    'total' => $nominal,
                    'cogs' => $nominal,
                    'qty_actual' => $detail['qty_in'],
                    'created_by' => $userId,
                    'updated_by' => $userId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }else if($detail['qty_out'] > 0){
                DB::table('inventory_details')->insert([
                    'document_number' => $header->correction_number,
                    'document_date' => $header->document_date,
                    'transaction_type' => 'Correction Out',
                    'warehouse_id' => $detail['warehouse_id'],
                    'item_id' => $detail['item_id'],
                    'quantity' => $detail['qty_out'],
                    'unit' => $detail['unit_id'],
                    'base_quantity' => $itemDetail->conversion,
                    'unit_base' => $it->base_unit_id ?? null,
                    'department_id' => $header->department_id,
                    'company_code' => $company->companyCode,
                    'total' => $nominal,
                    'cogs' => $nominal,
                    'qty_actual' => -1*$detail['qty_out'],
                    'created_by' => $userId,
                    'updated_by' => $userId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }

            Journal::create([
                'document_number' => $header->correction_number,
                'document_date' => $header->document_date,
                'account_number' => $category->account_inventory,
                'notes' => 'Persediaan ' . $it->item_name.' : '.$detail['qty'],
                'debet_nominal' => 0,
                'credit_nominal' => abs($nominal),
                'debet_nominal_base' => 0,
                'credit_nominal_base' => abs($nominal),
                'company_code' => $company->companyCode,
                'department_id' => $header->department_id,
                'created_by' => Auth::user()->id,
                'updated_by' => Auth::user()->id,
            ]);
        }

        Journal::create([
            'document_number' => $header->correction_number,
            'document_date' => $header->document_date,
            'account_number' => $header->coa_id,
            'notes' => 'Correction',
            'debet_nominal' => abs($totalNominal),
            'credit_nominal' => 0,
            'debet_nominal_base' => abs($totalNominal),
            'credit_nominal_base' => 0,
            'company_code' => $company->companyCode,
            'department_id' => $header->department_id,
            'created_by' => Auth::user()->id,
            'updated_by' => Auth::user()->id,
        ]);
    }

    public function show($id)
    {
        try {
            $correction = Correction::with(['details.item', 'details.unit', 'department','details.warehouse'])->findOrFail($id);
            return response()->json($correction);
        } catch (\Exception $e) {
            Log::error('Failed to fetch correction', ['id' => $id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
            return response()->json(['error' => 'Correction not found'], 404);
        }
    }

    public function getMasterData()
    {
        try {
            $Listdepartment = $this->getDepartment();
            $departments = Department::whereIn("id",$Listdepartment)->get();
            $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();
            $coa = Coa::orderBy("account_number")->get();

            $items = Item::with(['itemDetails.unit'])->get();
            $itemDetails = ItemDetail::with(['item', 'unit'])->get();
            $itemUnits = ItemUnit::get();

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

            $response = [
                'coa' => $coa,
                'departments' => $departments,
                'items' => $items,
                'item_units' => $itemUnits,
                'item_details' => $itemDetails,
                'warehouses' => $warehouses,
                'nobukti' => $nobukti,
                "role" => $this->getRole(),
            ];

            return response()->json($response);
        } catch (\Exception $e) {
            Log::error('Error fetching master data', ['error' => $e->getMessage(), 'user' => Auth::user()->id ?? 'system']);
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
    public function getNomorBukti(Request $request){
        try {
            $request->validate([
                'department_id' => 'required|integer|exists:department,id',
                'document_date' => 'required|date',
            ]);

            $company = Company::select('companyCode')->first();
            $department = Department::select('department_code')->find($request->department_id);
            $date = Carbon::parse($request->document_date);
            $nobukti = Module::generateDocumentNumber($company->companyCode, $department->department_code, $date->month, $date->year, "SC", 0);
            return response()->json(['nobukti' => $nobukti]);
        } catch (\Exception $e) {
            Log::error('Failed to generate document number', ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
            return response()->json(['error' => 'Failed to generate document number'], 500);
        }
    }

    public function reCalc(){
        $coa = Coa::all();
        $company = Company::first();
        try {
            DB::beginTransaction();
            $head = DB::table("corrections")->get();
            foreach($head as $header){
                Journal::where("document_number",$header->correction_number)->delete();
                $det = DB::table("correction_details")->where("correction_id",$header->id)->get();
                $totalNominal = 0;
                foreach($det as $detail){
                    $it = Item::find($detail->item_id);
                    $category = CategoryItem::find($it->category);
                    $ivd = DB::table('inventory_details')->where("document_number",$header->correction_number)
                    ->where("item_id",$detail->item_id)->where("unit",$detail->unit_id)
                    ->where("qty_actual",$detail->qty)->first();
                    $nominal = $ivd->cogs;
                    $totalNominal += $nominal;
                    Journal::create([
                        'document_number' => $header->correction_number,
                        'document_date' => $header->document_date,
                        'account_number' => $category->account_inventory,
                        'notes' => 'Persediaan ' . $it->item_name.' : '.$detail->qty,
                        'debet_nominal' => 0,
                        'credit_nominal' => abs($nominal),
                        'debet_nominal_base' => 0,
                        'credit_nominal_base' => abs($nominal),
                        'company_code' => $company->companyCode,
                        'department_id' => $header->department_id,
                        'created_by' => Auth::user()->id,
                        'updated_by' => Auth::user()->id,
                    ]);
                }
                Journal::create([
                    'document_number' => $header->correction_number,
                    'document_date' => $header->document_date,
                    'account_number' => $header->coa_id,
                    'notes' => 'Correction',
                    'debet_nominal' => abs($totalNominal),
                    'credit_nominal' => 0,
                    'debet_nominal_base' => abs($totalNominal),
                    'credit_nominal_base' => 0,
                    'company_code' => $company->companyCode,
                    'department_id' => $header->department_id,
                    'created_by' => Auth::user()->id,
                    'updated_by' => Auth::user()->id,
                ]);
            }
            DB::commit();
        } catch (\Exception $e) {
            DB::rollback();
            dd($e->getMessage());
            //dd($e->getTrace());
            return response()->json(['error' => 'Failed'], 500);
        }
    }
}
