<?php

namespace App\Controllers;

use App\Models\BarangModel;
use App\Models\StokPenyesuaianModel;
use Config\Database;

class StokPenyesuaianController extends BaseController
{
    private StokPenyesuaianModel $penyesuaianModel;
    private BarangModel $barangModel;

    public function __construct()
    {
        $this->penyesuaianModel = new StokPenyesuaianModel();
        $this->barangModel = new BarangModel();
    }

    public function index()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/dashboard', 'Akses ditolak. Penyesuaian stok hanya dapat diakses oleh administrator.')) {
            return $redirect;
        }

        $penyesuaian = $this->penyesuaianModel
            ->select('stok_penyesuaian.*, user.name AS nama_user, pembatal.name AS nama_pembatal')
            ->join('user', 'user.id = stok_penyesuaian.user_id', 'left')
            ->join('user pembatal', 'pembatal.id = stok_penyesuaian.dibatalkan_oleh', 'left')
            ->orderBy('stok_penyesuaian.id', 'DESC')
            ->findAll();

        return view('admin/stok_penyesuaian/index', [
            'penyesuaian' => $penyesuaian,
            'userName'    => session()->get('userName'),
            'userEmail'   => session()->get('userEmail'),
            'userRole'    => session()->get('userRole'),
        ]);
    }

    public function create()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/stok-penyesuaian')) {
            return $redirect;
        }

        $tanggal = date('Y-m-d');

        return view('admin/stok_penyesuaian/create', [
            'barang'          => $this->barangOptions(),
            'tanggal'         => $tanggal,
            'noPenyesuaian'   => $this->generateAdjustmentNumber($tanggal),
            'userName'        => session()->get('userName'),
            'userEmail'       => session()->get('userEmail'),
            'userRole'        => session()->get('userRole'),
        ]);
    }

    public function store()
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/stok-penyesuaian')) {
            return $redirect;
        }

        if (! $this->validate($this->validationRules())) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $barang = $this->barangModel->find((int) $this->request->getPost('barang_id'));

        if (! $barang) {
            return redirect()->back()->withInput()->with('error', 'Barang tidak ditemukan.');
        }

        $tanggal = (string) $this->request->getPost('tanggal_penyesuaian');
        $stokSistem = (int) ($barang['stok'] ?? 0);
        $stokFisik = (int) $this->request->getPost('stok_fisik');
        $selisih = $stokFisik - $stokSistem;
        $jenis = $selisih > 0 ? 'penambahan' : ($selisih < 0 ? 'pengurangan' : 'sesuai');

        $db = Database::connect();
        $db->transStart();

        $this->penyesuaianModel->insert([
            'no_penyesuaian'       => $this->generateAdjustmentNumber($tanggal),
            'tanggal_penyesuaian'  => $tanggal,
            'barang_id'            => (int) $barang['id'],
            'kode_barang'          => $barang['kode_barang'],
            'nama_barang'          => $barang['nama_barang'],
            'satuan'               => $barang['satuan'],
            'stok_sistem'          => $stokSistem,
            'stok_fisik'           => $stokFisik,
            'selisih'              => $selisih,
            'jenis'                => $jenis,
            'alasan'               => $this->request->getPost('alasan'),
            'catatan'              => $this->request->getPost('catatan') ?: null,
            'user_id'              => session()->get('userId'),
            'status'               => 'aktif',
        ]);

        $this->barangModel->update((int) $barang['id'], ['stok' => $stokFisik]);

        $db->transComplete();

        if (! $db->transStatus()) {
            return redirect()->back()->withInput()->with('error', 'Gagal menyimpan penyesuaian stok.');
        }

        return redirect()->to('/admin/stok-penyesuaian')->with('success', 'Penyesuaian stok berhasil disimpan.');
    }

    public function detail(int $id)
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/stok-penyesuaian')) {
            return $redirect;
        }

        $penyesuaian = $this->penyesuaianModel
            ->select('stok_penyesuaian.*, user.name AS nama_user, pembatal.name AS nama_pembatal')
            ->join('user', 'user.id = stok_penyesuaian.user_id', 'left')
            ->join('user pembatal', 'pembatal.id = stok_penyesuaian.dibatalkan_oleh', 'left')
            ->where('stok_penyesuaian.id', $id)
            ->first();

        if (! $penyesuaian) {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Penyesuaian stok tidak ditemukan.');
        }

        return view('admin/stok_penyesuaian/detail', [
            'penyesuaian' => $penyesuaian,
            'userName'    => session()->get('userName'),
            'userEmail'   => session()->get('userEmail'),
            'userRole'    => session()->get('userRole'),
        ]);
    }

    public function cancel(int $id)
    {
        if (! $this->isLoggedIn()) {
            return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
        }

        if ($redirect = $this->requireAdministrator('/admin/stok-penyesuaian')) {
            return $redirect;
        }

        $penyesuaian = $this->penyesuaianModel->find($id);

        if (! $penyesuaian) {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Penyesuaian stok tidak ditemukan.');
        }

        if (($penyesuaian['status'] ?? '') !== 'aktif') {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Penyesuaian stok sudah dibatalkan.');
        }

        $barang = $this->barangModel->find((int) $penyesuaian['barang_id']);

        if (! $barang) {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Barang terkait penyesuaian tidak ditemukan.');
        }

        $stokBaru = (int) ($barang['stok'] ?? 0) - (int) $penyesuaian['selisih'];

        if ($stokBaru < 0) {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Penyesuaian stok tidak bisa dibatalkan karena stok barang akan menjadi negatif.');
        }

        $db = Database::connect();
        $db->transStart();

        $this->barangModel->update((int) $barang['id'], ['stok' => $stokBaru]);
        $this->penyesuaianModel->update($id, [
            'status'              => 'dibatalkan',
            'dibatalkan_oleh'     => session()->get('userId'),
            'dibatalkan_pada'     => date('Y-m-d H:i:s'),
            'catatan_pembatalan'  => $this->request->getPost('catatan_pembatalan') ?: null,
        ]);

        $db->transComplete();

        if (! $db->transStatus()) {
            return redirect()->to('/admin/stok-penyesuaian')->with('error', 'Gagal membatalkan penyesuaian stok.');
        }

        return redirect()->to('/admin/stok-penyesuaian')->with('success', 'Penyesuaian stok berhasil dibatalkan dan stok dikembalikan.');
    }

    public function generateNumber()
    {
        if (! $this->isLoggedIn() || ! $this->isAdministratorRole()) {
            return $this->response->setStatusCode(403)->setJSON(['message' => 'Akses ditolak.']);
        }

        $tanggal = (string) ($this->request->getGet('tanggal_penyesuaian') ?: date('Y-m-d'));

        if (! $this->isValidDate($tanggal)) {
            return $this->response->setStatusCode(422)->setJSON(['message' => 'Tanggal tidak valid.']);
        }

        return $this->response->setJSON([
            'no_penyesuaian' => $this->generateAdjustmentNumber($tanggal),
        ]);
    }

    private function validationRules(): array
    {
        return [
            'tanggal_penyesuaian' => 'required|valid_date[Y-m-d]',
            'barang_id'           => 'required|is_not_unique[barang.id]',
            'stok_fisik'          => 'required|integer|greater_than_equal_to[0]',
            'alasan'              => 'required|max_length[150]',
            'catatan'             => 'permit_empty|max_length[1000]',
        ];
    }

    private function barangOptions(): array
    {
        return $this->barangModel
            ->select('barang.id, barang.kode_barang, barang.nama_barang, barang.satuan, barang.stok, kategori.nama_kategori')
            ->join('kategori', 'kategori.id = barang.kategori_id', 'left')
            ->orderBy('barang.nama_barang', 'ASC')
            ->findAll();
    }

    private function generateAdjustmentNumber(string $tanggal): string
    {
        $date = date_create($tanggal) ?: date_create();
        $prefix = $date->format('Ymd') . '/ADJ';
        $last = $this->penyesuaianModel
            ->select('no_penyesuaian')
            ->like('no_penyesuaian', $prefix . '/', 'after')
            ->orderBy('no_penyesuaian', 'DESC')
            ->first();
        $nextNumber = 1;

        if ($last && preg_match('/\/(\d+)$/', $last['no_penyesuaian'], $matches)) {
            $nextNumber = ((int) $matches[1]) + 1;
        }

        return $prefix . '/' . str_pad((string) $nextNumber, 3, '0', STR_PAD_LEFT);
    }

    private function isValidDate(string $date): bool
    {
        $parsed = date_create_from_format('Y-m-d', $date);

        return $parsed !== false && $parsed->format('Y-m-d') === $date;
    }

    private function isLoggedIn(): bool
    {
        return (bool) session()->get('isLoggedIn') && $this->isUserAccount();
    }
}
