<?php

function komplain_status_meta($status)
{
    $status = strtolower(trim((string) $status));

    $map = [
        'pending' => ['label' => 'Pending', 'badge' => 'warning'],
        'pending_pelaksana' => ['label' => 'Menunggu Pelaksana', 'badge' => 'warning'],
        'diproses_pelaksana' => ['label' => 'Diproses Pelaksana', 'badge' => 'info'],
        'dikirim_ke_teknisi' => ['label' => 'Dikirim ke Teknisi', 'badge' => 'secondary'],
        'diproses_teknisi' => ['label' => 'Diproses Teknisi', 'badge' => 'primary'],
        'selesai_teknisi' => ['label' => 'Hasil dari Teknisi', 'badge' => 'success'],
        'menunggu_pelaksana' => ['label' => 'Hasil dari Teknisi', 'badge' => 'success'],
        'selesai_pelaksana' => ['label' => 'Siap Dikirim ke Admin', 'badge' => 'success'],
        'menunggu_admin' => ['label' => 'Menunggu Persetujuan Admin', 'badge' => 'dark'],
        'proses' => ['label' => 'Proses', 'badge' => 'primary'],
        'selesai' => ['label' => 'Selesai', 'badge' => 'success'],
        'final_selesai' => ['label' => 'Selesai', 'badge' => 'success'],
    ];

    return $map[$status] ?? ['label' => ucfirst(str_replace('_', ' ', $status)), 'badge' => 'secondary'];
}

function komplain_status_label($status)
{
    return komplain_status_meta($status)['label'];
}

function komplain_status_badge($status)
{
    return komplain_status_meta($status)['badge'];
}

function komplain_group_statuses($group)
{
    $groups = [
        'pending' => ['pending', 'pending_pelaksana'],
        'proses' => [
            'proses',
            'diproses_pelaksana',
            'dikirim_ke_teknisi',
            'diproses_teknisi',
            'selesai_teknisi',
            'menunggu_pelaksana',
            'selesai_pelaksana',
            'menunggu_admin'
        ],
        'selesai' => ['selesai', 'final_selesai'],
    ];

    return $groups[$group] ?? [];
}

function komplain_group_sql($column, $group)
{
    $statuses = komplain_group_statuses($group);

    if (empty($statuses)) {
        return "1=0";
    }

    $quoted = array_map(function ($status) {
        return "'" . addslashes($status) . "'";
    }, $statuses);

    return $column . ' IN (' . implode(', ', $quoted) . ')';
}

function komplain_escape($conn, $value)
{
    return mysqli_real_escape_string($conn, trim((string) $value));
}

function komplain_row_value(array $row, $key, $default = '')
{
    if (!array_key_exists($key, $row)) {
        return $default;
    }

    $value = $row[$key];

    return $value === null ? $default : $value;
}

function komplain_first_non_empty(array $row, array $keys, $default = '')
{
    foreach ($keys as $key) {
        $value = komplain_row_value($row, $key, null);

        if ($value !== null && $value !== '') {
            return $value;
        }
    }

    return $default;
}

function komplain_wilayah_options($conn)
{
    $items = [];
    $query = mysqli_query($conn, "SELECT id, nama FROM wilayah ORDER BY nama ASC");

    while ($query && ($row = mysqli_fetch_assoc($query))) {
        $items[] = $row;
    }

    return $items;
}

function komplain_cluster_map($conn)
{
    $map = [];
    $query = mysqli_query($conn, "SELECT id, wilayah_id, nama FROM cluster ORDER BY nama ASC");

    while ($query && ($row = mysqli_fetch_assoc($query))) {
        $wilayahId = (int) $row['wilayah_id'];

        if (!isset($map[$wilayahId])) {
            $map[$wilayahId] = [];
        }

        $map[$wilayahId][] = [
            'id' => (int) $row['id'],
            'nama' => $row['nama'],
        ];
    }

    return $map;
}

function komplain_format_lokasi($wilayahNama, $clusterNama, $detail = '')
{
    $parts = array_filter([
        trim((string) $wilayahNama),
        trim((string) $clusterNama),
        trim((string) $detail),
    ]);

    return empty($parts) ? '-' : implode(' - ', $parts);
}

