<?php

namespace App\Controllers;

/**
 * Port dari Cekout.php (CI3). Slice pertama: jalur "Bayar dengan Saldo"
 * untuk PPOB prabayar/Token PLN (idproduk != 25, h2h = 0, dropship = 0).
 * Slice kedua: checkout fisik & jasa (bayarpesanan/bayarpesananjasa) dengan
 * metode Transfer Manual + Midtrans -- iPaymu TIDAK dibangun ulang (sudah
 * nonaktif/commented di CI3, bukan bagian dari yang berjalan sekarang).
 * Jalur H2H/dropship utk PPOB TIDAK diport -- itu di luar cakupan fase ini.
 *
 * PENTING: bayarpesananppob() memanggil API TRANSAKSI ASLI Digiflazz
 * (https://api.digiflazz.com/v1/transaction) saat berhasil -- bukan
 * simulasi. Begitu dipanggil dengan data valid, pulsa/token/saldo digital
 * akan benar-benar terkirim ke nomor tujuan dan saldo Digiflazz milik
 * toko terpotong sungguhan, sama seperti perilaku asli di CI3.
 */
class Cekout extends BaseController
{
    public function bayarpesananppob()
    {
        $usrid = session()->get('usrid');
        if ($usrid === null) {
            return $this->response->setJSON(['success' => false, 'message' => 'forbidden']);
        }

        $user = $this->func->getUser($usrid, 'semua');
        if ($user === null || (int) $user->status !== 1) {
            return $this->response->setJSON(['success' => false, 'message' => 'forbidden']);
        }

        $item = $this->db->table('transaksiprodukdigital')
            ->where('usrid', $usrid)
            ->where('idtransaksi', 0)
            ->orderBy('id', 'DESC')
            ->get()
            ->getRow();

        if ($item === null) {
            return $this->response->setJSON(['success' => false, 'message' => 'Keranjang kosong']);
        }

        $idproduk = (int) $item->idproduk;
        $h2h      = (int) $item->h2h;

        // Re-validasi harga di server (anti-tamper) -- sama seperti
        // tambahkeranjangppob(). idproduk=25 (Masa Aktif) dikecualikan,
        // sama seperti versi asli.
        if ($idproduk !== 25) {
            $hargaServer = $this->func->hargaJualSku((string) $item->idpo, $h2h);
            if ($hargaServer === null || (int) round($hargaServer) !== (int) round((float) $item->harga)) {
                $this->db->table('userdata')->where('id', $usrid)->update(['fcmtoken' => '', 'status' => 2]);

                return $this->response->setJSON(['success' => false, 'message' => 'forbidden']);
            }
        }

        $hargadigital = $idproduk === 25
            ? ((float) $item->harga / 1000) * (int) $item->jumlah
            : (float) $item->harga * (int) $item->jumlah;

        $saldoawal = (float) $this->func->getSaldo($usrid, 'saldo', 'usrid');
        $sisaSaldo = $saldoawal - $hargadigital;
        if ($sisaSaldo < 0) {
            return $this->response->setJSON(['success' => false, 'message' => 'Saldo Anda tidak cukup untuk membeli produk ini.']);
        }

        $kodeTrx    = 'TRX' . date('YmdHis');
        $saldoakhir = $saldoawal - $hargadigital;
        $produk     = $this->func->getProdukDigital($idproduk, 'semua');

        $idbayar = $this->db->table('pembayarandigital')->insert([
            'usrid'      => $usrid,
            'tgl'        => date('Y-m-d H:i:s'),
            'total'      => (int) round($hargadigital),
            'saldo'      => (int) round($hargadigital),
            'kodebayar'  => 0,
            'transfer'   => 0,
            'metode'     => 2,
            'diskon'     => 0,
            'status'     => 1,
            'kadaluarsa' => date('Y-m-d H:i:s', strtotime('+1 days')),
        ]) ? $this->db->insertID() : null;

        if ($idbayar === null) {
            return $this->response->setJSON(['success' => false, 'message' => 'Gagal mencatat pembayaran, silahkan coba lagi.']);
        }

        $this->db->table('saldo')->where('usrid', $usrid)->update([
            'saldo' => $saldoakhir,
            'apdet' => date('Y-m-d H:i:s'),
        ]);

        $this->db->table('saldohistory')->insert([
            'tgl'        => date('Y-m-d H:i:s'),
            'usrid'      => $usrid,
            'jenis'      => 2,
            'darike'     => 3,
            'sambung'    => $idbayar,
            'jumlah'     => (int) round($hargadigital),
            'saldoawal'  => (int) round($saldoawal),
            'saldoakhir' => (int) round($saldoakhir),
            'keterangan' => 'Pembayaran ' . ($produk->nama ?? 'Produk') . ' ' . $kodeTrx,
        ]);

        $invoice = date('Ymd') . $idbayar . '0';
        $this->db->table('pembayarandigital')->where('id', $idbayar)->update(['invoice' => $invoice]);

        $idtransaksi = $this->db->table('transaksidigital')->insert([
            'orderid'    => $kodeTrx,
            'tgl'        => date('Y-m-d H:i:s'),
            'kadaluarsa' => date('Y-m-d H:i:s', strtotime('+1 days')),
            'usrid'      => $usrid,
            'dropship'   => 0,
            'resi'       => $item->variasi,
            'status'     => 1,
            'idbayar'    => $idbayar,
            'saldo_awal' => (int) round($saldoawal),
            'saldo_akhir' => (int) round($saldoakhir),
        ]) ? $this->db->insertID() : null;

        if ($idtransaksi === null) {
            return $this->response->setJSON(['success' => false, 'message' => 'Gagal mencatat transaksi, silahkan coba lagi.']);
        }

        $this->db->table('transaksiprodukdigital')->where('id', $item->id)->update(['idtransaksi' => $idtransaksi]);

        // Panggilan ASLI ke Digiflazz -- lihat catatan di docblock class ini.
        if ($idproduk !== 25 && $h2h !== 1) {
            $set      = $this->func->getSetting('semua');
            $username = $set->mp_username ?? '';
            $apiKey   = $set->mp_apikey ?? '';

            $data = json_encode([
                'username'       => $username,
                'buyer_sku_code' => $item->idpo,
                'customer_no'    => $item->variasi,
                'ref_id'         => $kodeTrx,
                'sign'           => md5($username . $apiKey . $kodeTrx),
            ]);

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://api.digiflazz.com/v1/transaction');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
            curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            curl_exec($ch);
            curl_close($ch);
        }

        $this->func->addlog([
            'usrid'   => $usrid,
            'ip'      => $this->request->getIPAddress(),
            'type'    => 'web',
            'ket'     => 'cekout ppob ' . $kodeTrx,
            'created' => date('Y-m-d H:i:s'),
        ]);

        // Arahkan ke historidigital (bukan manage/pesananppob) -- halaman itu
        // datanya dari Assync (belum diport) jadi cuma "loading..." selamanya,
        // sedangkan historidigital sudah benar-benar berfungsi dengan data live.
        return $this->response->setJSON(['success' => true, 'url' => site_url('manage/historidigital')]);
    }

