<?php

namespace App\Controllers\Warga;

use App\Controllers\BaseController;
use App\Models\Buktibayarmodel;
use CodeIgniter\API\ResponseTrait;

use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;

use App\Models\Kkmodel;
use App\Models\Kolektormodel;
use App\Models\Operatormodel;
use App\Models\Tarifmodel;
use App\Models\Diskonmodel;
use App\Models\Invoicemodel;
use App\Models\Strukmodel;
use App\Models\Strukdetailmodel;
use App\Models\Transaksimodel;

use Dompdf\Dompdf;
use Endroid\QrCode\Color\Color;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\RoundBlockSizeMode;
use Endroid\QrCode\Writer\PngWriter;

class Home extends BaseController
{
    use ResponseTrait;

    private function getDataWarga(){
        $session = session();
        if (isset($_SESSION['warga'])) {
            $kk = $session->get("warga");
            return $kk;
        }else{
            die("Invalid Access!");
        }
    }

    public function index($kode_kk){
        $session = session();
        $kkmodel = new Kkmodel();
        $kkbuilder = $kkmodel->builder("vkk");
        $kk = $kkbuilder->where("kode",$kode_kk)->get()->getRowArray();
        
        if($kk != null){
            $session->set("warga",$kk);
        }
        
        return view('warga/splash');
    }

    public function dashboard()
    {
        $data['kk'] = $this->getDataWarga();
        return view('warga/home',$data);
    }

    public function pembayaran()
    {
        $data['kk'] = $this->getDataWarga();

        $invoicemodel = new Invoicemodel();
        $invoicebuilder = $invoicemodel->builder("vinvoiceopen");
        $invoicebuilder->where("id_kk",$data['kk']['id_kk']);
        $invoicebuilder->where("id_invoice not in (select id_invoice from vstrukdetail where flag_validasi='1' or flag_validasi='0')");
        $invoices = $invoicebuilder->get()->getResultArray();
        $data['invoices'] = $invoices;
        return view('warga/pembayaran',$data);
    }

    public function save_invoice(){
        $selectedPeriods = $this->request->getPost('input_check');
        if (empty($selectedPeriods)) {
            return $this->fail(["error" => "Silakan pilih setidaknya satu periode pembayaran."],400,null,'input');
        }

        $total = 0;
        foreach($selectedPeriods as $item){
            $invoicemodel = new Invoicemodel();
            $invoice = $invoicemodel->where("flag_close","0")->where("id_invoice",$item)->first();
            if(!$invoice){
                return $this->fail(["error" => "Invoice not available!"],400,null,'db');
            }
            $total += $invoice['nominal_akhir'];
        }

        session()->set('selectedPeriods', $selectedPeriods);
        session()->set('total_nominal', $total);

        return $this->respond(["status" => "success"],200);
    }

    public function pembayaran_info()
    {
        $data['kk'] = $this->getDataWarga();

        $invoicemodel = new Invoicemodel();
        $invoicebuilder = $invoicemodel->builder("vinvoiceopen");
        $invoicebuilder->where("id_kk",$data['kk']['id_kk']);
        $invoicebuilder->where("id_invoice not in (select id_invoice from vstrukdetail where flag_validasi='1' or flag_validasi='0')");
        $invoices = $invoicebuilder->get()->getResultArray();
        $data['invoices'] = $invoices;
        return view('warga/pembayaran_info',$data);
    }

    public function save_info(){
        $nama_pembayar = $this->request->getPost('nama_pembayar');
        $nomor_telepon = $this->request->getPost('nomor_telepon');
        if (empty($nama_pembayar) || empty($nomor_telepon)) {
            return $this->fail(["error" => "Silakan isi lengkap isian."],400,null,'input');
        }

        session()->set('nama_pembayar', $nama_pembayar);
        session()->set('nomor_telepon', $nomor_telepon);

        return $this->respond(["status" => "success"],200);
    }

    public function upload_bukti()
    {
        $data['kk'] = $this->getDataWarga();

        if (!isset($_SESSION['selectedPeriods'])) {
            return redirect()->to("vwarga/pembayaran");
        }

        $data['total'] = session()->get("total_nominal");
        return view('warga/upload_bukti',$data);
    }

