<?php

declare(strict_types=1);

if (defined('DENTAL_ROOT') && is_file(DENTAL_ROOT . '/app/treatment_flow.php')) { require_once DENTAL_ROOT . '/app/treatment_flow.php'; }

/**
 * First-time clinic setup and go-live readiness helpers.
 * These helpers are intentionally defensive because they are used during fresh
 * installs, resets, and partially updated databases.
 */

function dental_setup_safe_count(PDO $pdo, string $logicalTable, string $where = '1=1'): int
{
    try {
        $physical = table($logicalTable);
        if (!schema_table_exists($physical)) return 0;
        return (int) $pdo->query('SELECT COUNT(*) FROM `' . $physical . '` WHERE ' . $where)->fetchColumn();
    } catch (Throwable $exception) {
        error_log('DentalCare setup readiness count failed for ' . $logicalTable . ': ' . $exception->getMessage());
        return 0;
    }
}

function dental_setup_safe_setting(string $group, string $key, string $default = ''): string
{
    try {
        return trim((string) setting_get($group, $key, $default));
    } catch (Throwable) {
        return $default;
    }
}

function dental_setup_route_exists(string $route): bool
{
    try {
        $routesPath = DENTAL_ROOT . '/config/routes.php';
        if (!is_file($routesPath)) return false;
        $routes = require $routesPath;
        return is_array($routes) && isset($routes[$route]) && is_file((string) $routes[$route]);
    } catch (Throwable) {
        return false;
    }
}