    /** Port dari Cekout::bayarpesanan() (CI3) -- checkout produk fisik. */
    public function bayarpesanan()
    {
        return $this->prosesBayarPesanan(0);
    }

    /** Port dari Cekout::bayarpesananjasa() (CI3) -- checkout jasa, logika identik kecuali flag jasa. */
    public function bayarpesananjasa()
    {
        return $this->prosesBayarPesanan(1);
    }

    private function prosesBayarPesanan(int $jasa)
    {
        $usrid = session()->get('usrid');
        $total = $this->request->getPost('total');
        if ($usrid === null || $total === null) {
            return $this->response->setJSON(['success' => false, 'message' => 'forbidden']);
        }

        $usr   = $this->func->getUser($usrid, 'semua');
        $items = $this->db->table('transaksiproduk')
            ->where('idtransaksi', 0)->where('idpo', 0)->where('jasa', $jasa)->where('usrid', $usrid)
            ->get()->getResult();

        $hargatotal = 0;
        foreach ($items as $trx) {
            $hargatotal += $trx->harga * $trx->jumlah;
        }

        $kodebayaran = random_int(100, 999);
        $kodebayar   = $kodebayaran;
        $diskon      = (int) $this->request->getPost('diskon');
        $saldoPost   = (int) $this->request->getPost('saldo');
        $totalPost   = (int) $total - $diskon;
        $ongkir      = (int) $this->request->getPost('ongkir');
        $transfer    = $totalPost - $saldoPost;

        if ($transfer > 0) {
            $totalAkhir = $kodebayaran + (int) $hargatotal;
        } else {
            $totalAkhir = (int) $hargatotal;
            $kodebayar  = 0;
        }

        // Port persis dari bayarpesananjasa() CI3 -- cek tambahan yang TIDAK
        // ada di versi fisik (saldo harus pas dgn total sebelum ongkir).
        if ($jasa === 1 && $saldoPost !== $totalPost) {
            $this->db->table('userdata')->where('id', $usr->id)->update(['fcmtoken' => '', 'status' => 2]);
        }

        if ($totalPost < ($hargatotal + $ongkir)) {
            $this->db->table('userdata')->where('id', $usr->id)->update(['fcmtoken' => '', 'status' => 2]);

            return $this->response->setJSON(['success' => false, 'message' => 'forbidden']);
        }

        $status = $saldoPost - $totalPost >= 0 ? 1 : 0;
        $kurir  = (string) $this->request->getPost('kurir');
        if ($kurir === 'cod') {
            $status = 1;
        }

        $alamatPost = $this->request->getPost('alamat');
        if ($alamatPost === '0') {
            $statusal = $this->db->table('alamat')->where('usrid', $usrid)->countAllResults() > 0 ? 0 : 1;
            $this->db->table('alamat')->insert([
                'usrid'   => $usrid,
                'status'  => $statusal,
                'idkec'   => $this->request->getPost('idkec'),
                'idkel'   => $this->request->getPost('idkel'),
                'judul'   => $this->request->getPost('judul'),
                'alamat'  => $this->request->getPost('alamatbaru'),
                'kodepos' => $this->request->getPost('kodepos'),
                'nama'    => $this->request->getPost('nama'),
                'nohp'    => $this->request->getPost('nohp'),
            ]);
            $idalamat = $this->db->insertID();
        } else {
            $idalamat = (int) $alamatPost;
        }

        $voucher = $this->func->getVoucher($this->request->getPost('kodevoucher'), 'id', 'kode');
        $this->db->table('pembayaran')->insert([
            'usrid'      => $usrid,
            'tgl'        => date('Y-m-d H:i:s'),
            'total'      => $totalAkhir,
            'saldo'      => $saldoPost,
            'kodebayar'  => $kodebayar,
            'transfer'   => $transfer,
            'voucher'    => $voucher ?? 0,
            'metode'     => $this->request->getPost('metode'),
            'diskon'     => $diskon,
            'status'     => $status,
            'kadaluarsa' => date('Y-m-d H:i:s', strtotime('+1 days')),
        ]);
        $idbayar = $this->db->insertID();

        if ((int) $this->request->getPost('metode') === 2) {
            $saldoawal  = (int) $this->func->getSaldo($usrid, 'saldo', 'usrid');
            $saldoakhir = $saldoawal - $saldoPost;
            $this->db->table('saldo')->where('usrid', $usrid)->update(['saldo' => $saldoakhir, 'apdet' => date('Y-m-d H:i:s')]);
            $this->db->table('saldohistory')->insert([
                'tgl' => date('Y-m-d H:i:s'), 'usrid' => $usrid, 'jenis' => 2, 'jumlah' => $saldoPost,
                'darike' => 3, 'sambung' => $idbayar, 'saldoawal' => $saldoawal, 'saldoakhir' => $saldoakhir,
                'keterangan' => 'belanja',
            ]);
        }

        $invoice = $usrid . date('Ymd') . $idbayar . $kodebayaran;
        $this->db->table('pembayaran')->where('id', $idbayar)->update(['invoice' => $invoice]);
        $invoiceDisplay = '#' . $invoice;

        $transaksiData = [
            'orderid'    => 'TRX' . date('YmdHis'),
            'tgl'        => date('Y-m-d H:i:s'),
            'kadaluarsa' => date('Y-m-d H:i:s', strtotime('+1 days')),
            'usrid'      => $usrid,
            'alamat'     => $idalamat,
            'berat'      => $this->request->getPost('berat'),
            'ongkir'     => $ongkir,
            'kurir'      => $kurir,
            'paket'      => $this->request->getPost('paket'),
            'dari'       => $this->request->getPost('dari'),
            'tujuan'     => $this->request->getPost('tujuan'),
            'status'     => $status,
            'jasa'       => $jasa,
            'idbayar'    => $idbayar,
        ];
        $dropship = $this->request->getPost('dropship');
        if ($dropship !== null && $dropship !== '') {
            $transaksiData['dropship']       = $dropship;
            $transaksiData['dropshipnomer']  = $this->request->getPost('dropshipnomer');
            $transaksiData['dropshipalamat'] = $this->request->getPost('dropshipalamat');
        }
        $this->db->table('transaksi')->insert($transaksiData);
        $idtransaksi = $this->db->insertID();

        $idprodukList = $this->request->getPost('idproduk') ?? [];
        foreach ($idprodukList as $cartId) {
            $this->db->table('transaksiproduk')->where('id', $cartId)->update(['idtransaksi' => $idtransaksi]);
        }

        // UPDATE STOK PRODUK -- sama persis dgn CI3, batalkan kalau stok kurang.
        $cartItems = $this->db->table('transaksiproduk')->where('idtransaksi', $idtransaksi)->get()->getResult();
        foreach ($cartItems as $r) {
            if ((int) $r->variasi !== 0) {
                $var = $this->func->getVariasi($r->variasi, 'semua');
                if ($var === null || $r->jumlah > $var->stok) {
                    return $this->response->setJSON(['success' => false, 'message' => 'stok produk tidak mencukupi']);
                }
                $stokBaru = $var->stok - $r->jumlah;
                $this->db->table('produkvariasi')->where('id', $r->variasi)->update(['stok' => $stokBaru, 'tgl' => date('Y-m-d H:i:s')]);
                $this->db->table('historystok')->insert([
                    'usrid' => $usrid, 'stokawal' => $var->stok, 'stokakhir' => $stokBaru,
                    'variasi' => $r->variasi, 'jumlah' => $r->jumlah, 'tgl' => date('Y-m-d H:i:s'), 'idtransaksi' => $idtransaksi,
                ]);
            } else {
                $pro = $this->func->getProduk($r->idproduk, 'semua');
                if ($pro === null || $r->jumlah > $pro->stok) {
                    return $this->response->setJSON(['success' => false, 'message' => 'stok produk tidak mencukupi']);
                }
                $stokBaru = $pro->stok - $r->jumlah;
                $this->db->table('produk')->where('id', $r->idproduk)->update(['stok' => $stokBaru, 'tglupdate' => date('Y-m-d H:i:s')]);
                $this->db->table('historystok')->insert([
                    'usrid' => $usrid, 'stokawal' => $pro->stok, 'stokakhir' => $stokBaru,
                    'variasi' => 0, 'jumlah' => $r->jumlah, 'tgl' => date('Y-m-d H:i:s'), 'idtransaksi' => $idtransaksi,
                ]);
            }
        }

        $this->func->addlog([
            'usrid' => $usrid, 'ip' => $this->request->getIPAddress(), 'type' => 'web',
            'ket' => 'bayar pesanan ' . ($jasa === 1 ? 'jasa' : 'fisik'), 'created' => date('Y-m-d H:i:s'),
        ]);

        $this->kirimNotifikasiPesananBaru($usrid, $idbayar, $idalamat, $invoiceDisplay, $totalAkhir, $kodebayar, $ongkir, $diskon, $kurir, (string) $this->request->getPost('paket'));

        $idbayarEnc = $this->func->arrEnc(['idbayar' => $idbayar]);
        $url = $status === 0 ? site_url('home/invoice') . '?inv=' . $idbayarEnc : site_url('manage/pesanan');

        return $this->response->setJSON(['success' => true, 'url' => $url]);
    }

