<?php
require_once __DIR__ . '/../functions/security.php';

if (!function_exists('assetmanager_json_response')) {
    function assetmanager_json_response(array $payload): void
    {
        if (!headers_sent()) {
            header('Content-Type: application/json; charset=utf-8');
        }
        echo json_encode($payload);
        exit;
    }
}

if (!function_exists('assetmanager_e')) {
    function assetmanager_e($value): string
    {
        return htmlspecialchars((string)($value ?? ''), ENT_QUOTES, 'UTF-8');
    }
}

if (!function_exists('assetmanager_decode_json')) {
    function assetmanager_decode_json($json, array $fallback = []): array
    {
        if ($json === null || $json === '') {
            return $fallback;
        }

        $decoded = json_decode((string)$json, true);
        return is_array($decoded) ? $decoded : $fallback;
    }
}

if (!function_exists('assetmanager_encode_json')) {
    function assetmanager_encode_json(array $data): string
    {
        return json_encode($data, JSON_UNESCAPED_SLASHES);
    }
}

if (!function_exists('assetmanager_default_settings')) {
    function assetmanager_default_settings(): array
    {
        return [
            'enabled' => 0,
            'modules' => [
                'maintenance' => 1,
                'documents' => 1,
                'nfc' => 1,
                'fleet' => 0,
                'hire' => 0,
                'usage' => 0,
                'parts' => 0,
                'finance' => 0,
            ],
            'limits' => [
                'users' => 10,
                'local_assets' => 250,
                'storage_mb' => 1024,
            ],
            'branding' => [
                'tenant_logo' => 1,
                'client_logo' => 1,
                'primary' => '245781',
                'accent' => '54b4d3',
            ],
            'permissions' => [
                'include_enrep_assets' => 1,
                'client_add_assets' => 1,
                'client_archive_local_assets' => 1,
                'require_confirmations' => 1,
            ],
            'itemdetails_edit' => [
                'enabled' => 0,
                'fields' => [],
            ],
        ];
    }
}

if (!function_exists('assetmanager_table_exists')) {
    function assetmanager_table_exists(mysqli $con, string $table): bool
    {
        $table = preg_replace('/[^A-Za-z0-9_]/', '', $table);
        if ($table === '') {
            return false;
        }

        $stmt = $con->prepare("SELECT 1 FROM `{$table}` LIMIT 1");
        if (!$stmt) {
            return false;
        }

        $stmt->execute();
        $stmt->close();

        return true;
    }
}

if (!function_exists('assetmanager_schema_ready')) {
    function assetmanager_schema_ready(mysqli $con): bool
    {
        $status = assetmanager_schema_status($con);
        return empty($status['missing_required']);
    }
}

if (!function_exists('assetmanager_schema_tables')) {
    function assetmanager_schema_tables(): array
    {
        return [
            'assetmanager_client_settings',
            'assetmanager_users',
            'assetmanager_assets',
            'assetmanager_documents',
            'assetmanager_activity',
            'assetmanager_maintenance',
            'assetmanager_hire',
            'assetmanager_hire_pricing',
            'assetmanager_parts',
            'assetmanager_sequences',
        ];
    }
}

if (!function_exists('assetmanager_schema_status')) {
    function assetmanager_schema_status(mysqli $con): array
    {
        $required = assetmanager_schema_tables();
        $installed = [];
        $missingRequired = [];

        foreach ($required as $table) {
            if (assetmanager_table_exists($con, $table)) {
                $installed[] = $table;
            } else {
                $missingRequired[] = $table;
            }
        }

        return [
            'ready' => empty($missingRequired),
            'required' => $required,
            'installed' => $installed,
            'missing_required' => $missingRequired,
        ];
    }
}

if (!function_exists('assetmanager_request_json_array')) {
    function assetmanager_request_json_array(string $key, int $maxLength = 20000): array
    {
        $raw = enrep_request_string($key, '', $maxLength);
        if ($raw === '') {
            return [];
        }

        $decoded = json_decode($raw, true);
        return is_array($decoded) ? $decoded : [];
    }
}

if (!function_exists('assetmanager_parse_datetime')) {
    function assetmanager_parse_datetime(string $value, bool $dateOnly = false): ?string
    {
        $value = trim($value);
        if ($value === '') {
            return null;
        }

        $ts = strtotime(str_replace('/', '-', $value));
        if (!$ts) {
            return null;
        }

        return $dateOnly ? date('Y-m-d', $ts) : date('Y-m-d H:i:s', $ts);
    }
}