function dental_setup_readiness_snapshot(?PDO $pdo = null): array
{
    $pdo ??= db();
    $clinic = function_exists('clinic_profile') ? clinic_profile() : (function_exists('public_clinic_profile') ? public_clinic_profile() : []);

    $branchCount = dental_setup_safe_count($pdo, 'branches');
    $openDayCount = dental_setup_safe_count($pdo, 'branch_operating_hours', 'is_open=1 AND open_time IS NOT NULL AND close_time IS NOT NULL');
    $chairCount = dental_setup_safe_count($pdo, 'clinic_chairs', 'status <> "inactive"');
    $serviceCount = dental_setup_safe_count($pdo, 'service_catalog', 'is_active=1');
    $pricedServiceCount = dental_setup_safe_count($pdo, 'service_catalog', 'is_active=1 AND (fee_status="no_charge" OR standard_fee IS NOT NULL)');
    $dentistAccounts = dental_setup_safe_count($pdo, 'users', 'role_id IN (SELECT id FROM `' . table('roles') . '` WHERE code="dentist")');
    $activeDentists = dental_setup_safe_count($pdo, 'dentist_profiles', 'profile_status="active"');
    $staffAccounts = schema_column_exists(table('users'), 'status') ? dental_setup_safe_count($pdo, 'users', 'status="active"') : dental_setup_safe_count($pdo, 'users');
    $demoAccounts = schema_column_exists(table('users'), 'is_demo') ? dental_setup_safe_count($pdo, 'users', 'is_demo=1 AND status="active"') : 0;
    $demoPatients = schema_column_exists(table('patients'), 'is_demo') ? dental_setup_safe_count($pdo, 'patients', 'is_demo=1 AND status="active"') : 0;
    $demoInventoryItems = dental_setup_safe_count($pdo, 'demo_record_registry', 'entity_type="inventory_item"');
    $demoSterilizationRecords = dental_setup_safe_count($pdo, 'demo_record_registry', 'entity_type IN ("sterilization_equipment","instrument_set","sterilization_batch","sterilization_batch_set","sterilization_batch_event")');
    $fullDemoReady = (string) setting_get('system','full_demo_clinic_dataset_ready','0') === '1';
    $cashierWindows = dental_setup_safe_count($pdo, 'cashier_windows', 'is_active=1');
    $templates = dental_setup_safe_count($pdo, 'email_templates', 'is_active=1');
    $smsTemplates = dental_setup_safe_count($pdo, 'sms_templates', 'is_active=1');
    $smsReady = function_exists('dental_sms_schema_ready') && dental_sms_schema_ready();
    $smsProvider = dental_setup_safe_setting('sms', 'provider', 'log');
    $smsEnabled = dental_setup_safe_setting('sms', 'enabled', '0') === '1';
    $smtpConfigured = dental_setup_safe_setting('email', 'from_email') !== '' || dental_setup_safe_setting('smtp', 'host') !== '' || dental_setup_safe_setting('mail', 'from_email') !== '';
    $portalReady = dental_setup_route_exists('patient-portal') && dental_setup_route_exists('appointment-new');
    $patientNumberingConfigured = (string) setting_get('system','patient_numbering_configured','0') === '1' || function_exists('dental_patient_numbering_settings');
    $qaReady = version_compare(installed_application_version(), '0.5.9.8.63', '>=')
        && (string) setting_get('system', 'release_package_runtime_guard_confirmed', '0') === '1';
    $backupCount = dental_setup_safe_count($pdo, 'backup_logs');
    $verifiedBackupCount = dental_setup_safe_count($pdo, 'backup_logs', 'verified_at IS NOT NULL');
    $permissionMatrixReviewed = dental_setup_safe_setting('system', 'permission_matrix_reviewed_at') !== '';
    $roleNavigationHardened = dental_setup_safe_setting('system', 'role_permission_navigation_hardening_v067_ready', '0') === '1';
    $updateLoopHealed = dental_setup_safe_setting('system', 'update_loop_self_healing_v068_ready', '0') === '1';
    $inventoryTreatmentReady = dental_setup_safe_setting('system', 'inventory_treatment_reconciliation_v068_ready', '0') === '1';
    $treatmentFlowReady = function_exists('treatment_flow_schema_ready') && treatment_flow_schema_ready() && dental_setup_safe_setting('system','treatment_flow_finalization_ready','0') === '1';

    $clinicIdentityReady = $branchCount > 0
        && trim((string)($clinic['name'] ?? '')) !== ''
        && (trim((string)($clinic['phone'] ?? '')) !== '' || trim((string)($clinic['public_email'] ?? $clinic['email'] ?? '')) !== '');

    $steps = [
        'clinic_profile' => [
            'number' => 1,
            'title' => 'Clinic profile',
            'description' => 'Clinic name, branch identity, contact details, and public identity are ready.',
            'ready' => $clinicIdentityReady,
            'href' => 'settings.php',
            'action' => 'Open Landing Page Editor',
            'facts' => ['Branches: ' . $branchCount, 'Clinic name: ' . (trim((string)($clinic['name'] ?? '')) !== '' ? 'set' : 'missing')],
        ],
        'operation_hours' => [
            'number' => 2,
            'title' => 'Operating days and hours',
            'description' => 'Clinic days, open/close times, and booking intervals are configured.',
            'ready' => $openDayCount > 0,
            'href' => 'operation_hours.php',
            'action' => 'Configure Hours',
            'facts' => ['Open day rules: ' . $openDayCount],
        ],
        'chairs_resources' => [
            'number' => 3,
            'title' => 'Chairs and resources',
            'description' => 'Dental chairs/resources are available for queue and treatment assignment.',
            'ready' => $chairCount > 0,
            'href' => 'chairs.php',
            'action' => 'Manage Chairs',
            'facts' => ['Active resources: ' . $chairCount],
        ],
        'services_pricing' => [
            'number' => 4,
            'title' => 'Services and pricing',
            'description' => 'Service catalog, duration, provider type, and fee/no-charge policy are configured.',
            'ready' => $serviceCount > 0 && $pricedServiceCount > 0,
            'href' => 'services.php',
            'action' => 'Manage Services',
            'facts' => ['Active services: ' . $serviceCount, 'Priced/no-charge services: ' . $pricedServiceCount],
        ],
        'dentist_profiles' => [
            'number' => 5,
            'title' => 'Dentist profiles',
            'description' => 'At least one Dentist account has an active verified Dentist professional record.',
            'ready' => $activeDentists > 0,
            'href' => 'doctor_profile.php',
            'action' => 'Create / Link Profile',
            'facts' => ['Dentist accounts: ' . $dentistAccounts, 'Active profiles: ' . $activeDentists],
        ],
        'staff_accounts' => [
            'number' => 6,
            'title' => 'Staff accounts',
            'description' => 'Operational users are present for front desk, clinical support, cashier, and admin work.',
            'ready' => $staffAccounts >= 2,
            'href' => 'staff.php',
            'action' => 'Manage Staff',
            'facts' => ['Active users: ' . $staffAccounts],
        ],
        'patient_numbering' => [
            'number' => 7,
            'title' => 'Patient numbering',
            'description' => 'Patient ID format and next counter are controlled before live registration.',
            'ready' => $patientNumberingConfigured,
            'href' => 'patient_numbering.php',
            'action' => 'Configure Numbering',
            'facts' => ['Numbering control: ' . ($patientNumberingConfigured ? 'available' : 'review required')],
        ],
        'cashier_windows' => [
            'number' => 8,
            'title' => 'Cashier windows',
            'description' => 'Cashier windows/register stations are ready for controlled payment sessions.',
            'ready' => $cashierWindows > 0,
            'href' => 'billing.php',
            'action' => 'Open Cashier/POS',
            'facts' => ['Active cashier windows: ' . $cashierWindows],
        ],
        'email_sms' => [
            'number' => 9,
            'title' => 'Email, SMS, and message templates',
            'description' => 'Sender configuration, SMS provider readiness, and protected patient/staff templates are ready for communication.',
            'ready' => $templates > 0 && $smsReady && $smsTemplates > 0,
            'href' => 'sms_settings.php',
            'action' => 'Review SMS / Templates',
            'facts' => ['Active email templates: ' . $templates, 'SMS templates: ' . $smsTemplates, 'SMS provider: ' . ($smsProvider !== '' ? $smsProvider : 'log'), 'SMTP/sender signal: ' . ($smtpConfigured ? 'configured' : 'review required')],
            'warn' => !$smtpConfigured || !$smsEnabled,
        ],
        'patient_portal' => [
            'number' => 10,
            'title' => 'Patient portal and public booking',
            'description' => 'Public appointment intake and patient portal routes are available.',
            'ready' => $portalReady,
            'href' => 'appointment-new.php',
            'action' => 'Open Public Intake',
            'facts' => ['Public intake route: ' . (dental_setup_route_exists('appointment-new') ? 'ready' : 'missing'), 'Patient portal route: ' . (dental_setup_route_exists('patient-portal') ? 'ready' : 'missing')],
        ],
        'demo_accounts' => [
            'number' => 11,
            'title' => 'Demo accounts for orientation',
            'description' => 'Fictional role accounts are available for client training without using real staff credentials.',
            'ready' => $demoAccounts >= 3,
            'href' => 'demo_accounts.php',
            'action' => 'Create Demo Accounts',
            'facts' => ['Active demo accounts: ' . $demoAccounts, 'Expected minimum for walkthrough: 3'],
            'warn' => $demoAccounts === 0,
        ],
        'demo_patients' => [
            'number' => 12,
            'title' => 'Demo patients for orientation',
            'description' => 'Fictional patient records and sample workflow entries are available so client screens are not empty during orientation.',
            'ready' => $demoPatients >= 3,
            'href' => 'demo_accounts.php',
            'action' => 'Create Demo Patients',
            'facts' => ['Active demo patients: ' . $demoPatients, 'Expected minimum for walkthrough: 3'],
            'warn' => $demoPatients === 0,
        ],
        'full_demo_dataset' => [
            'number' => 13,
            'title' => 'Full demo clinic dataset',
            'description' => 'Fictional clinic setup, services, chairs, inventory, sterilization, treatment, billing, and recall samples are ready for client walkthroughs.',
            'ready' => $fullDemoReady && $demoPatients >= 3 && $demoInventoryItems >= 3,
            'href' => 'demo_accounts.php',
            'action' => 'Create Full Demo Dataset',
            'facts' => ['Dataset marker: ' . ($fullDemoReady ? 'ready' : 'pending'), 'Demo inventory items: ' . $demoInventoryItems, 'Sterilization records: ' . $demoSterilizationRecords],
            'warn' => !$fullDemoReady,
        ],
        'backup_restore' => [
            'number' => 14,
            'title' => 'Backup and restore readiness',
            'description' => 'A protected backup exists and the restore procedure has been reviewed before go-live.',
            'ready' => $backupCount > 0,
            'href' => 'backup_restore.php',
            'action' => 'Open Backup Center',
            'facts' => ['Backups: ' . $backupCount, 'Verified backups: ' . $verifiedBackupCount, 'Restore test: ' . (dental_setup_safe_setting('system','restore_tested_at') !== '' ? 'recorded' : 'not recorded')],
            'warn' => $verifiedBackupCount === 0,
        ],
        'permission_matrix' => [
            'number' => 15,
            'title' => 'Permission Matrix reviewed',
            'description' => 'Role access, route coverage, visible navigation, direct URL blocking, and role-separation rules are reviewed before issuing accounts to clinic staff.',
            'ready' => $permissionMatrixReviewed && $roleNavigationHardened,
            'href' => 'permission_matrix.php',
            'action' => 'Review Permissions',
            'facts' => ['Review marker: ' . ($permissionMatrixReviewed ? 'recorded' : 'pending'), 'v0.6.7 guard: ' . ($roleNavigationHardened ? 'installed' : 'pending')],
            'warn' => !$permissionMatrixReviewed,
        ],
        'treatment_flow' => [
            'number' => 16,
            'title' => 'Doctor workspace treatment flow',
            'description' => 'Doctor dashboard and clinical workspace share the same visit status rail from queue through treatment, billing, and closure.',
            'ready' => $treatmentFlowReady,
            'href' => 'doctor_treatment.php',
            'action' => 'Review Treatment Flow',
            'facts' => ['Status helper: ' . ($treatmentFlowReady ? 'ready' : 'pending'), 'Installed version: ' . installed_application_version()],
            'warn' => !$treatmentFlowReady,
        ],
        'update_inventory_reconciliation' => [
            'number' => 17,
            'title' => 'Update chain and treatment inventory reconciliation',
            'description' => 'The latest update marker is applied and treatment usage has a visible stock/billing reconciliation guard.',
            'ready' => $updateLoopHealed && $inventoryTreatmentReady,
            'href' => 'system_setup.php?tab=updates',
            'action' => 'Review Updates',
            'facts' => ['Update self-healing: ' . ($updateLoopHealed ? 'installed' : 'pending'), 'Inventory treatment guard: ' . ($inventoryTreatmentReady ? 'installed' : 'pending')],
            'warn' => !$updateLoopHealed || !$inventoryTreatmentReady,
        ],
        'qa_release' => [
            'number' => 18,
            'title' => 'Final QA and release safety',
            'description' => 'Updates, QA Smoke Test, and release package safety are aligned.',
            'ready' => $qaReady,
            'href' => 'system_smoke_test.php',
            'action' => 'Run QA Smoke Test',
            'facts' => ['Installed version: ' . installed_application_version(), 'Release package guard: ' . ((string) setting_get('system','release_package_runtime_guard_confirmed','0') === '1' ? 'confirmed' : 'pending')],
        ],
    ];

    $complete = count(array_filter($steps, static fn(array $step): bool => !empty($step['ready'])));
    $total = count($steps);
    $percent = $total > 0 ? (int) round(($complete / $total) * 100) : 0;

    return [
        'steps' => $steps,
        'complete' => $complete,
        'total' => $total,
        'percent' => $percent,
        'clinic' => $clinic,
        'counts' => [
            'branches' => $branchCount,
            'open_day_rules' => $openDayCount,
            'chairs' => $chairCount,
            'services' => $serviceCount,
            'active_dentists' => $activeDentists,
            'staff_accounts' => $staffAccounts,
            'demo_accounts' => $demoAccounts,
            'demo_patients' => $demoPatients,
            'demo_inventory_items' => $demoInventoryItems,
            'demo_sterilization_records' => $demoSterilizationRecords,
            'full_demo_dataset_ready' => $fullDemoReady ? 1 : 0,
            'cashier_windows' => $cashierWindows,
            'backups' => $backupCount,
            'verified_backups' => $verifiedBackupCount,
            'permission_matrix_reviewed' => $permissionMatrixReviewed ? 1 : 0,
            'role_navigation_hardened_v067' => $roleNavigationHardened ? 1 : 0,
            'email_templates' => $templates,
            'sms_templates' => $smsTemplates,
            'sms_ready' => $smsReady ? 1 : 0,
        ],
    ];
}