    private function kirimNotifikasiPesananBaru(int $usrid, int $idbayar, int $idalamat, string $invoice, int $total, int $kodebayar, int $ongkir, int $diskon, string $kurir, string $paket): void
    {
        $usr      = $this->func->getUser($usrid, 'semua');
        $alamat   = $this->func->getAlamat($idalamat, 'semua');
        $toko     = $this->func->getSetting('semua');
        $notifset = $this->func->getNotifSetting('semua');
        $pembelian = $total - $ongkir - $kodebayar;
        $diskonText   = $diskon !== 0 ? 'Diskon: <b>Rp ' . $this->func->formUang($diskon) . "</b><br/>" : '';
        $diskonWaText = $diskon !== 0 ? 'Diskon: *Rp ' . $this->func->formUang($diskon) . "*\n" : '';

        if (($notifset->email_pesanan ?? 0) == 1) {
            $pesan = "Halo <b>{$usr->nama}</b><br/>Terimakasih sudah membeli produk kami.<br/>" .
                "Segera lakukan pembayaran agar tidak terjadi pembatalan otomatis. Sebagai informasi, berikut detail pesananmu<br/>" .
                "No Invoice: <b>{$invoice}</b><br/>Total Pesanan: <b>Rp " . $this->func->formUang($total) . "</b><br/><br/>" .
                '<b>Rincian</b><br/>Pembelian: <b>Rp ' . $this->func->formUang($pembelian) . "</b><br/>" .
                'Kode unik: <b>Rp ' . $this->func->formUang($kodebayar) . "</b><br/>" .
                'Ongkos Kirim: <b>Rp ' . $this->func->formUang($ongkir) . "</b><br/>" . $diskonText .
                'Kurir Pengiriman: <b>' . strtoupper($kurir . ' ' . $paket) . "</b><br/><br/>" .
                "Detail Pengiriman<br/>Penerima: <b>{$alamat->nama}</b><br/>No HP: <b>{$alamat->nohp}</b><br/>Alamat: <b>{$alamat->alamat}</b><br/><br/>" .
                'Untuk pembayaran silahkan langsung klik link berikut:<br/>' .
                "<a href='" . site_url('home/invoice') . '?inv=' . $this->func->arrEnc(['idbayar' => $idbayar]) . "'>Bayar Pesanan Sekarang &raquo;</a>";
            $this->func->sendEmail($usr->username, $toko->nama . ' - Pesanan', $pesan, 'Pesanan');
        }
        if (($notifset->wa_pesanan_admin ?? 0) == 1) {
            $pesan = "Halo *{$usr->nama}*\nTerimakasih sudah membeli produk kami.\n" .
                "Segera lakukan pembayaran agar tidak terjadi pembatalan otomatis.\n\n" .
                "No Invoice: *{$invoice}*\nTotal Pesanan: *Rp " . $this->func->formUang($total) . "*\n\n" .
                "*Rincian:*\nPembelian: *Rp " . $this->func->formUang($pembelian) . "*\n" .
                'Kode Unik: *Rp ' . $this->func->formUang($kodebayar) . "*\n" .
                'Ongkos Kirim: *Rp ' . $this->func->formUang($ongkir) . "*\n" . $diskonWaText .
                'Kurir Pengiriman: *' . strtoupper($kurir . ' ' . $paket) . "*\n\n" .
                "Detail Pengiriman\nPenerima: *{$alamat->nama}*\nNo HP: *{$alamat->nohp}*\nAlamat: *{$alamat->alamat}*\n\n" .
                'Untuk pembayaran silahkan langsung klik link berikut: ' . site_url('home/invoice') . '?inv=' . $this->func->arrEnc(['idbayar' => $idbayar]);
            $this->func->sendWA($this->func->getProfil($usr->id, 'nohp', 'usrid'), $pesan);
        }
        if (($notifset->email_pesanan_admin ?? 0) == 1) {
            $pesan = "<h3>Pesanan Baru</h3><br/><b>" . strtoupper(strtolower($usr->nama)) . "</b> telah membuat pesanan baru dengan total pembayaran " .
                '<b>Rp. ' . $this->func->formUang($total) . "</b> Invoice ID: <b>{$invoice}</b><br/>&nbsp;<br/>&nbsp;<br/>" .
                "Cek Pesanan Pembeli di <b>Dashboard Admin {$toko->nama}</b><br/><a href='" . site_url('admin') . "'>Klik Disini</a>";
            $this->func->sendEmail($toko->email, $toko->nama . ' - Pesanan Baru', $pesan, 'Pesanan Baru di ' . $toko->nama);
        }
        if (($notifset->wa_pesanan ?? 0) == 1) {
            $pesan = "*Pesanan Baru*\n*" . strtoupper(strtolower($usr->nama)) . "* telah membuat pesanan baru dengan detail:\n" .
                'Total Pembayaran: *Rp. ' . $this->func->formUang($total) . "*\nInvoice ID: *{$invoice}*\n\n" .
                "Cek Pesanan Pembeli di *Dashboard Admin {$toko->nama}*";
            $this->func->sendWA($toko->wasap, $pesan);
        }
    }

