<?php

namespace App\Livewire;

use App\Services\SimbhpStockService;
use App\SIMBHPJenis;
use App\SIMBHPReport;
use App\User;
use Carbon\Carbon;
use Livewire\Component;
use Livewire\Attributes\On;
use Livewire\WithPagination;
use Illuminate\Support\Facades\DB;

class GudangPos extends Component
{
    use WithPagination;

    public string $tanggal = '';
    public ?int $penerimaId = null;

    public string $scan = '';
    public string $selectedKode = '';
    public string $satuanTransaksi = 'besar';
    public int $qty = 1;

    public string $search = '';

    /**
     * @var array<int, array{kode:string, jenis:string, qty:int, satuan_transaksi:string}>
     */
    public array $cart = [];

    public function mount(): void
    {
        $this->tanggal = date('Y-m-d');
        $this->penerimaId = User::orderBy('nama', 'ASC')->value('id');
    }

    public function updatingSearch(): void
    {
        $this->resetPage();
    }

    public function scanLookup(): void
    {
        $service = app(SimbhpStockService::class);
        $raw = (string) $this->scan;
        $parsed = $service->parseBarcode($raw);
        $kode = (string) ($parsed['kode'] ?? '');
        $jenisId = $parsed['jenis_id'] ?? null;
        $this->scan = '';

        if ($kode === '' && (is_null($jenisId) || (int) $jenisId <= 0)) {
            $this->toast('error', 'Kode barcode kosong.');
            return;
        }

        $jenis = $service->getJenisByKode($raw);
        if (!$jenis) {
            $this->toast('error', 'Kode barang tidak ditemukan.');
            return;
        }

        $saldoBase = $service->getStockBaseByJenis((string) ($jenis->jenis ?? ''));
        if ($saldoBase <= 0) {
            $this->toast('error', 'Stok kosong untuk ' . ((string) ($jenis->jenis ?? 'barang')) . '.');
            return;
        }

        $this->selectedKode = (string) ($jenis->kodejenis ?? '');
        $this->qty = 1;
        $this->satuanTransaksi = (string) ($parsed['satuan_transaksi'] ?? 'besar');
        $this->syncSatuanAvailability();
        $this->dispatch('gudangpos-open-modal');
    }

    #[On('gudangpos-select')]
    public function selectProduct(string $kode): void
    {
        $service = app(SimbhpStockService::class);
        $kode = $service->sanitizeKode($kode);
        $jenis = $service->getJenisByKode($kode);

        if (!$jenis) {
            $this->toast('error', 'Kode barang tidak ditemukan: ' . $kode);
            return;
        }

        $saldoBase = $service->getStockBaseByJenis((string) ($jenis->jenis ?? ''));
        if ($saldoBase <= 0) {
            $this->toast('error', 'Stok kosong untuk ' . ((string) ($jenis->jenis ?? 'barang')) . '.');
            return;
        }

        $this->selectedKode = (string) ($jenis->kodejenis ?? '');
        $this->qty = 1;
        $this->syncSatuanAvailability();
        $this->dispatch('gudangpos-open-modal');
    }

    #[On('gudangpos-refresh')]
    public function refreshComponent(): void
    {
        // Force rerender + keep UI responsive when stok berubah dari tab lain.
        $this->resetPage();
    }