function komplain_find_wilayah_by_name($conn, $nama)
{
    $nama = trim((string) $nama);

    if ($nama === '') {
        return null;
    }

    $namaSql = komplain_escape($conn, $nama);
    $query = mysqli_query($conn, "SELECT id, nama FROM wilayah WHERE LOWER(nama) = LOWER('{$namaSql}') LIMIT 1");

    return $query ? mysqli_fetch_assoc($query) : null;
}

function komplain_find_cluster_by_name($conn, $wilayahId, $nama)
{
    $wilayahId = (int) $wilayahId;
    $nama = trim((string) $nama);

    if ($wilayahId <= 0 || $nama === '') {
        return null;
    }

    $namaSql = komplain_escape($conn, $nama);
    $query = mysqli_query($conn, "SELECT id, nama FROM cluster WHERE wilayah_id = '{$wilayahId}' AND LOWER(nama) = LOWER('{$namaSql}') LIMIT 1");

    return $query ? mysqli_fetch_assoc($query) : null;
}

function komplain_find_or_create_wilayah($conn, $nama)
{
    $existing = komplain_find_wilayah_by_name($conn, $nama);

    if ($existing) {
        return $existing;
    }

    $namaSql = komplain_escape($conn, $nama);
    mysqli_query($conn, "INSERT INTO wilayah (nama) VALUES ('{$namaSql}')");

    return [
        'id' => mysqli_insert_id($conn),
        'nama' => trim((string) $nama),
    ];
}

function komplain_find_or_create_cluster($conn, $wilayahId, $nama)
{
    $existing = komplain_find_cluster_by_name($conn, $wilayahId, $nama);

    if ($existing) {
        return $existing;
    }

    $wilayahId = (int) $wilayahId;
    $namaSql = komplain_escape($conn, $nama);
    mysqli_query($conn, "INSERT INTO cluster (wilayah_id, nama) VALUES ('{$wilayahId}', '{$namaSql}')");

    return [
        'id' => mysqli_insert_id($conn),
        'nama' => trim((string) $nama),
    ];
}

function komplain_image_files($value)
{
    $value = trim((string) $value);

    if ($value === '') {
        return [];
    }

    $decoded = json_decode($value, true);

    if (is_array($decoded)) {
        return array_values(array_filter(array_map('trim', $decoded)));
    }

    if (strpos($value, ',') !== false) {
        return array_values(array_filter(array_map('trim', explode(',', $value))));
    }

    return [$value];
}

function komplain_images_to_json(array $files)
{
    $clean = array_values(array_filter(array_map('trim', $files)));

    return empty($clean) ? '' : json_encode($clean);
}

function komplain_merge_images($existing, array $newFiles)
{
    return komplain_images_to_json(array_merge(komplain_image_files($existing), $newFiles));
}

function komplain_safe_uploaded_name($prefix, $originalName, $index = 0)
{
    $ext = strtolower(pathinfo((string) $originalName, PATHINFO_EXTENSION));
    $base = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo((string) $originalName, PATHINFO_FILENAME));
    $ext = $ext !== '' ? '.' . $ext : '';

    return $prefix . '_' . time() . '_' . $index . '_' . $base . $ext;
}

function komplain_upload_multiple_images($fieldName, $folder, $prefix)
{
    $saved = [];
    $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
    $maxSize = 10 * 1024 * 1024;

    if (empty($_FILES[$fieldName])) {
        return $saved;
    }

    if (!is_dir($folder)) {
        mkdir($folder, 0777, true);
    }

    $names = $_FILES[$fieldName]['name'];
    $tmpNames = $_FILES[$fieldName]['tmp_name'];
    $errors = $_FILES[$fieldName]['error'];
    $sizes = $_FILES[$fieldName]['size'];

    if (!is_array($names)) {
        $names = [$names];
        $tmpNames = [$tmpNames];
        $errors = [$errors];
        $sizes = [$sizes];
    }

    foreach ($names as $index => $name) {
        if ($name === '' || (int) $errors[$index] !== UPLOAD_ERR_OK) {
            continue;
        }

        $ext = strtolower(pathinfo((string) $name, PATHINFO_EXTENSION));

        if (!in_array($ext, $allowedExtensions, true)) {
            continue;
        }

        if (!empty($sizes[$index]) && (int) $sizes[$index] > $maxSize) {
            continue;
        }

        $filename = komplain_safe_uploaded_name($prefix, $name, $index);

        if (move_uploaded_file($tmpNames[$index], rtrim($folder, '/\\') . DIRECTORY_SEPARATOR . $filename)) {
            $saved[] = $filename;
        }
    }

    return $saved;
}