    /** Port dari Home::midtranstoken() (CI3) -- generate Snap token utk pembayaran fisik/jasa. */
    public function midtransToken()
    {
        $usrid = session()->get('usrid');
        $invoice = $this->request->getPost('invoice');
        if ($usrid === null || $invoice === null) {
            return $this->response->setStatusCode(404)->setBody('Invoice tidak ditemukan');
        }

        $bayar = $this->func->getBayar($invoice, 'semua', 'invoice');
        if ($bayar === null || (int) $bayar->usrid !== (int) $usrid) {
            return $this->response->setStatusCode(404)->setBody('Invoice tidak ditemukan');
        }

        $this->func->configureMidtrans();
        $set    = $this->func->getSetting('semua');
        $user   = $this->func->getUser($bayar->usrid, 'semua');
        $profil = $this->func->getProfil($bayar->usrid, 'semua', 'usrid');

        $token = \Midtrans\Snap::getSnapToken([
            'transaction_details' => [
                'order_id'     => $invoice,
                'gross_amount' => (int) $bayar->transfer + (int) ($set->payment_biaya ?? 0),
            ],
            'customer_details' => [
                'first_name' => $profil->nama,
                'last_name'  => '',
                'email'      => $user->username,
                'phone'      => $profil->nohp,
            ],
        ]);

        return $this->response->setBody($token);
    }
}