function dental_setup_missing_titles(array $snapshot): array
{
    $missing = [];
    foreach ((array)($snapshot['steps'] ?? []) as $step) {
        if (empty($step['ready'])) $missing[] = (string)($step['title'] ?? 'Unnamed step');
    }
    return $missing;
}


function dental_setup_priority_missing_steps(array $snapshot, int $limit = 5): array
{
    $priority = [
        'clinic_profile' => 10,
        'operation_hours' => 20,
        'patient_numbering' => 25,
        'chairs_resources' => 30,
        'services_pricing' => 40,
        'dentist_profiles' => 50,
        'staff_accounts' => 60,
        'cashier_windows' => 70,
        'email_sms' => 80,
        'patient_portal' => 90,
        'demo_accounts' => 100,
        'demo_patients' => 110,
        'full_demo_dataset' => 120,
        'qa_release' => 130,
    ];
    $missing = [];
    foreach ((array)($snapshot['steps'] ?? []) as $key => $step) {
        if (!empty($step['ready'])) continue;
        $step['_key'] = (string)$key;
        $step['_priority'] = $priority[(string)$key] ?? 999;
        $missing[] = $step;
    }
    usort($missing, static function (array $a, array $b): int {
        $warnA = !empty($a['warn']) ? 1 : 0;
        $warnB = !empty($b['warn']) ? 1 : 0;
        if ($warnA !== $warnB) return $warnA <=> $warnB;
        return ((int)($a['_priority'] ?? 999)) <=> ((int)($b['_priority'] ?? 999));
    });
    return array_slice($missing, 0, max(1, $limit));
}