    public function addSelected(): void
    {
        $service = app(SimbhpStockService::class);
        $kode = $service->sanitizeKode($this->selectedKode);
        if ($kode === '') {
            $this->toast('error', 'Pilih barang dulu (scan barcode / klik daftar produk).');
            return;
        }

        $jenis = $service->getJenisByKode($kode);
        if (!$jenis) {
            $this->toast('error', 'Kode barang tidak ditemukan: ' . $kode);
            return;
        }

        $qty = (int) $this->qty;
        if ($qty <= 0) {
            $this->toast('error', 'Jumlah harus lebih dari 0.');
            return;
        }

        $setting = $service->getUnitSetting($jenis);
        if ($this->satuanTransaksi === 'kecil' && !$setting['has_breakdown']) {
            $this->satuanTransaksi = 'besar';
            $this->toast('info', 'Barang ini tidak memiliki satuan kecil, otomatis pakai satuan besar.');
        }

        $found = false;
        foreach ($this->cart as $i => $line) {
            if (($line['kode'] ?? '') === $kode && ($line['satuan_transaksi'] ?? '') === $this->satuanTransaksi) {
                $this->cart[$i]['qty'] = ((int) ($this->cart[$i]['qty'] ?? 0)) + $qty;
                $found = true;
                break;
            }
        }

        if (!$found) {
            $this->cart[] = [
                'kode' => $kode,
                'jenis' => (string) ($jenis->jenis ?? ''),
                'qty' => $qty,
                'satuan_transaksi' => $this->satuanTransaksi,
            ];
        }

        $this->qty = 1;
        $this->dispatch('gudangpos-close-modal');
        $this->dispatch('gudangpos-focus', field: 'scan');
    }

    public function removeLine(int $index): void
    {
        if (!isset($this->cart[$index])) {
            return;
        }

        array_splice($this->cart, $index, 1);
    }

    public function processCart(): void
    {
        if (count($this->cart) === 0) {
            $this->toast('info', 'Keranjang masih kosong.');
            return;
        }

        if (!$this->penerimaId) {
            $this->toast('error', 'Penerima wajib dipilih.');
            return;
        }

        $tanggal = trim((string) $this->tanggal);
        if ($tanggal === '') {
            $this->toast('error', 'Tanggal wajib diisi.');
            return;
        }

        try {
            $date = Carbon::parse($tanggal);
        } catch (\Throwable $e) {
            $this->toast('error', 'Format tanggal tidak valid.');
            return;
        }

        $penerima = User::select('id', 'nama')->find($this->penerimaId);
        if (!$penerima) {
            $this->toast('error', 'Penerima tidak ditemukan.');
            return;
        }

        $service = app(SimbhpStockService::class);

        $prepared = [];
        $stockCache = [];
        foreach ($this->cart as $line) {
            $kode = $service->sanitizeKode((string) ($line['kode'] ?? ''));
            $qty = (int) ($line['qty'] ?? 0);
            $satuan = (string) ($line['satuan_transaksi'] ?? 'besar');
            if ($kode === '' || $qty <= 0) {
                $this->toast('error', 'Ada item keranjang yang tidak valid.');
                return;
            }

            $jenis = $service->getJenisByKode($kode);
            if (!$jenis) {
                $this->toast('error', 'Kode barang tidak ditemukan: ' . $kode);
                return;
            }

            $setting = $service->getUnitSetting($jenis);
            if ($satuan === 'kecil' && !$setting['has_breakdown']) {
                $satuan = 'besar';
            }

            $qtyBase = $service->calculateBaseQty($jenis, $qty, $satuan);
            $jenisNama = (string) ($jenis->jenis ?? '');
            if (!array_key_exists($jenisNama, $stockCache)) {
                $stockCache[$jenisNama] = $service->getStockBaseByJenis($jenisNama);
            }

            if ($qtyBase > $stockCache[$jenisNama]) {
                if ((int) $stockCache[$jenisNama] <= 0) {
                    $this->toast('error', 'Stok kosong untuk ' . $jenisNama . '.');
                } else {
                    $this->toast('error', 'Stok tidak cukup untuk ' . $jenisNama . '.');
                }
                return;
            }
            $stockCache[$jenisNama] -= $qtyBase;

            $prepared[] = [
                'jenis' => $jenis,
                'qty' => $qty,
                'qty_base' => $qtyBase,
                'satuan_transaksi' => $satuan,
            ];
        }

        DB::transaction(function () use ($prepared, $date, $penerima) {
            foreach ($prepared as $row) {
                /** @var SIMBHPJenis $jenis */
                $jenis = $row['jenis'];
                SIMBHPReport::create([
                    'tanggal' => (int) $date->format('d'),
                    'bulan' => (int) $date->format('m'),
                    'tahun' => (int) $date->format('Y'),
                    'deskripsi' => 'Diterima oleh ' . ($penerima->nama ?? 'Unkown'),
                    'pemasukan' => null,
                    'pengeluaran' => (int) $row['qty'],
                    'qty_base' => (int) $row['qty_base'],
                    'satuan_transaksi' => (string) $row['satuan_transaksi'],
                    'masa_expired' => null,
                    'jenis' => (string) ($jenis->jenis ?? ''),
                    'keterangan' => '',
                    'marking' => '',
                ]);
            }
        });

        $this->cart = [];
        $this->qty = 1;
        $this->toast('success', 'Barang keluar berhasil diproses.');
        $this->dispatch('gudang-refresh');
        $this->dispatch('gudangpos-close-modal');
        $this->dispatch('gudangpos-focus', field: 'scan');
    }