function komplain_save_base64_image($base64, $folder, $prefix)
{
    $base64 = trim((string) $base64);

    if ($base64 === '' || strpos($base64, 'data:image/') !== 0) {
        return '';
    }

    if (!preg_match('/^data:image\/(png|jpeg|jpg|webp);base64,/', $base64, $matches)) {
        return '';
    }

    $ext = $matches[1] === 'jpeg' ? 'jpg' : $matches[1];
    $data = base64_decode(substr($base64, strpos($base64, ',') + 1), true);

    if ($data === false) {
        return '';
    }

    if (!is_dir($folder)) {
        mkdir($folder, 0777, true);
    }

    $filename = komplain_safe_uploaded_name($prefix, 'kamera.' . $ext, 0);
    $target = rtrim($folder, '/\\') . DIRECTORY_SEPARATOR . $filename;

    return file_put_contents($target, $data) !== false ? $filename : '';
}

function komplain_parse_money($value)
{
    return (float) preg_replace('/[^0-9]/', '', (string) $value);
}

function komplain_user_profile($conn, $userId)
{
    $userId = (int) $userId;
    $query = mysqli_query($conn, "SELECT username, role, foto_profil FROM users WHERE id='{$userId}' LIMIT 1");
    $user = $query ? mysqli_fetch_assoc($query) : null;

    return $user ?: [
        'username' => $_SESSION['username'] ?? 'User',
        'role' => $_SESSION['role'] ?? '',
        'foto_profil' => '',
    ];
}

function komplain_profile_photo_url(array $user)
{
    if (!empty($user['foto_profil'])) {
        $path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'profil' . DIRECTORY_SEPARATOR . $user['foto_profil'];

        if (is_file($path)) {
            return '../uploads/profil/' . rawurlencode($user['foto_profil']);
        }
    }

    return 'https://cdn.jsdelivr.net/npm/admin-lte@3.2/dist/img/user2-160x160.jpg';
}

function komplain_reverse_geocode_label($lat, $lng)
{
    $lat = trim((string) $lat);
    $lng = trim((string) $lng);

    if ($lat === '' || $lng === '') {
        return '-';
    }

    static $cache = [];
    $cacheKey = $lat . '|' . $lng;

    if (isset($cache[$cacheKey])) {
        return $cache[$cacheKey];
    }

    $url = 'https://nominatim.openstreetmap.org/reverse?format=jsonv2&zoom=10&addressdetails=1&lat=' . rawurlencode($lat) . '&lon=' . rawurlencode($lng);
    $context = stream_context_create([
        'http' => [
            'timeout' => 4,
            'header' => "User-Agent: PT-Alvindo/1.0\r\nAccept: application/json\r\n",
        ],
    ]);
    $json = @file_get_contents($url, false, $context);
    $label = '';

    if ($json !== false && $json !== '') {
        $decoded = json_decode($json, true);
        if (is_array($decoded)) {
            $address = $decoded['address'] ?? [];
            $parts = [];
            foreach (['suburb', 'city_district', 'village', 'town', 'city', 'county', 'state'] as $key) {
                if (!empty($address[$key]) && !in_array($address[$key], $parts, true)) {
                    $parts[] = $address[$key];
                }
            }
            if (!empty($parts)) {
                $label = implode(', ', array_slice($parts, 0, 3));
            } elseif (!empty($decoded['display_name'])) {
                $label = trim((string) $decoded['display_name']);
            }
        }
    }

    if ($label === '') {
        $label = 'Lokasi terdeteksi';
    }

    $cache[$cacheKey] = $label;
    return $label;
}