function dental_setup_grouped_steps(array $snapshot): array
{
    $steps = (array)($snapshot['steps'] ?? []);
    $definitions = [
        'foundation' => [
            'label' => 'Phase 1',
            'title' => 'Clinic foundation',
            'description' => 'Identity, operating hours, and patient-number controls.',
            'keys' => ['clinic_profile','operation_hours','patient_numbering'],
        ],
        'operations' => [
            'label' => 'Phase 2',
            'title' => 'Daily operations',
            'description' => 'Chairs, services, staff, dentist profiles, and cashier stations.',
            'keys' => ['chairs_resources','services_pricing','dentist_profiles','staff_accounts','cashier_windows'],
        ],
        'communication' => [
            'label' => 'Phase 3',
            'title' => 'Communication and portal',
            'description' => 'Email/SMS readiness and patient-facing booking access.',
            'keys' => ['email_sms','patient_portal'],
        ],
        'orientation' => [
            'label' => 'Phase 4',
            'title' => 'Demo and go-live',
            'description' => 'Demo accounts, demo patient data, sample workflow data, QA, and package safety.',
            'keys' => ['demo_accounts','demo_patients','full_demo_dataset','treatment_flow','qa_release'],
        ],
    ];
    $groups = [];
    foreach ($definitions as $groupKey => $definition) {
        $groupSteps = [];
        foreach ((array)$definition['keys'] as $key) {
            if (isset($steps[$key])) {
                $step = $steps[$key];
                $step['_key'] = $key;
                $groupSteps[] = $step;
            }
        }
        $total = count($groupSteps);
        $complete = count(array_filter($groupSteps, static fn(array $step): bool => !empty($step['ready'])));
        $warn = (bool) array_filter($groupSteps, static fn(array $step): bool => empty($step['ready']) && !empty($step['warn']));
        $groups[$groupKey] = [
            'label' => $definition['label'],
            'title' => $definition['title'],
            'description' => $definition['description'],
            'steps' => $groupSteps,
            'complete' => $complete,
            'total' => $total,
            'ready' => $total > 0 && $complete === $total,
            'warn' => $warn,
        ];
    }
    return $groups;
}