    public function updatedSelectedKode(): void
    {
        $this->syncSatuanAvailability();
    }

    public function updatedSatuanTransaksi(): void
    {
        $this->syncSatuanAvailability();
    }

    private function syncSatuanAvailability(): void
    {
        $service = app(SimbhpStockService::class);
        $kode = $service->sanitizeKode($this->selectedKode);
        if ($kode === '') {
            return;
        }

        $jenis = $service->getJenisByKode($kode);
        if (!$jenis) {
            return;
        }

        $setting = $service->getUnitSetting($jenis);
        if (!$setting['has_breakdown'] && $this->satuanTransaksi === 'kecil') {
            $this->satuanTransaksi = 'besar';
        }
    }

    private function toast(string $type, string $message): void
    {
        $this->dispatch('gudangpos-toast', type: $type, message: $message);
    }

    public function render()
    {
        $service = app(SimbhpStockService::class);

        $users = User::select('id', 'nama', 'previlage')->orderBy('nama', 'ASC')->get();

        $query = SIMBHPJenis::query()->orderBy('jenis', 'ASC');
        $search = trim((string) $this->search);
        if ($search !== '') {
            $searchLike = '%' . $search . '%';
            $driver = DB::connection()->getDriverName();
            $operator = ($driver === 'pgsql') ? 'ILIKE' : 'LIKE';
            $query->where(function ($q) use ($searchLike, $operator) {
                $q->where('jenis', $operator, $searchLike)
                    ->orWhere('kodejenis', $operator, $searchLike);
            });
        }

        $products = $query->paginate(12);

        $jenisNames = $products->getCollection()->pluck('jenis')->filter()->values()->all();
        $stockMap = $service->getStockBaseByJenisMany($jenisNames);

        $selectedJenis = null;
        $selectedStockDisplay = null;
        $selectedSetting = null;
        $kode = $service->sanitizeKode($this->selectedKode);
        if ($kode !== '') {
            $selectedJenis = $service->getJenisByKode($kode);
            if ($selectedJenis) {
                $saldoBase = $service->getStockBaseByJenis((string) $selectedJenis->jenis);
                $selectedSetting = $service->getUnitSetting($selectedJenis);
                $selectedStockDisplay = $service->formatStockDisplay(
                    $saldoBase,
                    (string) ($selectedJenis->satuan ?? ''),
                    (string) ($selectedJenis->satuan_kecil ?? ''),
                    (int) ($selectedJenis->konversi_kecil ?? 1),
                );
            }
        }

        return view('livewire.gudang-pos', [
            'users' => $users,
            'products' => $products,
            'stockMap' => $stockMap,
            'selectedJenis' => $selectedJenis,
            'selectedStockDisplay' => $selectedStockDisplay,
            'selectedSetting' => $selectedSetting,
        ]);
    }
}