function komplain_absensi_location_label(array $row)
{
    $stored = trim((string) komplain_row_value($row, 'lokasi_nama', ''));
    if ($stored !== '') {
        if (preg_match('/^-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?$/', $stored)) {
            [$lat, $lng] = array_map('trim', explode(',', $stored, 2));
            return komplain_reverse_geocode_label($lat, $lng);
        }

        if (stripos($stored, 'lokasi terdeteksi') === false) {
            return $stored;
        }
    }

    $lat = trim((string) komplain_row_value($row, 'latitude', ''));
    $lng = trim((string) komplain_row_value($row, 'longitude', ''));
    if ($lat === '' || $lng === '') {
        return $stored;
    }

    return komplain_reverse_geocode_label($lat, $lng);
}

function komplain_absensi_overtime_minutes(array $row)
{
    $start = trim((string) komplain_row_value($row, 'jam_lembur_mulai', ''));
    $end = trim((string) komplain_row_value($row, 'jam_lembur_selesai', ''));

    if ($start === '' || $end === '') {
        return 0;
    }

    $startTs = strtotime($start);
    $endTs = strtotime($end);

    if (!$startTs || !$endTs || $endTs <= $startTs) {
        return 0;
    }

    return min(24 * 60, (int) ceil(($endTs - $startTs) / 60));
}

function komplain_absensi_overtime_hours(array $row)
{
    return round(komplain_absensi_overtime_minutes($row) / 60, 2);
}

function komplain_absensi_overtime_rate(array $row, $defaultRate = 0)
{
    $rate = komplain_row_value($row, 'gaji_lembur_per_jam', null);

    return $rate !== null ? (float) $rate : (float) $defaultRate;
}

function komplain_absensi_overtime_subtotal(array $row, $ratePerHour = null)
{
    $rate = $ratePerHour === null ? komplain_absensi_overtime_rate($row) : (float) $ratePerHour;

    return komplain_absensi_overtime_hours($row) * $rate;
}

function komplain_absensi_overtime_label(array $row)
{
    $minutes = komplain_absensi_overtime_minutes($row);
    if ($minutes <= 0) {
        return '-';
    }

    $hours = intdiv($minutes, 60);
    $remaining = $minutes % 60;
    $parts = [];

    if ($hours > 0) {
        $parts[] = $hours . ' jam';
    }

    if ($remaining > 0) {
        $parts[] = $remaining . ' menit';
    }

    return implode(' ', $parts);
}

function komplain_absensi_overtime_amount(array $row, $ratePerHour)
{
    return komplain_absensi_overtime_subtotal($row, $ratePerHour);
}

function komplain_absensi_overtime_manual_total(array $row)
{
    foreach (['gaji_lembur_total', 'gaji_lembur_manual', 'lembur_total'] as $key) {
        $value = komplain_row_value($row, $key, null);
        if ($value !== null && $value !== '') {
            return (float) $value;
        }
    }

    return 0;
}

function komplain_absensi_payroll_overtime_amount(array $row)
{
    $manual = komplain_absensi_overtime_manual_total($row);
    if ($manual > 0) {
        return $manual;
    }

    $rate = komplain_absensi_overtime_rate($row);
    return komplain_absensi_overtime_subtotal($row, $rate);
}
function komplain_remove_image($value, $filename)
{
    $files = komplain_image_files($value);
    $filename = trim((string) $filename);

    if ($filename === '') {
        return komplain_images_to_json($files);
    }

    $files = array_values(array_filter($files, function ($file) use ($filename) {
        return basename((string) $file) !== $filename;
    }));

    return komplain_images_to_json($files);
}