if (!function_exists('assetmanager_active_clients')) {
    function assetmanager_active_clients(mysqli $con): array
    {
        $clients = [];
        $stmt = $con->prepare("
            SELECT clientnumber, clientname
            FROM clientdetails
            WHERE statuslive='1'
            ORDER BY clientname ASC
        ");
        if (!$stmt) {
            return $clients;
        }

        $stmt->execute();
        $res = $stmt->get_result();
        while ($row = $res->fetch_assoc()) {
            $clients[] = [
                'clientnumber' => (int)($row['clientnumber'] ?? 0),
                'clientname' => (string)($row['clientname'] ?? ''),
            ];
        }
        $stmt->close();

        return $clients;
    }
}

if (!function_exists('assetmanager_require_user')) {
    function assetmanager_require_user(): void
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        if ((int)($_SESSION['assetmanagerOperatorId'] ?? 0) > 0 && (int)($_SESSION['assetmanagerClientnumber'] ?? 0) > 0) {
            return;
        }

        if ((string)($_SESSION['usertype'] ?? '') !== '' && (int)($_SESSION['access'] ?? 0) >= 1) {
            return;
        }

        if ((int)($_SESSION['clientUniquePortal'] ?? 0) > 0 && (int)($_SESSION['clientPortalUserId'] ?? 0) > 0) {
            return;
        }

        enrep_fail(403, 'Forbidden');
    }
}

if (!function_exists('assetmanager_actor_user_id')) {
    function assetmanager_actor_user_id(): int
    {
        if ((int)($_SESSION['clientPortalUserId'] ?? 0) > 0) {
            return (int)$_SESSION['clientPortalUserId'];
        }

        if ((int)($_SESSION['assetmanagerOperatorId'] ?? 0) > 0) {
            return (int)$_SESSION['assetmanagerOperatorId'];
        }

        return (int)($_SESSION['userid'] ?? 0);
    }
}

if (!function_exists('assetmanager_access_scope')) {
    function assetmanager_access_scope(mysqli $con): array
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $assetManagerClient = (int)($_SESSION['assetmanagerClientnumber'] ?? 0);
        if ($assetManagerClient > 0 && (int)($_SESSION['assetmanagerOperatorId'] ?? 0) > 0) {
            return [
                'all_clients' => false,
                'clientnumbers' => [$assetManagerClient],
                'all_sites' => true,
                'site_numbers' => [],
                'portal' => false,
                'assetmanager_operator' => true,
            ];
        }

        $portalClient = (int)($_SESSION['clientUniquePortal'] ?? 0);
        if ($portalClient > 0 && (int)($_SESSION['clientPortalUserId'] ?? 0) > 0) {
            $accessAllSites = !empty($_SESSION['access_all']);
            $sites = [];
            if (!$accessAllSites && !empty($_SESSION['access_sites'])) {
                $decoded = is_array($_SESSION['access_sites']) ? $_SESSION['access_sites'] : json_decode((string)$_SESSION['access_sites'], true);
                if (is_array($decoded)) {
                    foreach ($decoded as $siteId) {
                        $siteId = (int)$siteId;
                        if ($siteId > 0 && !in_array($siteId, $sites, true)) {
                            $sites[] = $siteId;
                        }
                    }
                }
            }

            return [
                'all_clients' => false,
                'clientnumbers' => [$portalClient],
                'all_sites' => $accessAllSites,
                'site_numbers' => $sites,
                'portal' => true,
                'assetmanager_operator' => false,
            ];
        }

        if ((string)($_SESSION['usertype'] ?? '') === 'admins' && (int)($_SESSION['access'] ?? 0) >= 1) {
            $accessLevel = (int)($_SESSION['access'] ?? 0);
            if ($accessLevel > 1) {
                return [
                    'all_clients' => true,
                    'clientnumbers' => [],
                    'all_sites' => true,
                    'site_numbers' => [],
                    'portal' => false,
                    'assetmanager_operator' => false,
                ];
            }

            $adminId = (int)($_SESSION['userid'] ?? 0);
            $clients = [];
            if ($adminId > 0) {
                $stmt = $con->prepare("SELECT clientnumbers FROM admin_access WHERE admin_id=? LIMIT 1");
                if ($stmt) {
                    $stmt->bind_param('i', $adminId);
                    $stmt->execute();
                    $row = $stmt->get_result()->fetch_assoc();
                    $stmt->close();
                    $decoded = json_decode((string)($row['clientnumbers'] ?? '[]'), true);
                    if (is_array($decoded)) {
                        foreach ($decoded as $clientnumber) {
                            $clientnumber = (int)$clientnumber;
                            if ($clientnumber > 0 && !in_array($clientnumber, $clients, true)) {
                                $clients[] = $clientnumber;
                            }
                        }
                    }
                }
            }

            return [
                'all_clients' => false,
                'clientnumbers' => $clients,
                'all_sites' => true,
                'site_numbers' => [],
                'portal' => false,
                'assetmanager_operator' => false,
            ];
        }

        return [
            'all_clients' => false,
            'clientnumbers' => [],
            'all_sites' => false,
            'site_numbers' => [],
            'portal' => false,
            'assetmanager_operator' => false,
        ];
    }
}