    public function upload_bukti_proses(){
        $data['kk'] = $this->getDataWarga();
        if (!isset($_SESSION['selectedPeriods'])) {
            return $this->fail(["error" => "Periode not available!"],400,null,'db');
        }

        $selectedPeriods = session()->get("selectedPeriods");
        $nama_pembayar = session()->get("nama_pembayar");
        $nomor_telepon = session()->get("nomor_telepon");
        
        $total = 0;
        $total_diskon = 0;
        $total_akhir = 0;

        foreach($selectedPeriods as $item){
            $invoicemodel = new Invoicemodel();
            $invoice = $invoicemodel->where("flag_close","0")->where("id_invoice",$item)->first();
            if(!$invoice){
                return $this->fail(["error" => "Invoice not available!"],400,null,'db');
            }
            $total += $invoice['nominal'];
            $total_diskon += $invoice['nominal_diskon'];
            $total_akhir += $invoice['nominal_akhir'];
        }

        $request = [
            'id_grup_transaksi' => '2',
            'id_kolektor' => 0,
            'tanggal' => date("Y-m-d"),
            'id_operator' => 0,
            'created_by' => 14,
            'updated_by' => 14,
            'total' => $total,
            'total_diskon' => $total_diskon,
            'total_akhir' => $total_akhir,
            'id_jenis_pembayaran' => '2',
            'tanggal_pembayaran' => date("Y-m-d"),
            'pembayar' => $nama_pembayar,
            'no_telp' => $nomor_telepon,
            'flag_validasi' => '0'
        ];

        $tmodel = new Transaksimodel();
        $tmodel->db->transBegin();
        $tmodel->insert($request);
        if($tmodel->db->transStatus() === false){
            $tmodel->db->transRollback();
            return $this->fail($tmodel->errors(),400,null,'db');
        }else{
            $tmodel->db->transCommit();
            $id_transaksi = $tmodel->getInsertID();

            $kode = $tmodel->getNewKode();
            if (empty($kode)){
                return $this->fail(["error" => "Empty Kode"],400,null,'db');
            }
            $request = ["kode" => $kode, "flag_validasi" => "1"];
            $tmodel->update($id_transaksi, $request);
        }

        $strukmodel = new Strukmodel();
        $strukdetailmodel = new Strukdetailmodel();

        $struk_builder = $strukmodel->builder();
        $struk_builder->where("id_transaksi",$id_transaksi);
        $struk_builder->where("id_kk",$data['kk']['id_kk']);
        $data_struk = $struk_builder->get()->getRow();
        $id_struk = "";

        if ($data_struk!=null){
            $id_struk = $data_struk->id_struk;
        }else{
            //Struk untuk transaksi dan kk ini belum ada, buat baru
            $data_struk = [
                "id_transaksi" => $id_transaksi,
                "id_kk" => $data['kk']['id_kk']
            ];
            $id_struk = $strukmodel->insert($data_struk);
            if(empty($id_struk)){
                $tmodel->delete($id_transaksi);
                return $this->fail(["error" => "Struk creating failed"],400,null,'db');
            }
        }

        $strukmodel->db->transBegin();
        //clear detail struk untuk transaksi ini
        $strukdetail_builder = $strukdetailmodel->builder();
        $strukdetailmodel->db->transBegin();
        $strukdetail_builder->delete(["id_struk" => $id_struk]);

        //insert baru untuk tiap bulan iuran
        foreach($selectedPeriods as $iuran){
            $invoice = $invoicemodel->find($iuran);
            //pastikan invoice masih open
            if($invoice["flag_close"] == "1"){
                $tmodel->delete($id_transaksi);
                $strukmodel->delete($id_struk);
                $strukdetailmodel->db->transRollback();
                return $this->fail(["error" => "Invoice sudah di closed"],400,null,'db');
            }

            //pastikan invoice tidak dibuka di transaksi lain
            $strukdetailmodel = new Strukdetailmodel();
            $strukdetailbuilder = $strukdetailmodel->builder("vstrukdetail");
            $strukdetailbuilder->where("id_invoice",$invoice["id_invoice"]);
            $strukdetailbuilder->where("id_transaksi != ",$id_transaksi);
            $strukdetailbuilder->where("flag_batal","0");
            $strukdetail = $strukdetailbuilder->get()->getRow();
            if($strukdetail != null){
                $tmodel->delete($id_transaksi);
                $strukmodel->delete($id_struk);
                $strukmodel->db->transRollback();
                $strukdetailmodel->db->transRollback();
                return $this->fail(["error" => "Invoice sudah di open di transaksi lain"],400,null,'db');
            }

            $detail_struk=[
                "id_struk_detail" => date("YmdHis.u").$id_struk.$invoice["id_invoice"],
                "id_struk" => $id_struk,
                "id_invoice" => $invoice["id_invoice"],
                "bulan" => $invoice["bulan"],
                "tahun" => $invoice["tahun"],
                "nominal" => $invoice["nominal"],
                "nominal_diskon" => $invoice["nominal_diskon"],
                "nominal_total" => $invoice["nominal_akhir"],
                "created_by" => 14,
                "updated_by" => 14
            ];
            $total += $invoice['nominal'];
            $total_diskon += $invoice['nominal_diskon'];
            $total_akhir += $invoice['nominal_akhir'];
            $strukdetailmodel->insert($detail_struk);

            if($strukdetailmodel->db->transFailure){
                $tmodel->delete($id_transaksi);
                $strukmodel->delete($id_struk);
                $strukmodel->db->transRollback();
                $strukdetailmodel->db->transRollback();
                return $this->fail(["error" => "Invalid Struk Detail"],400,null,'db');
            }
        }

        //update total di struk
        $data_struk = [
            "total" => $total,
            "total_diskon" => $total_diskon,
            "total_akhir" => $total_akhir 
        ];

        $strukmodel->update($id_struk,$data_struk);
        if($strukmodel->db->transFailure){
            $tmodel->delete($id_transaksi);
            $strukmodel->delete($id_struk);
            $strukdetailmodel->db->transRollback();
            $strukmodel->db->transRollback();
            return $this->fail(["error" => "Struk update failed"],400,null,'db');
        }

        $files = $this->request->getFiles();
        if ($files && isset($files['bukti'])) {
            foreach ($files['bukti'] as $file) {
                if ($file->isValid() && !$file->hasMoved()) {
                    $newName = $id_transaksi . '_' . time() . '.' . $file->getExtension();
                    $uploadPath = FCPATH .'bukti_bayar/';
                    $file->move($uploadPath, $newName);
                    
                    $buktibayarmodel = new Buktibayarmodel();
                    $insert = [
                        "id_transaksi" => $id_transaksi,
                        "fnama" => $newName
                    ];
                    $buktibayarmodel->insert($insert);
                }
            }
        }else{
            $tmodel->delete($id_transaksi);
            $strukmodel->delete($id_struk);
            $strukdetailmodel->db->transRollback();
            $strukmodel->db->transRollback();
            return $this->fail(["error" => "Bukti bayar tidak tersedia!"],400,null,'input');
        }

        $strukmodel->db->transComplete();
        $strukdetailmodel->db->transComplete();

        session()->set("id_transaksi",$id_transaksi);
        return $this->response->setJSON(['status' => 'success']);
    }