function komplain_notify($conn, $roleTujuan, $judul, $pesan, $komplainId = null, $userId = null)
{
    $roleTujuan = trim(strtolower((string) $roleTujuan));
    $judulSql = komplain_escape($conn, $judul);
    $pesanSql = komplain_escape($conn, $pesan);
    $komplainIdSql = $komplainId !== null ? (int) $komplainId : 'NULL';
    $userIdSql = $userId !== null ? (int) $userId : 'NULL';

    if ($roleTujuan === '' || $judulSql === '' || $pesanSql === '') {
        return false;
    }

    return mysqli_query($conn, "
        INSERT INTO notifikasi (role_tujuan, user_id, komplain_id, judul, pesan, is_read, created_at)
        VALUES ('{$roleTujuan}', {$userIdSql}, {$komplainIdSql}, '{$judulSql}', '{$pesanSql}', 0, NOW())
    ");
}

function komplain_notify_roles($conn, array $roles, $judul, $pesan, $komplainId = null)
{
    $ok = true;

    foreach ($roles as $role) {
        $ok = komplain_notify($conn, $role, $judul, $pesan, $komplainId) && $ok;
    }

    return $ok;
}

function komplain_notification_count($conn, $role, $userId = null, $onlyUnread = true)
{
    $role = trim(strtolower((string) $role));
    $userIdSql = $userId !== null ? ' AND user_id = ' . (int) $userId : '';
    $readSql = $onlyUnread ? ' AND is_read = 0' : '';
    $query = mysqli_query($conn, "
        SELECT COUNT(*) AS jml
        FROM notifikasi
        WHERE role_tujuan = '" . komplain_escape($conn, $role) . "' {$userIdSql} {$readSql}
    ");

    $row = $query ? mysqli_fetch_assoc($query) : ['jml' => 0];
    return (int) ($row['jml'] ?? 0);
}

function komplain_recent_notifications($conn, $role, $limit = 5, $userId = null, $unreadOnly = false)
{
    $role = trim(strtolower((string) $role));
    $limit = max(1, (int) $limit);
    $userIdSql = $userId !== null ? ' AND user_id = ' . (int) $userId : '';
    $readSql = $unreadOnly ? ' AND is_read = 0' : '';
    $items = [];
    $query = mysqli_query($conn, "
        SELECT *
        FROM notifikasi
        WHERE role_tujuan = '" . komplain_escape($conn, $role) . "' {$userIdSql} {$readSql}
        ORDER BY created_at DESC, id DESC
        LIMIT {$limit}
    ");

    while ($query && ($row = mysqli_fetch_assoc($query))) {
        $items[] = $row;
    }

    return $items;
}

function komplain_mark_notifications_read($conn, $role, $userId = null)
{
    $role = trim(strtolower((string) $role));
    $userIdSql = $userId !== null ? ' AND user_id = ' . (int) $userId : '';

    return mysqli_query($conn, "
        UPDATE notifikasi
        SET is_read = 1,
            read_at = COALESCE(read_at, NOW())
        WHERE role_tujuan = '" . komplain_escape($conn, $role) . "'
        AND is_read = 0
          {$userIdSql}
    ");
}

function komplain_mark_notification_read_by_id($conn, $notificationId, $role, $userId = null)
{
    $notificationId = (int) $notificationId;
    if ($notificationId <= 0) {
        return false;
    }

    $role = trim(strtolower((string) $role));
    $userIdSql = $userId !== null ? ' AND user_id = ' . (int) $userId : '';

    return mysqli_query($conn, "
        UPDATE notifikasi
        SET is_read = 1,
            read_at = COALESCE(read_at, NOW())
        WHERE id = '{$notificationId}'
          AND role_tujuan = '" . komplain_escape($conn, $role) . "'
          {$userIdSql}
          AND is_read = 0
    ");
}

function komplain_notification_target_url(array $notif, $role)
{
    $komplainId = (int) ($notif['komplain_id'] ?? 0);
    $role = trim(strtolower((string) $role));

    if ($komplainId <= 0) {
        return '';
    }

    $notifId = (int) ($notif['id'] ?? 0);
    $notifParam = $notifId > 0 ? '&notif_id=' . $notifId : '';

    if ($role === 'admin') {
        return '../admin/detail_komplain.php?id=' . $komplainId . $notifParam;
    }

    if ($role === 'pelaksana') {
        return '../pelaksana/data_komplain.php?filter=total' . $notifParam . '#komplain-' . $komplainId;
    }

    if ($role === 'teknisi') {
        return '../teknisi/data_komplain.php?filter=total' . $notifParam . '#komplain-' . $komplainId;
    }

    return '';
}
