<?php

namespace App\Http\Controllers;

use App\Models\Purchase;
use App\Models\JournalEntry;
use App\Models\JournalDetail;
use App\Models\Account;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class PurchaseController extends Controller
{
    public function index(Request $request)
    {
        $user = Auth::user();
        $branches = \App\Models\Branch::all();
        $branch = $user->branch ?? 'Cabang 1';

        $query = Purchase::with('product')->orderBy('date', 'desc');

        if ($request->filled('year')) {
            $query->whereYear('date', $request->year);
        }
        if ($request->filled('month')) {
            $query->whereMonth('date', $request->month);
        }
        if ($request->filled('day')) {
            $query->whereDay('date', $request->day);
        }

        if ($request->filled('search')) {
            $query->where('item', 'like', '%' . $request->search . '%');
        }

        // Apply "today" filter by default only when the page is first loaded
        // (i.e. there are no query parameters). If the user submitted the filter
        // form with "Semua Tahun" (empty values), we treat that as an explicit
        // request and do not force today's data.
        if (count($request->query()) === 0) {
            $query->whereDate('date', \Carbon\Carbon::today());
        }

        // Filter raw materials by branch for karyawan, show all for admin
        if ($user->role === 'admin') {
            $rawMaterials = \App\Models\RawMaterial::all();
            $purchases = $query->get();
            return view('laporan_pembelian', compact('purchases', 'branches', 'rawMaterials'));
        } else {
            $rawMaterials = \App\Models\RawMaterial::where('branch', $branch)->get();
            $purchases = $query->where('branch', $user->branch)->get();
            return view('laporan_pembelian', compact('purchases', 'branches', 'rawMaterials'));
        }
    }

    public function create()
    {
        $user = Auth::user();

        if ($user->role === 'admin') {
            return redirect('/laporan/pembelian')->with('error', 'Fitur tambah pembelian hanya tersedia untuk karyawan.');
        }

        $branches = \App\Models\Branch::all();
        $branch = $user->branch ?? 'Cabang 1';
        $rawMaterials = \App\Models\RawMaterial::where('branch', $branch)->get();

        return view('transaksi.pembelian', compact('branches', 'rawMaterials'));
    }

    public function exportPdf(Request $request)
    {
        $user = Auth::user();
        if ($user->role !== 'admin') {
            abort(403);
        }

        $query = Purchase::with('product')->orderBy('date', 'desc');

        if ($request->filled('year')) {
            $query->whereYear('date', $request->year);
        }
        if ($request->filled('month')) {
            $query->whereMonth('date', $request->month);
        }
        if ($request->filled('day')) {
            $query->whereDay('date', $request->day);
        }

        if ($request->filled('search')) {
            $query->where('item', 'like', '%' . $request->search . '%');
        }

        // Apply default today filter for export only when there are no query params
        if (count($request->query()) === 0) {
            $query->whereDate('date', \Carbon\Carbon::today());
        }

        $purchases = $query->get();
        $branches = \App\Models\Branch::all();
        
        $pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('reports.purchase_pdf', compact('purchases', 'branches'));
        return $pdf->download('laporan_pembelian.pdf');
    }

    public function store(Request $request)
    {
        $rules = [
            'date' => 'required|date',
            'item' => 'required|string|max:255',
            'quantity' => 'required|string|max:255',
            'total_price' => 'required|numeric|min:0',
            'type' => 'nullable|in:product,raw_material',
            'raw_material_id' => 'required_if:type,raw_material|not_in:0',
        ];

        // Hanya require field bahan baku baru jika raw_material_id = 'new'
        if ($request->input('type') === 'raw_material' && $request->input('raw_material_id') === 'new') {
            $rules['new_raw_material_name'] = 'required|string|max:255';
            $rules['new_raw_material_unit'] = 'required|string|max:50';
        }

        $request->validate($rules);

        // Debug log
        \Illuminate\Support\Facades\Log::info('Purchase store - Request data:', [
            'type' => $request->type,
            'raw_material_id' => $request->raw_material_id,
            'new_raw_material_name' => $request->new_raw_material_name,
            'new_raw_material_unit' => $request->new_raw_material_unit,
            'item' => $request->item,
            'quantity' => $request->quantity
        ]);

        try {
            \Illuminate\Support\Facades\DB::transaction(function () use ($request) {
                $branch = Auth::user()->branch ?? 'Cabang 1';
                if (Auth::user()->role === 'admin' && $request->has('branch')) {
                    $branch = $request->branch;
                }

                // Bersihkan format angka (hapus titik pemisah ribuan jika ada)
                $cleanPrice = str_replace('.', '', $request->total_price);

                // Handle raw material creation if new raw material is provided
                $rawMaterialId = $request->raw_material_id;
                if ($request->type === 'raw_material' && $request->raw_material_id === 'new') {
                    if ($request->filled('new_raw_material_name') && $request->filled('new_raw_material_unit')) {
                        // Create new raw material
                        $newRm = \App\Models\RawMaterial::create([
                            'name' => $request->new_raw_material_name,
                            'unit' => $request->new_raw_material_unit,
                            'stock_quantity' => 0,
                            'branch' => $branch
                        ]);
                        $rawMaterialId = $newRm->id;
                    } else {
                        throw new \Exception('Nama dan satuan bahan baku baru harus diisi.');
                    }
                }

                $purchase = Purchase::create([
                    'date' => $request->date,
                    'branch' => $branch,
                    'item' => $request->item,
                    'quantity' => $request->quantity,
                    'total_price' => (int) $cleanPrice,
                    'product_id' => null,
                    'raw_material_id' => $request->type === 'raw_material' ? $rawMaterialId : null,
                    'type' => $request->type ?? 'product',
                ]);

                if ($purchase->type === 'raw_material' && $purchase->raw_material_id) {
                    $rm = \App\Models\RawMaterial::find($purchase->raw_material_id);
                    if ($rm) {
                        // Only update stock if raw material belongs to user's branch
                        if ($rm->branch !== $branch) {
                            throw new \Exception('Bahan baku ini tidak terdaftar di cabang Anda.');
                        }

                        // Parse quantity string, e.g. "10 Kilogram" → value=10, unit=kilogram
                        $parsed   = $this->parseQuantity($purchase->quantity);
                        $qtyValue = $parsed['value'];
                        $qtyUnit  = $parsed['unit'] ?: strtolower($rm->unit);

                        // Konversi ke satuan dasar bahan baku
                        $qtyInBase = $this->convertToBaseUnit($qtyValue, $qtyUnit);

                        $rm->stock_quantity += $qtyInBase;
                        $rm->save();
                        $this->recalculateProductsFromRawMaterial($rm->id, $branch);
                    }
                }

                // Create Journal Entry
                $kasAccount = Account::where('code', '101')->first();
                $persediaanAccount = Account::where('code', '102')->first();

                if ($kasAccount && $persediaanAccount) {
                    $journal = JournalEntry::create([
                        'date' => $purchase->date,
                        'description' => 'Pembelian ' . $purchase->item,
                        'reference_type' => 'Purchase',
                        'reference_id' => $purchase->id,
                        'branch' => $branch,
                    ]);

                    // Debit Persediaan, Kredit Kas
                    JournalDetail::create(['journal_entry_id' => $journal->id, 'account_id' => $persediaanAccount->id, 'debit' => $purchase->total_price, 'credit' => 0]);
                    JournalDetail::create(['journal_entry_id' => $journal->id, 'account_id' => $kasAccount->id, 'debit' => 0, 'credit' => $purchase->total_price]);
                }

            });

            return back()->with('success', 'Transaksi pembelian berhasil ditambahkan!');
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('Purchase store error: ' . $e->getMessage());
            return back()->withInput()->withErrors(['db_error' => 'Gagal menyimpan transaksi: ' . $e->getMessage()]);
        }
    }

    /**
     * Konversi nilai ke satuan stok yang dipakai aplikasi.
     * Untuk bisnis sederhana, pembelian liter dan unit lain disimpan apa adanya
     * agar stok tetap sesuai dengan satuan yang dimasukkan.
     */
    private function convertToBaseUnit($value, $unit)
    {
        $unit = strtolower(trim($unit));
        $conversions = [
            'kilogram' => 1000,
            'kg'       => 1000,
            'gram'     => 1,
            'gr'       => 1,
            'g'        => 1,
            'liter'    => 1,
            'l'        => 1,
            'mililiter'=> 1,
            'ml'       => 1,
            'pcs'      => 1,
            'dus'      => 1,
            'pack'     => 1,
            'karung'   => 1,
            'ikat'     => 1,
            'botol'    => 1,
            'kaleng'   => 1,
            'lembar'   => 1,
            'sendok makan' => 1,
            'sendok teh'   => 1,
        ];
        $multiplier = $conversions[$unit] ?? 1;
        return $value * $multiplier;
    }

    /**
     * Parse quantity string seperti "10 Kilogram" → returns ['value' => 10, 'unit' => 'kilogram']
     */
    private function parseQuantity($quantityStr)
    {
        $quantityStr = trim($quantityStr);
        // Coba pisahkan angka dan satuan
        if (preg_match('/^([\d.,]+)\s*(.*)$/', $quantityStr, $matches)) {
            $value = floatval(str_replace(',', '.', $matches[1]));
            $unit  = strtolower(trim($matches[2]));
            return ['value' => $value, 'unit' => $unit];
        }
        return ['value' => floatval($quantityStr), 'unit' => ''];
    }

    private function recalculateProductsFromRawMaterial($rawMaterialId, $branch)
    {
        // Ambil semua resep yang menggunakan bahan baku ini, eager load product & semua resep produk tsb
        $recipes = \App\Models\ProductRecipe::where('raw_material_id', $rawMaterialId)
            ->with(['product.recipes.rawMaterial'])
            ->get();

        foreach ($recipes as $recipe) {
            $product = $recipe->product;
            if (!$product) continue;

            $minStock = null;

            foreach ($product->recipes as $prodRecipe) {
                $rm = $prodRecipe->rawMaterial;
                if (!$rm || $prodRecipe->quantity_needed <= 0) continue;

                // Stok bahan baku sudah dalam satuan dasar (disimpan apa adanya)
                $rmStock = $rm->stock_quantity;

                // quantity_needed di resep dalam satuan apa? Anggap sama dengan satuan bahan baku
                $needed = $prodRecipe->quantity_needed;

                $possibleAmount = floor($rmStock / $needed);

                if ($minStock === null || $possibleAmount < $minStock) {
                    $minStock = $possibleAmount;
                }
            }

            if ($minStock !== null && $minStock >= 0) {
                // Update semua cabang (atau hanya cabang ini)
                $allBranches = \App\Models\Branch::all();
                foreach ($allBranches as $b) {
                    $stock = \App\Models\Stock::firstOrCreate(
                        ['product_id' => $product->id, 'branch' => $b->name],
                        ['quantity' => 0, 'unit' => 'Pcs']
                    );
                    $stock->quantity = $minStock;
                    $stock->save();
                }
            }
        }
    }

    public function update(Request $request, $id)
    {
        $rules = [
            'date' => 'required|date',
            'item' => 'required|string|max:255',
            'quantity' => 'required|string|max:255',
            'total_price' => 'required|numeric|min:0',
            'type' => 'nullable|in:product,raw_material',
            'raw_material_id' => 'required_if:type,raw_material|not_in:0',
        ];

        // Hanya require field bahan baku baru jika raw_material_id = 'new'
        if ($request->input('type') === 'raw_material' && $request->input('raw_material_id') === 'new') {
            $rules['new_raw_material_name'] = 'required|string|max:255';
            $rules['new_raw_material_unit'] = 'required|string|max:50';
        }

        $request->validate($rules);

        try {
            \Illuminate\Support\Facades\DB::transaction(function () use ($request, $id) {
                $purchase = Purchase::findOrFail($id);
                $oldType = $purchase->type;
                $oldRawMaterialId = $purchase->raw_material_id;
                $branch = $purchase->branch;

                // Jika pembelian lama adalah bahan baku, hapus stok lama dulu
                if ($oldType === 'raw_material' && $oldRawMaterialId) {
                    $oldRm = \App\Models\RawMaterial::find($oldRawMaterialId);
                    if ($oldRm) {
                        $oldParsed = $this->parseQuantity($purchase->quantity);
                        $oldQty = $this->convertToBaseUnit($oldParsed['value'], $oldParsed['unit'] ?: strtolower($oldRm->unit));
                        $oldRm->stock_quantity -= $oldQty;
                        if ($oldRm->stock_quantity < 0) {
                            $oldRm->stock_quantity = 0;
                        }
                        $oldRm->save();
                    }
                }

                $newRawMaterialId = null;
                if ($request->type === 'raw_material') {
                    $newRawMaterialId = $request->raw_material_id;
                    if ($newRawMaterialId === 'new') {
                        $newRm = \App\Models\RawMaterial::create([
                            'name' => $request->new_raw_material_name,
                            'unit' => $request->new_raw_material_unit,
                            'stock_quantity' => 0,
                            'branch' => Auth::user()->branch ?? 'Cabang 1',
                        ]);
                        $newRawMaterialId = $newRm->id;
                    }

                    $rm = \App\Models\RawMaterial::find($newRawMaterialId);
                    if ($rm) {
                        $parsed = $this->parseQuantity($request->quantity);
                        $qty = $this->convertToBaseUnit($parsed['value'], $parsed['unit'] ?: strtolower($rm->unit));
                        $rm->stock_quantity += $qty;
                        $rm->save();
                    }
                }

                // Perbarui data pembelian
                $cleanPrice = str_replace('.', '', $request->total_price);
                $data = $request->all();
                $data['total_price'] = (int) $cleanPrice;
                $data['product_id'] = null;

                if (Auth::user()->role === 'admin' && $request->has('branch')) {
                    $data['branch'] = $request->branch;
                }

                $purchase->update($data);

                // Recalculate product stock from raw materials if needed
                if ($oldType === 'raw_material' && $oldRawMaterialId) {
                    $this->recalculateProductsFromRawMaterial($oldRawMaterialId, $branch);
                }
                if ($request->type === 'raw_material' && $newRawMaterialId) {
                    $this->recalculateProductsFromRawMaterial($newRawMaterialId, $branch);
                }

                // Recreate Journal Entry
                JournalEntry::where('reference_type', 'Purchase')->where('reference_id', $purchase->id)->delete();

                $kasAccount = Account::where('code', '101')->first();
                $persediaanAccount = Account::where('code', '102')->first();

                if ($kasAccount && $persediaanAccount) {
                    $journal = JournalEntry::create([
                        'date' => $purchase->date,
                        'description' => 'Pembelian ' . $purchase->item,
                        'reference_type' => 'Purchase',
                        'reference_id' => $purchase->id,
                        'branch' => $purchase->branch,
                    ]);

                    JournalDetail::create(['journal_entry_id' => $journal->id, 'account_id' => $persediaanAccount->id, 'debit' => $purchase->total_price, 'credit' => 0]);
                    JournalDetail::create(['journal_entry_id' => $journal->id, 'account_id' => $kasAccount->id, 'debit' => 0, 'credit' => $purchase->total_price]);
                }
            });

            return back()->with('success', 'Transaksi pembelian berhasil diperbarui!');
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('Purchase update error: ' . $e->getMessage());
            return back()->withInput()->withErrors(['db_error' => 'Gagal memperbarui transaksi: ' . $e->getMessage()]);
        }
    }

    public function destroy($id)
    {
        try {
            \Illuminate\Support\Facades\DB::transaction(function () use ($id) {
                $purchase = Purchase::findOrFail($id);

                // If this is a raw material purchase, update stock and potentially delete raw material
                if ($purchase->type === 'raw_material' && $purchase->raw_material_id) {
                    $rm = \App\Models\RawMaterial::find($purchase->raw_material_id);
                    if ($rm) {
                        // Parse quantity to subtract from stock
                        $parsed = $this->parseQuantity($purchase->quantity);
                        $qtyValue = $parsed['value'];
                        $qtyUnit = $parsed['unit'] ?: strtolower($rm->unit);
                        $qtyInBase = $this->convertToBaseUnit($qtyValue, $qtyUnit);

                        // Subtract from stock
                        $rm->stock_quantity -= $qtyInBase;
                        if ($rm->stock_quantity < 0) $rm->stock_quantity = 0;
                        $rm->save();

                        // Recalculate products
                        $this->recalculateProductsFromRawMaterial($rm->id, $purchase->branch);

                        // Check if this is the only purchase for this raw material
                        $otherPurchases = Purchase::where('raw_material_id', $rm->id)
                            ->where('id', '!=', $purchase->id)
                            ->count();

                        if ($otherPurchases === 0) {
                            // No other purchases, delete the raw material
                            $rm->delete();
                        }
                    }
                }

                // Delete journal entries
                JournalEntry::where('reference_type', 'Purchase')->where('reference_id', $purchase->id)->delete();

                // Delete purchase
                $purchase->delete();
            });

            return back()->with('success', 'Transaksi pembelian berhasil dihapus!');
        } catch (\Exception $e) {
            \Illuminate\Support\Facades\Log::error('Purchase destroy error: ' . $e->getMessage());
            return back()->with('error', 'Gagal menghapus transaksi: ' . $e->getMessage());
        }
    }
}