    public function pembayaran_selesai(){
        $data['kk'] = $this->getDataWarga();

        $id_transaksi = "";
        if (!isset($_SESSION['id_transaksi'])) {
            return redirect()->to("vwarga/pembayaran");
        }
        $id_transaksi = session()->get("id_transaksi");
        $transaksimodel = new Transaksimodel();
        $transaksibuilder = $transaksimodel->builder("vtransaksi");
        $transaksibuilder->where("id_transaksi",$id_transaksi);
        $transaksi = $transaksibuilder->get()->getRow();
        if(!$transaksi){
            session()->unset("id_transaksi");
            return redirect()->to("vwarga/dashboard");
        }
        
        $data['nomor_transaksi'] = $transaksi->kode;
        $data['tanggal'] = $transaksi->tanggal;
        $data['nominal'] = $transaksi->total_akhir;
        
        return view('warga/pembayaranselesai',$data);
    }

    public function riwayat(){
        $data['kk'] = $this->getDataWarga();

        $transaksimodel = new Transaksimodel();
        $transaksibuilder = $transaksimodel->builder("vtransaksi2");
        $transaksi = $transaksibuilder->where("id_kk",$data['kk']['id_kk'])->get()->getResultArray();
        $data['transaksi'] = $transaksi;
        
        return view('warga/riwayat',$data);
    }

