<?php
/**
 * Pembantu global (helper) — dipanggil dari view maupun controller.
 */

use App\Core\Acl;
use App\Core\Auth;
use App\Core\Csrf;
use App\Core\Dates;
use App\Core\Flash;
use App\Core\Num;
use App\Core\Settings;
use App\Core\Url;
use App\Core\View;

if (!function_exists('e')) {
    /** Escape HTML — WAJIB dipakai untuk semua output dinamis. */
    function e($v): string { return htmlspecialchars((string)($v ?? ''), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
}

if (!function_exists('attr')) {
    function attr($v): string { return htmlspecialchars((string)($v ?? ''), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
}

if (!function_exists('rp')) {
    /** Rupiah teks: Rp 1.250.000 / (Rp 1.250.000) / '-' bila nol. */
    function rp($v, ?int $dec = null): string { return Num::rupiah($v, $dec); }
}

if (!function_exists('rph')) {
    /** Rupiah HTML dengan warna merah untuk negatif. */
    function rph($v, ?int $dec = null): string { return Num::rupiahHtml($v, $dec); }
}

if (!function_exists('nf')) {
    function nf($v, ?int $dec = null): string { return Num::fmt($v, $dec); }
}

if (!function_exists('pct')) {
    function pct($v, int $dec = 1): string { return Num::percent($v, $dec); }
}

if (!function_exists('tgl')) {
    /** Tanggal DD-MM-YYYY. */
    function tgl(?string $ymd): string { return Dates::fmt($ymd); }
}

if (!function_exists('tglWaktu')) {
    function tglWaktu(?string $dt): string { return Dates::fmtDateTime($dt); }
}

if (!function_exists('tglPanjang')) {
    function tglPanjang(?string $ymd): string { return Dates::fmtLong($ymd); }
}

if (!function_exists('url')) {
    function url(string $path = '/', array $q = []): string { return Url::to($path, $q); }
}

if (!function_exists('asset')) {
    function asset(string $p): string { return Url::asset($p); }
}

if (!function_exists('urlCurrent')) {
    function urlCurrent(array $merge = [], array $remove = []): string { return Url::current($merge, $remove); }
}

if (!function_exists('csrf')) {
    function csrf(): string { return Csrf::field(); }
}

if (!function_exists('csrfToken')) {
    function csrfToken(): string { return Csrf::token(); }
}

if (!function_exists('can')) {
    function can(string $module, string $action = 'view'): bool { return Acl::can($module, $action); }
}

if (!function_exists('old')) {
    function old(string $key, $default = '') { return Flash::old($key, $default); }
}

if (!function_exists('setting')) {
    function setting(string $key, $default = null) { return Settings::get($key, $default); }
}

if (!function_exists('userName')) {
    function userName(): string { return Auth::name(); }
}

if (!function_exists('badge')) {
    /** Lencana Bootstrap. */
    function badge(string $text, string $color = 'secondary', bool $soft = true): string
    {
        $cls = $soft ? "badge bg-$color-subtle text-$color-emphasis border border-$color-subtle" : "badge bg-$color";
        return '<span class="' . $cls . '">' . e($text) . '</span>';
    }
}

if (!function_exists('statusBadge')) {
    /** Lencana status pembayaran berdasarkan master payment_statuses. */
    function statusBadge(?string $code): string
    {
        static $map = null;
        if ($map === null) {
            $map = [];
            try {
                foreach (App\Core\Database::i()->all('SELECT code, name, color FROM payment_statuses') as $r) {
                    $map[$r['code']] = $r;
                }
            } catch (\Throwable $e) { $map = []; }
        }
        $code = (string)$code;
        $s = $map[$code] ?? ['name' => $code !== '' ? str_replace('_', ' ', $code) : '-', 'color' => 'secondary'];
        return badge($s['name'], $s['color']);
    }
}

if (!function_exists('docStatusBadge')) {
    function docStatusBadge(?string $s): string
    {
        $m = [
            'active'      => ['Aktif', 'success'],
            'cancelled'   => ['Dibatalkan', 'dark'],
            'replaced'    => ['Diganti', 'secondary'],
            'revised'     => ['Direvisi', 'secondary'],
            'written_off' => ['Dihapuskan', 'dark'],
        ];
        [$label, $color] = $m[(string)$s] ?? ['-', 'secondary'];
        return badge($label, $color);
    }
}

if (!function_exists('agingColor')) {
    function agingColor(?int $days): string
    {
        if ($days === null) return 'secondary';
        if ($days < 0)   return 'info';
        if ($days === 0) return 'primary';
        if ($days <= 30) return 'success';
        if ($days <= 60) return 'warning';
        if ($days <= 120)return 'danger';
        return 'dark';
    }
}

if (!function_exists('acpIndicator')) {
    /**
     * Indikator target ACP.
     * @return array{color:string,label:string,icon:string}
     */
    function acpIndicator(?float $actual, ?float $target, float $tolerance = 5.0): array
    {
        if ($actual === null || $target === null || $target <= 0) {
            return ['color' => 'secondary', 'label' => 'Tanpa Target', 'icon' => 'dash-circle'];
        }
        $diff = $actual - $target;
        if ($diff <= 0)             return ['color' => 'success', 'label' => 'Memenuhi Target', 'icon' => 'check-circle-fill'];
        if ($diff <= $tolerance)    return ['color' => 'warning', 'label' => 'Mendekati Target', 'icon' => 'exclamation-triangle-fill'];
        return ['color' => 'danger', 'label' => 'Di Bawah Target', 'icon' => 'x-circle-fill'];
    }
}

if (!function_exists('arr')) {
    function arr($json): array
    {
        if (is_array($json)) return $json;
        if (!$json) return [];
        $d = json_decode((string)$json, true);
        return is_array($d) ? $d : [];
    }
}

if (!function_exists('sortLink')) {
    /** Tautan pengurutan kolom tabel. */
    function sortLink(string $field, string $label, string $currentSort = '', string $currentDir = 'asc'): string
    {
        $dir = ($currentSort === $field && $currentDir === 'asc') ? 'desc' : 'asc';
        $icon = '';
        if ($currentSort === $field) {
            $icon = ' <i class="bi bi-caret-' . ($currentDir === 'asc' ? 'up' : 'down') . '-fill small"></i>';
        }
        return '<a href="' . e(urlCurrent(['urut' => $field, 'arah' => $dir, 'hal' => 1]))
             . '" class="text-decoration-none text-body-secondary">' . e($label) . $icon . '</a>';
    }
}

if (!function_exists('viewStart')) {
    function viewStart(string $name): void { View::start($name); }
    function viewStop(): void { View::stop(); }
}

if (!function_exists('nlbr')) {
    function nlbr(?string $s): string { return nl2br(e($s)); }
}

if (!function_exists('truncate')) {
    function truncate(?string $s, int $len = 40): string
    {
        $s = (string)$s;
        return mb_strlen($s) > $len ? mb_substr($s, 0, $len - 1) . '…' : $s;
    }
}

if (!function_exists('ukuranBerkas')) {
    /** Ukuran berkas dalam satuan yang mudah dibaca. */
    function ukuranBerkas($bytes): string
    {
        $bytes = (float)$bytes;
        $u = ['B', 'KB', 'MB', 'GB', 'TB'];
        $i = 0;
        while ($bytes >= 1024 && $i < count($u) - 1) { $bytes /= 1024; $i++; }
        return Num::fmt($bytes, $i === 0 ? 0 : 1) . ' ' . $u[$i];
    }
}

if (!function_exists('activeIf')) {
    function activeIf(bool $cond, string $cls = 'active'): string { return $cond ? $cls : ''; }
}

if (!function_exists('json_attr')) {
    function json_attr($data): string
    {
        return htmlspecialchars((string)json_encode($data, JSON_UNESCAPED_UNICODE | JSON_HEX_APOS | JSON_HEX_QUOT), ENT_QUOTES, 'UTF-8');
    }
}