if (!function_exists('assetmanager_operator_list')) {
    function assetmanager_operator_list(mysqli $con, string $tenantKey, int $clientnumber): array
    {
        if ($clientnumber <= 0 || !assetmanager_table_exists($con, 'assetmanager_users')) {
            return [];
        }

        $operators = [];
        $stmt = $con->prepare("
            SELECT id, name, email, status_key, role_key, last_login_at, created_at
            FROM assetmanager_users
            WHERE tenant_key=? AND clientnumber=?
            ORDER BY status_key ASC, name ASC
        ");
        if (!$stmt) {
            return [];
        }

        $stmt->bind_param('si', $tenantKey, $clientnumber);
        $stmt->execute();
        $res = $stmt->get_result();
        while ($row = $res->fetch_assoc()) {
            $operators[] = $row;
        }
        $stmt->close();

        return $operators;
    }
}

if (!function_exists('assetmanager_user_can_access_client')) {
    function assetmanager_user_can_access_client(mysqli $con, int $clientnumber): bool
    {
        if ($clientnumber <= 0) {
            return false;
        }

        $scope = assetmanager_access_scope($con);
        return !empty($scope['all_clients']) || in_array($clientnumber, $scope['clientnumbers'], true);
    }
}

if (!function_exists('assetmanager_filter_clients_by_access')) {
    function assetmanager_filter_clients_by_access(mysqli $con, array $clients): array
    {
        $scope = assetmanager_access_scope($con);
        if (!empty($scope['all_clients'])) {
            return $clients;
        }

        $allowed = $scope['clientnumbers'];
        return array_values(array_filter($clients, function ($client) use ($allowed) {
            return in_array((int)($client['clientnumber'] ?? 0), $allowed, true);
        }));
    }
}

if (!function_exists('assetmanager_client_site_filter_sql')) {
    function assetmanager_client_site_filter_sql(mysqli $con, int $clientnumber, string $column = 'a.locnumber'): array
    {
        $scope = assetmanager_access_scope($con);
        if (empty($scope['portal']) || !empty($scope['all_sites'])) {
            return ['', '', []];
        }

        if (!assetmanager_user_can_access_client($con, $clientnumber)) {
            return [' AND 1=0', '', []];
        }

        $sites = $scope['site_numbers'];
        if (count($sites) < 1) {
            return [' AND 1=0', '', []];
        }

        $placeholders = implode(',', array_fill(0, count($sites), '?'));
        return [' AND ' . $column . ' IN (' . $placeholders . ')', str_repeat('i', count($sites)), $sites];
    }
}

if (!function_exists('assetmanager_user_can_access_asset')) {
    function assetmanager_user_can_access_asset(mysqli $con, string $tenantKey, int $clientnumber, string $source, int $sourceId): bool
    {
        if (!assetmanager_user_can_access_client($con, $clientnumber)) {
            return false;
        }

        if ($source === 'assetmanager_item') {
            $stmt = $con->prepare("SELECT id FROM assetmanager_assets WHERE id=? AND tenant_key=? AND clientnumber=? AND archived='0' LIMIT 1");
            if (!$stmt) {
                return false;
            }
            $stmt->bind_param('isi', $sourceId, $tenantKey, $clientnumber);
            $stmt->execute();
            $row = $stmt->get_result()->fetch_assoc();
            $stmt->close();
            return !empty($row['id']);
        }

        if ($source !== 'enrep_item' || !assetmanager_enrep_assets_enabled($con, $tenantKey, $clientnumber)) {
            return false;
        }

        [$siteSql, $siteTypes, $siteParams] = assetmanager_client_site_filter_sql($con, $clientnumber, 'locnumber');
        $stmt = $con->prepare("SELECT itemnumber FROM itemdetails WHERE clientnumber=? AND itemnumber=? AND statuslive='1'{$siteSql} LIMIT 1");
        if (!$stmt) {
            return false;
        }
        $types = 'ii' . $siteTypes;
        $params = array_merge([$clientnumber, $sourceId], $siteParams);
        $stmt->bind_param($types, ...$params);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        return !empty($row['itemnumber']);
    }
}

if (!function_exists('assetmanager_json_require_client_access')) {
    function assetmanager_json_require_client_access(mysqli $con, int $clientnumber): void
    {
        if (!assetmanager_user_can_access_client($con, $clientnumber)) {
            assetmanager_json_response(['success' => false, 'message' => 'You do not have access to this client.']);
        }
    }
}

if (!function_exists('assetmanager_json_require_asset_access')) {
    function assetmanager_json_require_asset_access(mysqli $con, string $tenantKey, int $clientnumber, string $source, int $sourceId): void
    {
        if (!assetmanager_user_can_access_asset($con, $tenantKey, $clientnumber, $source, $sourceId)) {
            assetmanager_json_response(['success' => false, 'message' => 'You do not have access to this asset.']);
        }
    }
}

if (!function_exists('assetmanager_client_settings_map')) {
    function assetmanager_client_settings_map(mysqli $con, string $tenantKey): array
    {
        if (!assetmanager_table_exists($con, 'assetmanager_client_settings')) {
            return [];
        }

        $settings = [];
        $stmt = $con->prepare("
            SELECT clientnumber, enabled, modules_json, limits_json, branding_json, permissions_json, itemdetails_edit_json
            FROM assetmanager_client_settings
            WHERE tenant_key=?
        ");
        if (!$stmt) {
            return $settings;
        }

        $stmt->bind_param('s', $tenantKey);
        $stmt->execute();
        $res = $stmt->get_result();
        while ($row = $res->fetch_assoc()) {
            $clientnumber = (int)($row['clientnumber'] ?? 0);
            $settings[$clientnumber] = [
                'enabled' => (int)($row['enabled'] ?? 0),
                'modules' => assetmanager_decode_json($row['modules_json'] ?? ''),
                'limits' => assetmanager_decode_json($row['limits_json'] ?? ''),
                'branding' => assetmanager_decode_json($row['branding_json'] ?? ''),
                'permissions' => assetmanager_decode_json($row['permissions_json'] ?? ''),
                'itemdetails_edit' => assetmanager_decode_json($row['itemdetails_edit_json'] ?? ''),
            ];
        }
        $stmt->close();

        return $settings;
    }
}

if (!function_exists('assetmanager_merge_settings')) {
    function assetmanager_merge_settings(array $saved): array
    {
        $defaults = assetmanager_default_settings();
        foreach (['modules', 'limits', 'branding', 'permissions', 'itemdetails_edit'] as $key) {
            $saved[$key] = array_merge($defaults[$key], is_array($saved[$key] ?? null) ? $saved[$key] : []);
        }
        $saved['enabled'] = !empty($saved['enabled']) ? 1 : 0;

        return array_merge($defaults, $saved);
    }
}

if (!function_exists('assetmanager_format_sequence_ref')) {
    function assetmanager_format_sequence_ref(array $sequence): string
    {
        $prefix = substr(trim((string)($sequence['prefix'] ?? '')), 0, 40);
        $suffix = substr(trim((string)($sequence['suffix'] ?? '')), 0, 40);
        $number = max(1, (int)($sequence['next_number'] ?? 1));
        $padding = max(0, min(12, (int)($sequence['padding'] ?? 0)));
        $numberText = $padding > 0 ? str_pad((string)$number, $padding, '0', STR_PAD_LEFT) : (string)$number;
        return $prefix . $numberText . $suffix;
    }
}

if (!function_exists('assetmanager_default_sequences')) {
    function assetmanager_default_sequences(): array
    {
        return [
            'hire_agreement' => [
                'prefix' => 'HA-',
                'next_number' => 1,
                'padding' => 4,
                'suffix' => '',
            ],
            'hire_quote' => [
                'prefix' => 'HQ-',
                'next_number' => 1,
                'padding' => 4,
                'suffix' => '',
            ],
        ];
    }
}

if (!function_exists('assetmanager_normalise_sequence')) {
    function assetmanager_normalise_sequence(array $sequence, array $fallback): array
    {
        return [
            'prefix' => substr(trim((string)($sequence['prefix'] ?? $fallback['prefix'] ?? '')), 0, 40),
            'next_number' => max(1, (int)($sequence['next_number'] ?? $fallback['next_number'] ?? 1)),
            'padding' => max(0, min(12, (int)($sequence['padding'] ?? $fallback['padding'] ?? 0))),
            'suffix' => substr(trim((string)($sequence['suffix'] ?? $fallback['suffix'] ?? '')), 0, 40),
        ];
    }
}

if (!function_exists('assetmanager_get_client_sequences')) {
    function assetmanager_get_client_sequences(mysqli $con, string $tenantKey, int $clientnumber): array
    {
        $defaults = assetmanager_default_sequences();
        if ($clientnumber <= 0 || !assetmanager_table_exists($con, 'assetmanager_sequences')) {
            return $defaults;
        }

        $sequences = $defaults;
        $stmt = $con->prepare("
            SELECT sequence_key, prefix, next_number, padding, suffix
            FROM assetmanager_sequences
            WHERE tenant_key=? AND clientnumber=?
        ");
        if (!$stmt) {
            return $sequences;
        }

        $stmt->bind_param('si', $tenantKey, $clientnumber);
        $stmt->execute();
        $res = $stmt->get_result();
        while ($row = $res->fetch_assoc()) {
            $key = (string)($row['sequence_key'] ?? '');
            if (!isset($defaults[$key])) {
                continue;
            }
            $sequences[$key] = assetmanager_normalise_sequence($row, $defaults[$key]);
        }
        $stmt->close();

        return $sequences;
    }
}

if (!function_exists('assetmanager_save_client_sequences')) {
    function assetmanager_save_client_sequences(mysqli $con, string $tenantKey, int $clientnumber, array $sequences): bool
    {
        if ($clientnumber <= 0 || !assetmanager_table_exists($con, 'assetmanager_sequences')) {
            return false;
        }

        $defaults = assetmanager_default_sequences();
        $now = date('Y-m-d H:i:s');
        $stmt = $con->prepare("
            INSERT INTO assetmanager_sequences
                (tenant_key, clientnumber, sequence_key, prefix, next_number, padding, suffix, created_at, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE
                prefix=VALUES(prefix),
                next_number=VALUES(next_number),
                padding=VALUES(padding),
                suffix=VALUES(suffix),
                updated_at=VALUES(updated_at)
        ");
        if (!$stmt) {
            return false;
        }

        $ok = true;
        foreach ($defaults as $key => $fallback) {
            $sequence = assetmanager_normalise_sequence(is_array($sequences[$key] ?? null) ? $sequences[$key] : [], $fallback);
            $stmt->bind_param(
                'sissiisss',
                $tenantKey,
                $clientnumber,
                $key,
                $sequence['prefix'],
                $sequence['next_number'],
                $sequence['padding'],
                $sequence['suffix'],
                $now,
                $now
            );
            if (!$stmt->execute()) {
                $ok = false;
                break;
            }
        }
        $stmt->close();

        return $ok;
    }
}

if (!function_exists('assetmanager_next_client_sequence_ref')) {
    function assetmanager_next_client_sequence_ref(mysqli $con, string $tenantKey, int $clientnumber, string $sequenceKey): string
    {
        $defaults = assetmanager_default_sequences();
        if ($clientnumber <= 0 || !isset($defaults[$sequenceKey]) || !assetmanager_table_exists($con, 'assetmanager_sequences')) {
            return '';
        }

        $defaultSequence = $defaults[$sequenceKey];

        $startedTransaction = false;
        try {
            if (method_exists($con, 'begin_transaction')) {
                $con->begin_transaction();
                $startedTransaction = true;
            } else {
                $con->query('START TRANSACTION');
                $startedTransaction = true;
            }

            $stmt = $con->prepare("
                SELECT prefix, next_number, padding, suffix
                FROM assetmanager_sequences
                WHERE tenant_key=? AND clientnumber=? AND sequence_key=?
                LIMIT 1
                FOR UPDATE
            ");
            if (!$stmt) {
                throw new RuntimeException('Sequence settings could not be locked.');
            }
            $stmt->bind_param('sis', $tenantKey, $clientnumber, $sequenceKey);
            $stmt->execute();
            $row = $stmt->get_result()->fetch_assoc();
            $stmt->close();
            if (!$row) {
                if (!assetmanager_save_client_sequences($con, $tenantKey, $clientnumber, [$sequenceKey => $defaultSequence])) {
                    throw new RuntimeException('Client sequence settings are not configured.');
                }
                $row = $defaultSequence;
            }

            $sequence = assetmanager_normalise_sequence($row, $defaultSequence);
            $ref = assetmanager_format_sequence_ref($sequence);
            $nextNumber = $sequence['next_number'] + 1;
            $now = date('Y-m-d H:i:s');

            $update = $con->prepare("
                UPDATE assetmanager_sequences
                SET next_number=?, updated_at=?
                WHERE tenant_key=? AND clientnumber=? AND sequence_key=?
            ");
            if (!$update) {
                throw new RuntimeException('Sequence settings could not be updated.');
            }
            $update->bind_param('issis', $nextNumber, $now, $tenantKey, $clientnumber, $sequenceKey);
            $update->execute();
            $update->close();

            if ($startedTransaction) {
                $con->commit();
            }
            return $ref;
        } catch (Throwable $e) {
            if ($startedTransaction) {
                $con->rollback();
            }
            return '';
        }
    }
}

if (!function_exists('assetmanager_get_client_settings')) {
    function assetmanager_get_client_settings(mysqli $con, string $tenantKey, int $clientnumber): array
    {
        if ($clientnumber <= 0 || !assetmanager_table_exists($con, 'assetmanager_client_settings')) {
            return assetmanager_default_settings();
        }

        $stmt = $con->prepare("
            SELECT enabled, modules_json, limits_json, branding_json, permissions_json, itemdetails_edit_json
            FROM assetmanager_client_settings
            WHERE tenant_key=? AND clientnumber=?
            LIMIT 1
        ");
        if (!$stmt) {
            return assetmanager_default_settings();
        }

        $stmt->bind_param('si', $tenantKey, $clientnumber);
        $stmt->execute();
        $row = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if (!$row) {
            return assetmanager_default_settings();
        }

        return assetmanager_merge_settings([
            'enabled' => (int)($row['enabled'] ?? 0),
            'modules' => assetmanager_decode_json($row['modules_json'] ?? ''),
            'limits' => assetmanager_decode_json($row['limits_json'] ?? ''),
            'branding' => assetmanager_decode_json($row['branding_json'] ?? ''),
            'permissions' => assetmanager_decode_json($row['permissions_json'] ?? ''),
            'itemdetails_edit' => assetmanager_decode_json($row['itemdetails_edit_json'] ?? ''),
        ]);
    }
}

if (!function_exists('assetmanager_client_enabled')) {
    function assetmanager_client_enabled(mysqli $con, string $tenantKey, int $clientnumber): bool
    {
        $settings = assetmanager_get_client_settings($con, $tenantKey, $clientnumber);
        return !empty($settings['enabled']);
    }
}

if (!function_exists('assetmanager_module_enabled')) {
    function assetmanager_module_enabled(mysqli $con, string $tenantKey, int $clientnumber, string $module): bool
    {
        $settings = assetmanager_get_client_settings($con, $tenantKey, $clientnumber);
        return !empty($settings['enabled']) && !empty($settings['modules'][$module]);
    }
}

if (!function_exists('assetmanager_permission_enabled')) {
    function assetmanager_permission_enabled(mysqli $con, string $tenantKey, int $clientnumber, string $permission): bool
    {
        $settings = assetmanager_get_client_settings($con, $tenantKey, $clientnumber);
        return !empty($settings['enabled']) && !empty($settings['permissions'][$permission]);
    }
}

if (!function_exists('assetmanager_enrep_assets_enabled')) {
    function assetmanager_enrep_assets_enabled(mysqli $con, string $tenantKey, int $clientnumber): bool
    {
        return assetmanager_permission_enabled($con, $tenantKey, $clientnumber, 'include_enrep_assets');
    }
}

if (!function_exists('assetmanager_json_require_client_enabled')) {
    function assetmanager_json_require_client_enabled(mysqli $con, string $tenantKey, int $clientnumber): void
    {
        if (!assetmanager_client_enabled($con, $tenantKey, $clientnumber)) {
            assetmanager_json_response(['success' => false, 'message' => 'Asset Manager is not enabled for this client.']);
        }
    }
}

if (!function_exists('assetmanager_json_require_module')) {
    function assetmanager_json_require_module(mysqli $con, string $tenantKey, int $clientnumber, string $module, string $label): void
    {
        if (!assetmanager_module_enabled($con, $tenantKey, $clientnumber, $module)) {
            assetmanager_json_response(['success' => false, 'message' => $label . ' is not enabled for this client.']);
        }
    }
}

if (!function_exists('assetmanager_json_require_permission')) {
    function assetmanager_json_require_permission(mysqli $con, string $tenantKey, int $clientnumber, string $permission, string $label): void
    {
        if (!assetmanager_permission_enabled($con, $tenantKey, $clientnumber, $permission)) {
            assetmanager_json_response(['success' => false, 'message' => $label . ' is not permitted for this client.']);
        }
    }
}

if (!function_exists('assetmanager_save_client_settings')) {
    function assetmanager_save_client_settings(mysqli $con, string $tenantKey, int $clientnumber, array $settings, int $userId = 0): bool
    {
        $GLOBALS['assetmanager_last_error'] = '';
        if (!assetmanager_table_exists($con, 'assetmanager_client_settings')) {
            $GLOBALS['assetmanager_last_error'] = 'assetmanager_client_settings table is not available.';
            return false;
        }

        $now = date('Y-m-d H:i:s');
        $enabled = !empty($settings['enabled']) ? 1 : 0;
        $modulesJson = assetmanager_encode_json($settings['modules'] ?? []);
        $limitsJson = assetmanager_encode_json($settings['limits'] ?? []);
        $brandingJson = assetmanager_encode_json($settings['branding'] ?? []);
        $permissionsJson = assetmanager_encode_json($settings['permissions'] ?? []);
        $itemdetailsEditJson = assetmanager_encode_json($settings['itemdetails_edit'] ?? []);

        $stmt = $con->prepare("
            INSERT INTO assetmanager_client_settings
                (tenant_key, clientnumber, enabled, modules_json, limits_json, branding_json, permissions_json, itemdetails_edit_json, created_at, updated_at)
            VALUES
                (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE
                enabled=VALUES(enabled),
                modules_json=VALUES(modules_json),
                limits_json=VALUES(limits_json),
                branding_json=VALUES(branding_json),
                permissions_json=VALUES(permissions_json),
                itemdetails_edit_json=VALUES(itemdetails_edit_json),
                updated_at=VALUES(updated_at)
        ");
        if (!$stmt) {
            $GLOBALS['assetmanager_last_error'] = $con->error ?: 'Client settings save statement could not be prepared.';
            return false;
        }

        $stmt->bind_param(
            'siisssssss',
            $tenantKey,
            $clientnumber,
            $enabled,
            $modulesJson,
            $limitsJson,
            $brandingJson,
            $permissionsJson,
            $itemdetailsEditJson,
            $now,
            $now
        );
        $ok = $stmt->execute();
        if (!$ok) {
            $GLOBALS['assetmanager_last_error'] = $stmt->error ?: 'Client settings save failed.';
        }
        $stmt->close();

        if ($ok) {
            assetmanager_audit($con, $tenantKey, $clientnumber, $userId, 'client_settings', $clientnumber, 'save', [], $settings);
        }

        return $ok;
    }
}

if (!function_exists('assetmanager_audit')) {
    function assetmanager_audit(mysqli $con, string $tenantKey, ?int $clientnumber, int $userId, string $entityType, ?int $entityId, string $action, array $before, array $after): void
    {
        if (!assetmanager_table_exists($con, 'assetmanager_activity')) {
            return;
        }

        $payload = [];
        if (!empty($before)) {
            $payload['before'] = $before;
        }
        if (!empty($after)) {
            $payload['after'] = $after;
        }
        $payloadJson = empty($payload) ? null : assetmanager_encode_json($payload);
        $now = date('Y-m-d H:i:s');
        $assetId = $entityType === 'asset' && $entityId !== null ? $entityId : null;
        $summary = ucfirst(str_replace('_', ' ', $action));
        $moduleKey = 'system';

        $stmt = $con->prepare("
            INSERT INTO assetmanager_activity
                (tenant_key, clientnumber, asset_id, module_key, parent_type, parent_id, activity_type, activity_at, summary, payload_json, created_by, created_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ");
        if (!$stmt) {
            return;
        }

        $stmt->bind_param(
            'siississssis',
            $tenantKey,
            $clientnumber,
            $assetId,
            $moduleKey,
            $entityType,
            $entityId,
            $action,
            $now,
            $summary,
            $payloadJson,
            $userId,
            $now
        );
        $stmt->execute();
        $stmt->close();
    }
}

if (!function_exists('assetmanager_resolve_asset_id')) {
    function assetmanager_resolve_asset_id(mysqli $con, string $tenantKey, int $clientnumber, string $source, int $sourceId, string $assetTitle = '', bool $create = false): int
    {
        if ($source === 'assetmanager_item') {
            $stmt = $con->prepare("SELECT id FROM assetmanager_assets WHERE id=? AND tenant_key=? AND clientnumber=? LIMIT 1");
            if (!$stmt) {
                return 0;
            }
            $stmt->bind_param('isi', $sourceId, $tenantKey, $clientnumber);
            $stmt->execute();
            $row = $stmt->get_result()->fetch_assoc();
            $stmt->close();
            return (int)($row['id'] ?? 0);
        }

        if ($source !== 'enrep_item' || !assetmanager_enrep_assets_enabled($con, $tenantKey, $clientnumber)) {
            return 0;
        }

        $stmt = $con->prepare("SELECT id FROM assetmanager_assets WHERE tenant_key=? AND clientnumber=? AND source_type='enrep_item' AND source_itemnumber=? LIMIT 1");
        if ($stmt) {
            $stmt->bind_param('sii', $tenantKey, $clientnumber, $sourceId);
            $stmt->execute();
            $row = $stmt->get_result()->fetch_assoc();
            $stmt->close();
            if (!empty($row['id'])) {
                return (int)$row['id'];
            }
        }

        if (!$create) {
            return 0;
        }

        if ($assetTitle === '') {
            $assetTitle = 'EnRep item ' . $sourceId;
        }

        $now = date('Y-m-d H:i:s');
        $sourceType = 'enrep_item';
        $category = 'enrep';
        $status = 'active';
        $coreJson = assetmanager_encode_json([]);
        $customJson = assetmanager_encode_json([]);
        $moduleJson = assetmanager_encode_json([]);
        $archived = 0;
        $userId = assetmanager_actor_user_id();

        $stmt = $con->prepare("
            INSERT INTO assetmanager_assets
                (tenant_key, clientnumber, source_type, source_itemnumber, category_key, asset_title, status_key, core_fields_json, custom_fields_json, module_data_json, archived, created_by, created_at, updated_at)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), updated_at=VALUES(updated_at)
        ");
        if (!$stmt) {
            return 0;
        }
        $stmt->bind_param(
            'sisissssssisss',
            $tenantKey,
            $clientnumber,
            $sourceType,
            $sourceId,
            $category,
            $assetTitle,
            $status,
            $coreJson,
            $customJson,
            $moduleJson,
            $archived,
            $userId,
            $now,
            $now
        );
        $ok = $stmt->execute();
        $assetId = $ok ? (int)$stmt->insert_id : 0;
        $stmt->close();

        return $assetId;
    }
}

if (!function_exists('assetmanager_format_date')) {
    function assetmanager_format_date($value): string
    {
        $value = trim((string)($value ?? ''));
        if ($value === '') {
            return '';
        }
        if (ctype_digit($value)) {
            return date('d-m-Y', (int)$value);
        }
        $ts = strtotime($value);
        return $ts ? date('d-m-Y', $ts) : $value;
    }
}