    public function riwayat_detail($id_transaksi){
        $data['kk'] = $this->getDataWarga();

        $transaksimodel = new Transaksimodel();
        $transaksibuilder = $transaksimodel->builder("vtransaksi");
        $transaksi = $transaksibuilder->where("id_transaksi",$id_transaksi)->get()->getRowArray();
        $data['transaksi'] = $transaksi;
        
        return view('warga/riwayat_detail',$data);
    }

    public function cetak_struk($id_struk){
        $data = array();
        $data["company_name"] = COMPANY_NAME;
        $data["company_logo"] = base_url("img/logo_company.png");

        $strukmodel = new Strukmodel();
        $strukbuilder = $strukmodel->builder("vstruk");
        $strukbuilder->where("id_struk",$id_struk);
        $strukbuilder->where("flag_validasi","2");
        $struk = $strukbuilder->get()->getRow();
        if($struk == null){
            die("Struk Not Available!");
        }

        $data["tanggal"] = $struk->tanggal;
        $data["nomor_transaksi"] = $struk->kode_transaksi;
        $data["nomor_struk"] = $struk->nomor;
        $data['kode_rumah'] = $struk->kode_kk;
        $data['nama_pemilik'] = $struk->nama_pemilik;
        $data['alamat'] = $struk->nama_jalan.', '.$struk->nama_blok.', No. '.$struk->nomor_rumah;
        $data['nominal'] = $struk->total_akhir;
        $data['operator'] = $struk->nama_operator;
        $data['kolektor'] = $struk->nama_kolektor;
        $data['jenis_pembayaran'] = $struk->jenis_pembayaran;
        $data['tanggal_pembayaran'] = $struk->tanggal_pembayaran;
        $data['receiver'] = $struk->pembayar;
        $data['no_telp'] = $struk->no_telp;

        // ===== Data Transaksi ===== //
        $qr_text = base_url().'transaksi/struk/'.$struk->id_struk;

        // ===== Buat QR Code ===== //
        $writer = new PngWriter();
        $qrCode = new QrCode(
            data: $qr_text,
            encoding: new Encoding('UTF-8'),
            errorCorrectionLevel: ErrorCorrectionLevel::Low,
            size: 100,
            margin: 0,
            roundBlockSizeMode: RoundBlockSizeMode::Margin,
            foregroundColor: new Color(0, 0, 0),
            backgroundColor: new Color(255, 255, 255)
        );

        $result = $writer->write($qrCode);

        ob_start();
        $result->saveToFile('php://output');
        $imageData = ob_get_clean();
        $base64 = base64_encode($imageData);
        $imgSrc = 'data:image/png;base64,' . $base64;

        $data['qr_code'] = $imgSrc;

        $periode = array();
        $invoice = array();

        $strukdetailmodel = new Strukdetailmodel();
        $strukdetailbuilder = $strukdetailmodel->builder("vstrukdetail");
        $strukdetail = $strukdetailbuilder->where("id_struk",$id_struk)->get()->getResultArray();
        foreach($strukdetail as $item){
            $periode[] = $item['bulan'].'-'.$item['tahun'];
            $invoice[] = $item["nomor_invoice"];
        }
        $data["periode"] = implode(", ",$periode);
        $data["nomor_invoice"] = implode(", ",$invoice);

        $html = view('print/struk', $data);

        while (ob_get_level()) {
            ob_end_clean();
        }

        $options = new Options();
        $options->set('isRemoteEnabled', true);
        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper([0, 0, 93.2, 241.3], 'portrait'); // 1/3 folio
        $dompdf->render();
        $dompdf->stream('struk_pembayaran.pdf', ['Attachment' => false]);
    }
}
