<?php
require_once __DIR__ . '/Includes.php';
require_once __DIR__ . '/pos_core.php';
pos_ensure_schema($pdo);

$sessionRole = (string)($_SESSION['role'] ?? '');
$isAdminReadOnlyView = $sessionRole === 'admin' && (string)($_GET['admin_view'] ?? '') === '1';
if ($sessionRole === 'admin' && !$isAdminReadOnlyView) {
  header('Location: admin.php');
  exit;
}
check_login(['accountant', 'admin']);

$pdo->exec("CREATE TABLE IF NOT EXISTS classes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(150) NOT NULL UNIQUE,
  password_hash VARCHAR(255) NOT NULL,
  role ENUM('admin', 'teacher', 'hop', 'accountant', 'ancillary', 'parent') NOT NULL DEFAULT 'teacher',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");

try {
  $pdo->exec("ALTER TABLE users MODIFY role ENUM('admin', 'teacher', 'hop', 'accountant', 'ancillary', 'parent') NOT NULL DEFAULT 'teacher'");
} catch (PDOException $e) {
  // Ignore when schema is already updated.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS staff_profiles (
  user_id INT NOT NULL PRIMARY KEY,
  sex ENUM('Male','Female','Other') NULL,
  date_of_birth DATE NULL,
  ec_number VARCHAR(80) NULL,
  national_id VARCHAR(80) NULL,
  work_profile VARCHAR(255) NULL,
  qualifications TEXT NULL,
  subject_specialization VARCHAR(255) NULL,
  updated_by INT NULL,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_staff_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_staff_profiles_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS learners (
  reg_number VARCHAR(30) NOT NULL PRIMARY KEY,
  id INT NOT NULL AUTO_INCREMENT UNIQUE,
  class_id INT NOT NULL,
  date_of_admission DATE NULL,
  surname VARCHAR(100) NULL,
  christian_names VARCHAR(150) NULL,
  full_name VARCHAR(150) NOT NULL,
  date_of_birth_info VARCHAR(40) NULL,
  birth_certificate_number VARCHAR(80) NULL,
  religious_denomination VARCHAR(120) NULL,
  gender ENUM('Male', 'Female', 'Other') NOT NULL DEFAULT 'Other',
  guardian_name VARCHAR(120) NULL,
  guardian_national_id VARCHAR(60) NULL,
  guardian_address VARCHAR(255) NULL,
  guardian_phone VARCHAR(40) NULL,
  student_photo_path VARCHAR(255) NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_learners_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS fee_invoices (
  id INT AUTO_INCREMENT PRIMARY KEY,
  invoice_number VARCHAR(40) NOT NULL UNIQUE,
  learner_id INT NOT NULL,
  class_id INT NOT NULL,
  description VARCHAR(255) NOT NULL,
  amount_due DECIMAL(10,2) NOT NULL,
  fee_gpf DECIMAL(10,2) NOT NULL DEFAULT 0,
  fee_ssf DECIMAL(10,2) NOT NULL DEFAULT 0,
  fee_sdc DECIMAL(10,2) NOT NULL DEFAULT 0,
  fee_registration DECIMAL(10,2) NOT NULL DEFAULT 0,
  fee_zimsec DECIMAL(10,2) NOT NULL DEFAULT 0,
  due_date DATE NULL,
  status ENUM('unpaid', 'partially_paid', 'paid') NOT NULL DEFAULT 'unpaid',
  created_by INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_fee_invoices_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  CONSTRAINT fk_fee_invoices_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_fee_invoices_user FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE,
  INDEX idx_fee_invoices_learner (learner_id),
  INDEX idx_fee_invoices_status (status),
  INDEX idx_fee_invoices_due (due_date)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS fee_payments (
  id INT AUTO_INCREMENT PRIMARY KEY,
  invoice_id INT NULL,
  learner_id INT NOT NULL,
  amount_paid DECIMAL(10,2) NOT NULL,
  currency_code ENUM('USD','ZIG','RAND') NOT NULL DEFAULT 'USD',
  fx_rate_to_usd DECIMAL(18,8) NOT NULL DEFAULT 1,
  amount_paid_usd DECIMAL(12,2) NOT NULL DEFAULT 0,
  payment_date DATE NOT NULL,
  fee_component VARCHAR(10) NOT NULL DEFAULT 'GPF',
  payment_method ENUM('cash','ecocash','bank_transfer','pos','other') NOT NULL DEFAULT 'cash',
  reference_no VARCHAR(80) NULL,
  note VARCHAR(255) NULL,
  received_by INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_fee_payments_invoice FOREIGN KEY (invoice_id) REFERENCES fee_invoices(id) ON DELETE SET NULL,
  CONSTRAINT fk_fee_payments_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  CONSTRAINT fk_fee_payments_user FOREIGN KEY (received_by) REFERENCES users(id) ON DELETE CASCADE,
  INDEX idx_fee_payments_learner_date (learner_id, payment_date),
  INDEX idx_fee_payments_invoice (invoice_id)
)");

$invoiceColumnsToEnsure = [
  "fee_gpf DECIMAL(10,2) NOT NULL DEFAULT 0",
  "fee_ssf DECIMAL(10,2) NOT NULL DEFAULT 0",
  "fee_sdc DECIMAL(10,2) NOT NULL DEFAULT 0",
  "fee_registration DECIMAL(10,2) NOT NULL DEFAULT 0",
  "fee_zimsec DECIMAL(10,2) NOT NULL DEFAULT 0"
];
foreach ($invoiceColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE fee_invoices ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors for idempotent upgrades.
  }
}

$paymentColumnsToEnsure = [
  "currency_code ENUM('USD','ZIG','RAND') NOT NULL DEFAULT 'USD'",
  "fx_rate_to_usd DECIMAL(18,8) NOT NULL DEFAULT 1",
  "amount_paid_usd DECIMAL(12,2) NOT NULL DEFAULT 0",
  "fee_component VARCHAR(10) NOT NULL DEFAULT 'GPF'"
];
foreach ($paymentColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE fee_payments ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors for idempotent upgrades.
  }
}

try {
  $pdo->exec("UPDATE fee_payments
    SET amount_paid_usd = ROUND(amount_paid * COALESCE(NULLIF(fx_rate_to_usd, 0), 1), 2)
    WHERE amount_paid_usd IS NULL OR amount_paid_usd = 0");
} catch (PDOException $e) {
  // Ignore temporary migration issues.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS school_expenses (
  id INT AUTO_INCREMENT PRIMARY KEY,
  expense_date DATE NOT NULL,
  category VARCHAR(80) NOT NULL,
  payee VARCHAR(180) NULL,
  description VARCHAR(255) NOT NULL,
  amount_original DECIMAL(12,2) NOT NULL,
  currency_code ENUM('USD','ZIG','RAND') NOT NULL DEFAULT 'USD',
  fx_rate_to_usd DECIMAL(18,8) NOT NULL,
  amount_usd DECIMAL(12,2) NOT NULL,
  payment_method VARCHAR(60) NULL,
  reference_no VARCHAR(80) NULL,
  note VARCHAR(255) NULL,
  proof_original_name VARCHAR(255) NULL,
  proof_file_path VARCHAR(255) NULL,
  proof_mime_type VARCHAR(120) NULL,
  proof_file_size BIGINT NULL,
  recorded_by INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_school_expenses_user FOREIGN KEY (recorded_by) REFERENCES users(id) ON DELETE CASCADE,
  INDEX idx_school_expense_date (expense_date),
  INDEX idx_school_expense_currency (currency_code)
)");

try {
  refresh_exchange_rates_online($pdo, true);
} catch (Throwable $e) {
  // Continue with cached/default rates if online source is unavailable.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS inventory_records (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  category ENUM('textbook','furniture','equipment','other') NOT NULL DEFAULT 'other',
  item_name VARCHAR(180) NOT NULL,
  quantity_recorded INT UNSIGNED NOT NULL DEFAULT 0,
  item_condition VARCHAR(80) NULL,
  inventory_note TEXT NULL,
  status ENUM('submitted','verified','discrepancy') NOT NULL DEFAULT 'submitted',
  stock_take_quantity INT UNSIGNED NULL,
  accountant_review TEXT NULL,
  reviewed_by INT NULL,
  reviewed_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ir_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ir_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_ir_reviewer FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_ir_teacher_created (teacher_id, created_at),
  INDEX idx_ir_status_created (status, created_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS school_assets_register (
  id INT AUTO_INCREMENT PRIMARY KEY,
  source_inventory_id INT NOT NULL UNIQUE,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  category ENUM('textbook','furniture','equipment','other') NOT NULL DEFAULT 'other',
  item_name VARCHAR(180) NOT NULL,
  quantity INT UNSIGNED NOT NULL DEFAULT 0,
  item_condition VARCHAR(80) NULL,
  inventory_note TEXT NULL,
  approved_by INT NULL,
  approved_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_sar_source_inventory FOREIGN KEY (source_inventory_id) REFERENCES inventory_records(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_approver FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_sar_class (class_id),
  INDEX idx_sar_category (category),
  INDEX idx_sar_approved_at (approved_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS ancillary_salary_register (
  id INT AUTO_INCREMENT PRIMARY KEY,
  ancillary_id INT NOT NULL,
  salary_month CHAR(7) NOT NULL,
  base_salary DECIMAL(12,2) NOT NULL DEFAULT 0,
  allowance_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
  deduction_amount DECIMAL(12,2) NOT NULL DEFAULT 0,
  net_salary DECIMAL(12,2) NOT NULL DEFAULT 0,
  pay_date DATE NULL,
  note VARCHAR(255) NULL,
  recorded_by INT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_asr_ancillary FOREIGN KEY (ancillary_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_asr_recorded_by FOREIGN KEY (recorded_by) REFERENCES users(id) ON DELETE SET NULL,
  UNIQUE KEY uq_asr_worker_month (ancillary_id, salary_month),
  INDEX idx_asr_month (salary_month)
)");

function inventory_category_label(string $category): string {
  $map = [
    'textbook' => 'Textbooks',
    'furniture' => 'Furniture',
    'equipment' => 'Equipment (Laptops, Projectors, etc.)',
    'other' => 'Other Teaching Materials'
  ];
  return $map[$category] ?? ucfirst(str_replace('_', ' ', $category));
}

function format_file_size($bytes): string {
  $size = (float)$bytes;
  if ($size <= 0) {
    return '0 B';
  }
  $units = ['B', 'KB', 'MB', 'GB', 'TB'];
  $power = min((int)floor(log($size, 1024)), count($units) - 1);
  $value = $size / pow(1024, $power);
  return number_format($value, $value >= 100 || $power === 0 ? 0 : 1) . ' ' . $units[$power];
}

function generate_invoice_number(): string {
  return 'INV-' . date('Ymd') . '-' . strtoupper(bin2hex(random_bytes(2)));
}

function sync_invoice_status(PDO $pdo, int $invoiceId): void {
  $invoiceStmt = $pdo->prepare("SELECT id, amount_due FROM fee_invoices WHERE id = ? LIMIT 1");
  $invoiceStmt->execute([$invoiceId]);
  $invoice = $invoiceStmt->fetch();
  if (!$invoice) {
    return;
  }

  $paidStmt = $pdo->prepare("SELECT COALESCE(SUM(COALESCE(amount_paid_usd, amount_paid)), 0) FROM fee_payments WHERE invoice_id = ?");
  $paidStmt->execute([$invoiceId]);
  $paidTotal = (float)$paidStmt->fetchColumn();
  $amountDue = (float)$invoice['amount_due'];

  $status = 'unpaid';
  if ($paidTotal >= $amountDue && $amountDue > 0) {
    $status = 'paid';
  } elseif ($paidTotal > 0 && $paidTotal < $amountDue) {
    $status = 'partially_paid';
  }

  $updateStmt = $pdo->prepare("UPDATE fee_invoices SET status = ? WHERE id = ?");
  $updateStmt->execute([$status, $invoiceId]);
}

function log_accountant_activity(PDO $pdo, int $actorId, string $action, string $details, ?string $entityType = null, ?int $entityId = null): void {
  if ($actorId <= 0) {
    return;
  }

  try {
    append_system_log(
      $pdo,
      $action,
      $details,
      $actorId,
      'accountant',
      $entityType,
      $entityId,
      null
    );
  } catch (Throwable $e) {
    // Never block desk operations if logging fails.
  }
}

$alerts = [];
$activeUserId = (int)($_SESSION['user_id'] ?? 0);
$accountantProfile = null;

ensure_system_logs_table($pdo);

if (!$isAdminReadOnlyView) {
  $accountantProfileStmt = $pdo->prepare("SELECT id, name, email, password_hash FROM users WHERE id = ? AND role = 'accountant' LIMIT 1");
  $accountantProfileStmt->execute([$activeUserId]);
  $accountantProfile = $accountantProfileStmt->fetch();

  if (!$accountantProfile) {
    logout_user();
    header('Location: index.php');
    exit;
  }

  if (isset($_POST['save_accountant_profile'])) {
    $profileName = trim((string)($_POST['profile_name'] ?? ''));
    $profileEmail = trim((string)($_POST['profile_email'] ?? ''));

    if ($profileName === '' || $profileEmail === '') {
      $alerts[] = ['type' => 'error', 'text' => 'Profile name and email are required.'];
    } elseif (!filter_var($profileEmail, FILTER_VALIDATE_EMAIL)) {
      $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid email address.'];
    } else {
      $emailExistsStmt = $pdo->prepare("SELECT id FROM users WHERE LOWER(email) = LOWER(?) AND id <> ? LIMIT 1");
      $emailExistsStmt->execute([$profileEmail, $activeUserId]);
      if ($emailExistsStmt->fetch()) {
        $alerts[] = ['type' => 'error', 'text' => 'That email is already used by another account.'];
      } else {
        $updateProfileStmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ? AND role = 'accountant' LIMIT 1");
        $updateProfileStmt->execute([$profileName, $profileEmail, $activeUserId]);
        $_SESSION['name'] = $profileName;
        $accountantProfile['name'] = $profileName;
        $accountantProfile['email'] = $profileEmail;
        log_accountant_activity(
          $pdo,
          $activeUserId,
          'accountant_profile_updated',
          'Accountant profile updated. New email: ' . $profileEmail,
          'user',
          $activeUserId
        );
        $alerts[] = ['type' => 'success', 'text' => 'Accountant profile updated successfully.'];
      }
    }
  }

  if (isset($_POST['change_accountant_password'])) {
    $currentPassword = (string)($_POST['current_password'] ?? '');
    $newPassword = (string)($_POST['new_password'] ?? '');
    $confirmPassword = (string)($_POST['confirm_password'] ?? '');

    if ($currentPassword === '' || $newPassword === '' || $confirmPassword === '') {
      $alerts[] = ['type' => 'error', 'text' => 'Current password, new password, and confirmation are required.'];
    } elseif (!password_verify($currentPassword, (string)$accountantProfile['password_hash'])) {
      $alerts[] = ['type' => 'error', 'text' => 'Current password is incorrect.'];
    } elseif (!mavela_password_is_strong($newPassword)) {
      $alerts[] = ['type' => 'error', 'text' => 'Use at least 10 characters with uppercase, lowercase, and a number.'];
    } elseif ($newPassword !== $confirmPassword) {
      $alerts[] = ['type' => 'error', 'text' => 'New password and confirmation do not match.'];
    } else {
      $newHash = password_hash($newPassword, PASSWORD_DEFAULT);
      $updatePasswordStmt = $pdo->prepare("UPDATE users SET password_hash = ?, must_change_password = 0 WHERE id = ? AND role = 'accountant' LIMIT 1");
      $updatePasswordStmt->execute([$newHash, $activeUserId]);
      $_SESSION['must_change_password'] = false;
      $accountantProfile['password_hash'] = $newHash;
      log_accountant_activity(
        $pdo,
        $activeUserId,
        'accountant_password_changed',
        'Accountant changed account password.',
        'user',
        $activeUserId
      );
      $alerts[] = ['type' => 'success', 'text' => 'Accountant password changed successfully.'];
    }
  }
}

if (isset($_POST['save_manual_exchange_rates']) && !$isAdminReadOnlyView) {
  $rawUsdRate = trim((string)($_POST['rate_usd'] ?? '1'));
  $rawZigRate = trim((string)($_POST['rate_zig'] ?? ''));
  $rawRandRate = trim((string)($_POST['rate_rand'] ?? ''));

  $usdRate = (float)str_replace(',', '.', $rawUsdRate);
  $zigRate = (float)str_replace(',', '.', $rawZigRate);
  $randRate = (float)str_replace(',', '.', $rawRandRate);

  if ($usdRate <= 0 || $zigRate <= 0 || $randRate <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'All manual exchange rates must be numeric values greater than zero.'];
  } else {
    try {
      $upsertRateStmt = $pdo->prepare("INSERT INTO currency_rates (currency_code, base_currency, rate_to_base, source, fetched_at)
        VALUES (?, 'USD', ?, 'manual', NOW())
        ON DUPLICATE KEY UPDATE rate_to_base = VALUES(rate_to_base), source = VALUES(source), fetched_at = VALUES(fetched_at)");

      $upsertRateStmt->execute(['USD', $usdRate]);
      $upsertRateStmt->execute(['ZIG', $zigRate]);
      $upsertRateStmt->execute(['RAND', $randRate]);

      set_exchange_rate_mode($pdo, 'manual', $activeUserId > 0 ? $activeUserId : null);
      log_accountant_activity(
        $pdo,
        $activeUserId,
        'exchange_rates_manual_saved',
        'Manual FX rates saved (USD=' . number_format($usdRate, 8, '.', '') . ', ZIG=' . number_format($zigRate, 8, '.', '') . ', RAND=' . number_format($randRate, 8, '.', '') . ').',
        'exchange_rate',
        null
      );
      $alerts[] = ['type' => 'success', 'text' => 'Manual exchange rates saved successfully. Automatic online refresh is now paused.'];
    } catch (Throwable $e) {
      $alerts[] = ['type' => 'error', 'text' => 'Could not save manual exchange rates: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['use_auto_exchange_rates']) && !$isAdminReadOnlyView) {
  try {
    set_exchange_rate_mode($pdo, 'auto', $activeUserId > 0 ? $activeUserId : null);
    $refreshResult = refresh_exchange_rates_online($pdo, true);
    log_accountant_activity(
      $pdo,
      $activeUserId,
      'exchange_rates_auto_enabled',
      'Automatic FX rate mode enabled. Result: ' . (string)($refreshResult['message'] ?? 'unknown') . '.',
      'exchange_rate',
      null
    );
    if (!empty($refreshResult['ok'])) {
      $alerts[] = ['type' => 'success', 'text' => 'Automatic exchange rate mode enabled. Latest online rates pulled successfully.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Automatic mode enabled, but online refresh failed: ' . (string)($refreshResult['message'] ?? 'unknown error')];
    }
  } catch (Throwable $e) {
    $alerts[] = ['type' => 'error', 'text' => 'Could not enable automatic exchange rate mode: ' . mavela_exception_detail($e)];
  }
}

if ($isAdminReadOnlyView && ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
  $_POST = [];
  $alerts[] = ['type' => 'error', 'text' => 'Admin view is read-only. Changes are not allowed in accountant dashboard preview mode.'];
}

if ($isAdminReadOnlyView) {
  $alerts[] = ['type' => 'success', 'text' => 'Admin read-only preview mode is active for accountant dashboard.'];
}

if (isset($_POST['create_invoice'])) {
  $learnerId = (int)($_POST['invoice_learner_id'] ?? 0);
  $description = trim((string)($_POST['invoice_description'] ?? ''));
  $amountDueRaw = trim((string)($_POST['invoice_amount_due'] ?? ''));
  $invoiceRegistrationRaw = trim((string)($_POST['invoice_fee_registration'] ?? ''));
  $invoiceZimsecRaw = trim((string)($_POST['invoice_fee_zimsec'] ?? ''));
  $dueDate = trim((string)($_POST['invoice_due_date'] ?? ''));

  $invoiceGpf = 20.00;
  $invoiceSsf = 20.00;
  $invoiceSdc = 80.00;

  if ($learnerId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a learner for the invoice.'];
  } elseif ($description === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Invoice description is required.'];
  } elseif ($invoiceRegistrationRaw === '' || !is_numeric(str_replace(',', '.', $invoiceRegistrationRaw))
    || $invoiceZimsecRaw === '' || !is_numeric(str_replace(',', '.', $invoiceZimsecRaw))) {
    $alerts[] = ['type' => 'error', 'text' => 'Registration Fees and ZIMSEC must be numeric values.'];
  } else {
    $invoiceRegistration = (float)str_replace(',', '.', $invoiceRegistrationRaw);
    $invoiceZimsec = (float)str_replace(',', '.', $invoiceZimsecRaw);
    $componentTotal = round($invoiceGpf + $invoiceSsf + $invoiceSdc + $invoiceRegistration + $invoiceZimsec, 2);

    if ($invoiceRegistration < 0 || $invoiceZimsec < 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Fee components cannot be negative values.'];
    } elseif ($componentTotal <= 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Total invoice amount from all fee components must be greater than zero.'];
    } else {
      $amountDue = $componentTotal;
      if ($amountDueRaw !== '') {
        if (!is_numeric(str_replace(',', '.', $amountDueRaw))) {
          $alerts[] = ['type' => 'error', 'text' => 'Invoice amount must be numeric.'];
        } else {
          $requestedAmountDue = (float)str_replace(',', '.', $amountDueRaw);
          if ($requestedAmountDue <= 0) {
            $alerts[] = ['type' => 'error', 'text' => 'Invoice amount must be greater than zero.'];
          } elseif (abs($requestedAmountDue - $componentTotal) > 0.01) {
            $alerts[] = ['type' => 'error', 'text' => 'Amount Due must match the sum of all fee components.'];
          }
        }
      }

      if (!empty($alerts)) {
        // Keep validation messaging deterministic before attempting inserts.
      } else {
      $learnerStmt = $pdo->prepare("SELECT id, class_id FROM learners WHERE id = ? AND COALESCE(is_frozen, 0) = 0 LIMIT 1");
      $learnerStmt->execute([$learnerId]);
      $learner = $learnerStmt->fetch();

      if (!$learner) {
        $alerts[] = ['type' => 'error', 'text' => 'Learner not found for invoice creation.'];
      } else {
        $invoiceNumber = generate_invoice_number();
        $insertStmt = $pdo->prepare("INSERT INTO fee_invoices
          (invoice_number, learner_id, class_id, description, amount_due, fee_gpf, fee_ssf, fee_sdc, fee_registration, fee_zimsec, due_date, created_by)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $insertStmt->execute([
          $invoiceNumber,
          $learnerId,
          (int)$learner['class_id'],
          $description,
          $amountDue,
          $invoiceGpf,
          $invoiceSsf,
          $invoiceSdc,
          $invoiceRegistration,
          $invoiceZimsec,
          $dueDate === '' ? null : $dueDate,
          $activeUserId
        ]);
        $invoiceId = (int)$pdo->lastInsertId();
        log_accountant_activity(
          $pdo,
          $activeUserId,
          'invoice_created',
          'Invoice ' . $invoiceNumber . ' created for learner ID ' . $learnerId . ' with amount USD ' . number_format($amountDue, 2) . '.',
          'fee_invoice',
          $invoiceId > 0 ? $invoiceId : null
        );
        $alerts[] = ['type' => 'success', 'text' => 'Invoice ' . $invoiceNumber . ' created successfully.'];

        if (whatsapp_notifications_enabled()) {
          $waStats = notify_parents_owed_update_whatsapp(
            $pdo,
            $learnerId,
            'New fee invoice posted.',
            'Invoice: ' . $invoiceNumber
              . ' | Amount: $' . number_format($amountDue, 2)
              . ' | GPF: $' . number_format($invoiceGpf, 2)
              . ' | SSF: $' . number_format($invoiceSsf, 2)
              . ' | SDC: $' . number_format($invoiceSdc, 2)
              . ' | Registration: $' . number_format($invoiceRegistration, 2)
              . ' | ZIMSEC: $' . number_format($invoiceZimsec, 2)
          );
          $alerts[] = ['type' => 'success', 'text' => 'WhatsApp owed update: ' . $waStats['sent'] . ' sent, ' . $waStats['failed'] . ' failed, ' . $waStats['skipped'] . ' skipped.'];
        } else {
          $alerts[] = ['type' => 'success', 'text' => 'Invoice created. WhatsApp not configured yet (set NAPS_WHATSAPP_TOKEN and NAPS_WHATSAPP_PHONE_NUMBER_ID).'];
        }
      }
      }
    }
  }
}

if (isset($_POST['record_payment'])) {
  $learnerId = (int)($_POST['payment_learner_id'] ?? 0);
  $invoiceId = (int)($_POST['payment_invoice_id'] ?? 0);
  $amountPaidRaw = trim((string)($_POST['payment_amount'] ?? ''));
  $currencyCode = strtoupper(trim((string)($_POST['payment_currency_code'] ?? 'USD')));
  $paymentDate = trim((string)($_POST['payment_date'] ?? ''));
  $paymentMethod = trim((string)($_POST['payment_method'] ?? 'cash'));
  $referenceNo = trim((string)($_POST['payment_reference'] ?? ''));
  $note = trim((string)($_POST['payment_note'] ?? ''));

  $allowedMethods = ['cash', 'ecocash', 'bank_transfer', 'pos', 'other'];

  if ($learnerId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a learner for payment.'];
  } elseif (!in_array($currencyCode, supported_currencies(), true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Unsupported payment currency selected.'];
  } elseif ($amountPaidRaw === '' || !is_numeric(str_replace(',', '.', $amountPaidRaw))) {
    $alerts[] = ['type' => 'error', 'text' => 'Payment amount must be numeric.'];
  } elseif ($paymentDate === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Payment date is required.'];
  } elseif (!in_array($paymentMethod, $allowedMethods, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid payment method selected.'];
  } elseif ($referenceNo === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Receipt number is required. Enter the manual receipt number before recording payment.'];
  } else {
    $amountPaid = (float)str_replace(',', '.', $amountPaidRaw);
    if ($amountPaid <= 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Payment amount must be greater than zero.'];
    } else {
      if ($invoiceId > 0) {
        $invoiceCheckStmt = $pdo->prepare("SELECT id FROM fee_invoices WHERE id = ? AND learner_id = ? LIMIT 1");
        $invoiceCheckStmt->execute([$invoiceId, $learnerId]);
        if (!$invoiceCheckStmt->fetch()) {
          $alerts[] = ['type' => 'error', 'text' => 'Selected invoice does not belong to the selected learner.'];
        }
      }

      if (empty($alerts)) {
        $fxRate = get_currency_rate_to_usd($pdo, $currencyCode);
        $amountPaidUsd = round($amountPaid * $fxRate, 2);

        $allocationWeights = [
          'GPF' => 20,
          'SSF' => 20,
          'SDC' => 80
        ];
        $totalWeight = array_sum($allocationWeights);
        $components = array_keys($allocationWeights);
        $allocationOriginal = [];
        $allocationUsd = [];
        $remainingOriginal = $amountPaid;
        $remainingUsd = $amountPaidUsd;

        foreach ($components as $index => $componentCode) {
          $isLast = $index === count($components) - 1;
          if ($isLast) {
            $componentOriginal = round($remainingOriginal, 2);
            $componentUsd = round($remainingUsd, 2);
          } else {
            $componentOriginal = round($amountPaid * ($allocationWeights[$componentCode] / $totalWeight), 2);
            $componentUsd = round($amountPaidUsd * ($allocationWeights[$componentCode] / $totalWeight), 2);
            $remainingOriginal -= $componentOriginal;
            $remainingUsd -= $componentUsd;
          }
          $allocationOriginal[$componentCode] = $componentOriginal;
          $allocationUsd[$componentCode] = $componentUsd;
        }

        $paymentInsertStmt = $pdo->prepare("INSERT INTO fee_payments
          (invoice_id, learner_id, amount_paid, currency_code, fx_rate_to_usd, amount_paid_usd, payment_date, fee_component, payment_method, reference_no, note, received_by)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

        $insertedPaymentIds = [];
        foreach ($components as $componentCode) {
          $componentOriginal = (float)($allocationOriginal[$componentCode] ?? 0);
          $componentUsd = (float)($allocationUsd[$componentCode] ?? 0);
          if ($componentOriginal <= 0 && $componentUsd <= 0) {
            continue;
          }

          $paymentInsertStmt->execute([
            $invoiceId > 0 ? $invoiceId : null,
            $learnerId,
            $componentOriginal,
            $currencyCode,
            $fxRate,
            $componentUsd,
            $paymentDate,
            $componentCode,
            $paymentMethod,
            $referenceNo,
            $note === '' ? null : $note,
            $activeUserId
          ]);
          $insertedPaymentIds[] = (int)$pdo->lastInsertId();
        }
        $paymentId = !empty($insertedPaymentIds) ? (int)end($insertedPaymentIds) : 0;

        log_accountant_activity(
          $pdo,
          $activeUserId,
          'payment_recorded',
          'Payment recorded for learner ID ' . $learnerId . ' (' . $currencyCode . ' ' . number_format($amountPaid, 2) . ', USD ' . number_format($amountPaidUsd, 2) . ') and auto-allocated across GPF/SSF/SDC.',
          'fee_payment',
          $paymentId > 0 ? $paymentId : null
        );

        if ($invoiceId > 0) {
          sync_invoice_status($pdo, $invoiceId);
        }

        $alerts[] = ['type' => 'success', 'text' => 'Payment recorded and auto-allocated across GPF/SSF/SDC (' . $currencyCode . ' ' . number_format($amountPaid, 2) . ' => USD $' . number_format($amountPaidUsd, 2) . ').'];

        if (whatsapp_notifications_enabled()) {
          $waStats = notify_parents_payment_whatsapp(
            $pdo,
            $learnerId,
            $amountPaid,
            $paymentDate,
            $paymentMethod,
            $referenceNo === '' ? null : $referenceNo,
            $currencyCode,
            $amountPaidUsd,
            'AUTO-ALLOCATED GPF/SSF/SDC'
          );
          $alerts[] = ['type' => 'success', 'text' => 'WhatsApp payment alert: ' . $waStats['sent'] . ' sent, ' . $waStats['failed'] . ' failed, ' . $waStats['skipped'] . ' skipped.'];
        } else {
          $alerts[] = ['type' => 'success', 'text' => 'Payment recorded. WhatsApp not configured yet (set NAPS_WHATSAPP_TOKEN and NAPS_WHATSAPP_PHONE_NUMBER_ID).'];
        }
      }
    }
  }
}

if (isset($_POST['record_expense'])) {
  $expenseDate = trim((string)($_POST['expense_date'] ?? date('Y-m-d')));
  $expenseCategory = trim((string)($_POST['expense_category'] ?? 'General'));
  $expensePayee = trim((string)($_POST['expense_payee'] ?? ''));
  $expenseDescription = trim((string)($_POST['expense_description'] ?? ''));
  $expenseAmountRaw = trim((string)($_POST['expense_amount'] ?? ''));
  $expenseCurrency = strtoupper(trim((string)($_POST['expense_currency_code'] ?? 'USD')));
  $expenseMethod = trim((string)($_POST['expense_method'] ?? ''));
  $expenseReference = trim((string)($_POST['expense_reference'] ?? ''));
  $expenseNote = trim((string)($_POST['expense_note'] ?? ''));

  if ($expenseDescription === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Expense description is required.'];
  } elseif ($expenseAmountRaw === '' || !is_numeric(str_replace(',', '.', $expenseAmountRaw))) {
    $alerts[] = ['type' => 'error', 'text' => 'Expense amount must be numeric.'];
  } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $expenseDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Expense date must be a valid date.'];
  } elseif (!in_array($expenseCurrency, supported_currencies(), true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Unsupported expense currency selected.'];
  } else {
    $expenseAmountOriginal = (float)str_replace(',', '.', $expenseAmountRaw);
    if ($expenseAmountOriginal <= 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Expense amount must be greater than zero.'];
    } else {
      $proofError = (int)($_FILES['expense_proof']['error'] ?? UPLOAD_ERR_NO_FILE);
      $proofOriginalName = null;
      $proofPath = null;
      $proofMimeType = null;
      $proofFileSize = null;

      if ($proofError !== UPLOAD_ERR_OK) {
        $alerts[] = ['type' => 'error', 'text' => 'Proof of payment upload is required.'];
      } else {
        $proofOriginalName = (string)($_FILES['expense_proof']['name'] ?? '');
        $proofTmpName = (string)($_FILES['expense_proof']['tmp_name'] ?? '');
        $proofFileSize = (int)($_FILES['expense_proof']['size'] ?? 0);
        $proofExtension = strtolower(pathinfo($proofOriginalName, PATHINFO_EXTENSION));
        $allowedExtensions = ['pdf', 'jpg', 'jpeg', 'png', 'webp'];

        if ($proofOriginalName === '' || $proofTmpName === '') {
          $alerts[] = ['type' => 'error', 'text' => 'Invalid proof upload payload.'];
        } elseif (!in_array($proofExtension, $allowedExtensions, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'Proof file must be PDF or image (JPG/PNG/WEBP).'];
        } elseif ($proofFileSize <= 0 || $proofFileSize > 8 * 1024 * 1024) {
          $alerts[] = ['type' => 'error', 'text' => 'Proof file size must be between 1 byte and 8 MB.'];
        } else {
          $finfo = finfo_open(FILEINFO_MIME_TYPE);
          $proofMimeType = $finfo ? (string)finfo_file($finfo, $proofTmpName) : null;
          if ($finfo) {
            finfo_close($finfo);
          }
          $allowedProofMimes = ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'];
          if ($proofMimeType === null || !in_array($proofMimeType, $allowedProofMimes, true)) {
            $alerts[] = ['type' => 'error', 'text' => 'The proof file content does not match an allowed PDF or image format.'];
          } else {
            $safeBase = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo($proofOriginalName, PATHINFO_FILENAME));
            $safeBase = trim((string)$safeBase, '._-');
            if ($safeBase === '') {
              $safeBase = 'expense_proof';
            }

            $uploadDir = __DIR__ . '/Uploads/expense_proofs';
            if (!is_dir($uploadDir) && !mkdir($uploadDir, 0775, true)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not prepare proof upload folder.'];
            } else {
              $fileName = 'expense_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '_' . $safeBase . '.' . $proofExtension;
              $destPath = $uploadDir . '/' . $fileName;
              if (!move_uploaded_file($proofTmpName, $destPath)) {
                $alerts[] = ['type' => 'error', 'text' => 'Could not save proof upload file.'];
              } else {
                $proofPath = 'Uploads/expense_proofs/' . $fileName;
              }
            }
          }
        }
      }

      if (empty($alerts)) {
        $fxRate = get_currency_rate_to_usd($pdo, $expenseCurrency);
        $amountUsd = round($expenseAmountOriginal * $fxRate, 2);

        $insertExpenseStmt = $pdo->prepare("INSERT INTO school_expenses
          (expense_date, category, payee, description, amount_original, currency_code, fx_rate_to_usd, amount_usd,
           payment_method, reference_no, note, proof_original_name, proof_file_path, proof_mime_type, proof_file_size, recorded_by)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $insertExpenseStmt->execute([
          $expenseDate,
          $expenseCategory === '' ? 'General' : $expenseCategory,
          $expensePayee === '' ? null : $expensePayee,
          $expenseDescription,
          $expenseAmountOriginal,
          $expenseCurrency,
          $fxRate,
          $amountUsd,
          $expenseMethod === '' ? null : $expenseMethod,
          $expenseReference === '' ? null : $expenseReference,
          $expenseNote === '' ? null : $expenseNote,
          $proofOriginalName,
          $proofPath,
          $proofMimeType,
          $proofFileSize,
          $activeUserId
        ]);
        $expenseId = (int)$pdo->lastInsertId();

        log_accountant_activity(
          $pdo,
          $activeUserId,
          'expense_recorded',
          'Expense recorded: ' . $expenseCurrency . ' ' . number_format($expenseAmountOriginal, 2) . ' (USD ' . number_format($amountUsd, 2) . ') for ' . ($expenseCategory === '' ? 'General' : $expenseCategory) . '.',
          'school_expense',
          $expenseId > 0 ? $expenseId : null
        );

        $alerts[] = ['type' => 'success', 'text' => 'Expense recorded: ' . $expenseCurrency . ' ' . number_format($expenseAmountOriginal, 2) . ' (USD $' . number_format($amountUsd, 2) . ').'];
      }
    }
  }
}

if (isset($_POST['verify_inventory_record'])) {
  $inventoryRecordId = (int)($_POST['inventory_record_id'] ?? 0);
  $stockTakeQuantityRaw = trim((string)($_POST['stock_take_quantity'] ?? ''));
  $verificationStatus = trim((string)($_POST['verification_status'] ?? 'verified'));
  $inventoryReview = trim((string)($_POST['inventory_review'] ?? ''));

  if ($inventoryRecordId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid inventory record selected for verification.'];
  } elseif ($stockTakeQuantityRaw === '' || !ctype_digit($stockTakeQuantityRaw)) {
    $alerts[] = ['type' => 'error', 'text' => 'Physical stock-take quantity must be a whole number (0 or more).'];
  } elseif (!in_array($verificationStatus, ['verified', 'discrepancy'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid inventory verification status selected.'];
  } else {
    $inventoryExistsStmt = $pdo->prepare("SELECT id, teacher_id, class_id, category, item_name, item_condition, inventory_note
      FROM inventory_records WHERE id = ? LIMIT 1");
    $inventoryExistsStmt->execute([$inventoryRecordId]);
    $inventoryRow = $inventoryExistsStmt->fetch();
    if (!$inventoryRow) {
      $alerts[] = ['type' => 'error', 'text' => 'Inventory record not found.'];
    } else {
      $inventoryUpdateStmt = $pdo->prepare("UPDATE inventory_records
        SET stock_take_quantity = ?,
            status = ?,
            accountant_review = ?,
            reviewed_by = ?,
            reviewed_at = NOW()
        WHERE id = ?");
      $inventoryUpdateStmt->execute([
        (int)$stockTakeQuantityRaw,
        $verificationStatus,
        $inventoryReview === '' ? null : $inventoryReview,
        $activeUserId,
        $inventoryRecordId
      ]);

      if ($verificationStatus === 'verified') {
        $assetsUpsertStmt = $pdo->prepare("INSERT INTO school_assets_register
          (source_inventory_id, teacher_id, class_id, category, item_name, quantity, item_condition, inventory_note, approved_by, approved_at)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
          ON DUPLICATE KEY UPDATE
            teacher_id = VALUES(teacher_id),
            class_id = VALUES(class_id),
            category = VALUES(category),
            item_name = VALUES(item_name),
            quantity = VALUES(quantity),
            item_condition = VALUES(item_condition),
            inventory_note = VALUES(inventory_note),
            approved_by = VALUES(approved_by),
            approved_at = NOW()");
        $assetsUpsertStmt->execute([
          $inventoryRecordId,
          (int)$inventoryRow['teacher_id'],
          (int)$inventoryRow['class_id'],
          (string)$inventoryRow['category'],
          (string)$inventoryRow['item_name'],
          (int)$stockTakeQuantityRaw,
          $inventoryRow['item_condition'] === null ? null : (string)$inventoryRow['item_condition'],
          $inventoryRow['inventory_note'] === null ? null : (string)$inventoryRow['inventory_note'],
          $activeUserId > 0 ? $activeUserId : null
        ]);
      } else {
        $assetsDeleteStmt = $pdo->prepare("DELETE FROM school_assets_register WHERE source_inventory_id = ?");
        $assetsDeleteStmt->execute([$inventoryRecordId]);
      }

      log_accountant_activity(
        $pdo,
        $activeUserId,
        'inventory_reviewed',
        'Inventory record #' . $inventoryRecordId . ' reviewed with status ' . $verificationStatus . ' and stock take qty ' . (int)$stockTakeQuantityRaw . '.',
        'inventory_record',
        $inventoryRecordId
      );

      $alerts[] = ['type' => 'success', 'text' => 'Inventory stock-take review sent to teacher desk successfully.'];
    }
  }
}

if (isset($_POST['review_transfer_clearance_accountant'])) {
  $transferRequestId = (int)($_POST['transfer_request_id'] ?? 0);
  $decision = trim((string)($_POST['accountant_transfer_decision'] ?? 'approve'));
  $comment = trim((string)($_POST['accountant_transfer_comment'] ?? ''));

  if ($transferRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer request selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer clearance decision.'];
  } else {
    $status = $decision === 'approve' ? 'approved' : 'rejected';
    $checkStmt = $pdo->prepare("SELECT id FROM transfer_requests
      WHERE id = ? AND status = 'clearance_requested' AND accountant_status = 'pending' LIMIT 1");
    $checkStmt->execute([$transferRequestId]);

    if (!$checkStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Transfer request not found or already reviewed by accounts office.'];
    } else {
      $updateStmt = $pdo->prepare("UPDATE transfer_requests
        SET accountant_status = ?, accountant_comment = ?, accountant_reviewed_at = NOW(),
            status = CASE WHEN ? = 'rejected' THEN 'rejected' ELSE status END
        WHERE id = ?");
      $updateStmt->execute([
        $status,
        $comment === '' ? ($status === 'approved' ? 'Accountant clearance approved.' : 'Accountant clearance rejected.') : $comment,
        $status,
        $transferRequestId
      ]);
      log_accountant_activity(
        $pdo,
        $activeUserId,
        'transfer_clearance_reviewed',
        'Transfer request #' . $transferRequestId . ' reviewed with decision: ' . $status . '.',
        'transfer_request',
        $transferRequestId
      );
      $alerts[] = ['type' => 'success', 'text' => 'Transfer clearance ' . $status . ' successfully.'];
    }
  }
}

if (isset($_POST['save_ancillary_salary_record']) && !$isAdminReadOnlyView) {
  $ancillaryUserId = (int)($_POST['salary_ancillary_id'] ?? 0);
  $salaryMonth = trim((string)($_POST['salary_month'] ?? ''));
  $baseSalaryRaw = trim((string)($_POST['salary_base'] ?? '0'));
  $allowanceRaw = trim((string)($_POST['salary_allowance'] ?? '0'));
  $deductionRaw = trim((string)($_POST['salary_deduction'] ?? '0'));
  $payDate = trim((string)($_POST['salary_pay_date'] ?? ''));
  $note = trim((string)($_POST['salary_note'] ?? ''));

  if ($ancillaryUserId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose an ancillary staff member for salary posting.'];
  } elseif (!preg_match('/^\d{4}-\d{2}$/', $salaryMonth)) {
    $alerts[] = ['type' => 'error', 'text' => 'Salary month must use YYYY-MM format.'];
  } elseif (!is_numeric(str_replace(',', '.', $baseSalaryRaw)) || !is_numeric(str_replace(',', '.', $allowanceRaw)) || !is_numeric(str_replace(',', '.', $deductionRaw))) {
    $alerts[] = ['type' => 'error', 'text' => 'Salary values must be numeric.'];
  } elseif ($payDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $payDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Pay date must use YYYY-MM-DD format.'];
  } else {
    $baseSalary = round((float)str_replace(',', '.', $baseSalaryRaw), 2);
    $allowanceAmount = round((float)str_replace(',', '.', $allowanceRaw), 2);
    $deductionAmount = round((float)str_replace(',', '.', $deductionRaw), 2);
    $netSalary = round(($baseSalary + $allowanceAmount) - $deductionAmount, 2);

    if ($baseSalary < 0 || $allowanceAmount < 0 || $deductionAmount < 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Salary values cannot be negative.'];
    } elseif ($netSalary < 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Net salary cannot be negative. Check base salary, allowance, and deductions.'];
    } else {
      $existsStmt = $pdo->prepare("SELECT id FROM users WHERE id = ? AND role = 'ancillary' LIMIT 1");
      $existsStmt->execute([$ancillaryUserId]);
      if (!$existsStmt->fetch()) {
        $alerts[] = ['type' => 'error', 'text' => 'Selected ancillary staff member was not found.'];
      } else {
        $upsertStmt = $pdo->prepare("INSERT INTO ancillary_salary_register
          (ancillary_id, salary_month, base_salary, allowance_amount, deduction_amount, net_salary, pay_date, note, recorded_by)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
          ON DUPLICATE KEY UPDATE
            base_salary = VALUES(base_salary),
            allowance_amount = VALUES(allowance_amount),
            deduction_amount = VALUES(deduction_amount),
            net_salary = VALUES(net_salary),
            pay_date = VALUES(pay_date),
            note = VALUES(note),
            recorded_by = VALUES(recorded_by),
            updated_at = CURRENT_TIMESTAMP");
        $upsertStmt->execute([
          $ancillaryUserId,
          $salaryMonth,
          $baseSalary,
          $allowanceAmount,
          $deductionAmount,
          $netSalary,
          $payDate === '' ? null : $payDate,
          $note === '' ? null : $note,
          $activeUserId > 0 ? $activeUserId : null
        ]);

        log_accountant_activity(
          $pdo,
          $activeUserId,
          'ancillary_salary_saved',
          'Saved salary register entry for ancillary user ID ' . $ancillaryUserId . ' month ' . $salaryMonth . ' (net USD ' . number_format($netSalary, 2) . ').',
          'ancillary_salary_register',
          null
        );

        $alerts[] = ['type' => 'success', 'text' => 'Ancillary salary register saved for ' . $salaryMonth . '.'];
      }
    }
  }
}

$learners = $pdo->query("SELECT l.id, l.reg_number, l.full_name, c.name AS class_name
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  WHERE COALESCE(l.is_frozen, 0) = 0
  ORDER BY c.id, l.surname, l.christian_names, l.full_name")->fetchAll();

$ancillaryWorkers = $pdo->query("SELECT u.id, u.name, u.email,
    sp.work_profile, sp.ec_number
  FROM users u
  LEFT JOIN staff_profiles sp ON sp.user_id = u.id
  WHERE u.role = 'ancillary'
  ORDER BY u.name")->fetchAll();

$ancillarySalaryRows = $pdo->query("SELECT asr.id, asr.salary_month, asr.base_salary, asr.allowance_amount,
    asr.deduction_amount, asr.net_salary, asr.pay_date, asr.note, asr.updated_at,
    u.name AS ancillary_name, u.email AS ancillary_email,
    sp.work_profile,
    rb.name AS recorded_by_name
  FROM ancillary_salary_register asr
  JOIN users u ON u.id = asr.ancillary_id
  LEFT JOIN staff_profiles sp ON sp.user_id = u.id
  LEFT JOIN users rb ON rb.id = asr.recorded_by
  ORDER BY asr.salary_month DESC, u.name ASC")->fetchAll();

$openInvoices = $pdo->query("SELECT fi.id, fi.invoice_number, fi.learner_id, fi.description, fi.amount_due,
  fi.fee_gpf, fi.fee_ssf, fi.fee_sdc, fi.fee_registration, fi.fee_zimsec,
    fi.due_date, fi.status, l.full_name, l.reg_number, c.name AS class_name,
  COALESCE(SUM(COALESCE(fp.amount_paid_usd, fp.amount_paid)), 0) AS paid_total
  FROM fee_invoices fi
  JOIN learners l ON l.id = fi.learner_id
  JOIN classes c ON c.id = fi.class_id
  LEFT JOIN fee_payments fp ON fp.invoice_id = fi.id
  GROUP BY fi.id
  HAVING fi.status <> 'paid'
  ORDER BY fi.created_at DESC
  LIMIT 300")->fetchAll();

$invoiceRows = $pdo->query("SELECT fi.id, fi.invoice_number, fi.learner_id, fi.description, fi.amount_due,
  fi.fee_gpf, fi.fee_ssf, fi.fee_sdc, fi.fee_registration, fi.fee_zimsec, fi.due_date,
    fi.status, fi.created_at, l.full_name, l.reg_number, c.name AS class_name,
  COALESCE(SUM(COALESCE(fp.amount_paid_usd, fp.amount_paid)), 0) AS paid_total
  FROM fee_invoices fi
  JOIN learners l ON l.id = fi.learner_id
  JOIN classes c ON c.id = fi.class_id
  LEFT JOIN fee_payments fp ON fp.invoice_id = fi.id
  GROUP BY fi.id
  ORDER BY fi.created_at DESC
  LIMIT 400")->fetchAll();

$paymentRows = $pdo->query("SELECT fp.id, fp.learner_id, fp.payment_date, fp.amount_paid, fp.currency_code, fp.fx_rate_to_usd, fp.amount_paid_usd,
  fp.fee_component, fp.payment_method, fp.reference_no, fp.note,
    fp.created_at, l.full_name, l.reg_number, c.name AS class_name, fi.invoice_number
  FROM fee_payments fp
  JOIN learners l ON l.id = fp.learner_id
  JOIN classes c ON c.id = l.class_id
  LEFT JOIN fee_invoices fi ON fi.id = fp.invoice_id
  ORDER BY fp.payment_date DESC, fp.created_at DESC
  LIMIT 500")->fetchAll();

$learnerBalanceRows = $pdo->query("SELECT l.id, l.reg_number, l.full_name, c.name AS class_name,
    COALESCE((SELECT SUM(fi.amount_due) FROM fee_invoices fi WHERE fi.learner_id = l.id), 0) AS total_invoiced,
  COALESCE((SELECT SUM(COALESCE(fp.amount_paid_usd, fp.amount_paid)) FROM fee_payments fp WHERE fp.learner_id = l.id), 0) AS total_paid
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  ORDER BY c.id, l.surname, l.christian_names, l.full_name
  LIMIT 500")->fetchAll();

$ledgerCardRows = $pdo->query("SELECT
    l.id,
    l.reg_number,
    l.full_name,
    c.name AS class_name,
    COALESCE((SELECT COUNT(*) FROM fee_invoices fi WHERE fi.learner_id = l.id), 0) AS invoice_count,
    COALESCE((SELECT COUNT(*) FROM fee_payments fp WHERE fp.learner_id = l.id), 0) AS payment_count,
    (SELECT MAX(fp.payment_date) FROM fee_payments fp WHERE fp.learner_id = l.id) AS last_payment_date,
    COALESCE((SELECT SUM(fi.amount_due) FROM fee_invoices fi WHERE fi.learner_id = l.id), 0) AS total_invoiced,
    COALESCE((SELECT SUM(COALESCE(fp.amount_paid_usd, fp.amount_paid)) FROM fee_payments fp WHERE fp.learner_id = l.id), 0) AS total_paid
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  ORDER BY c.id, l.surname, l.christian_names, l.full_name
  LIMIT 600")->fetchAll();

$inventoryPendingRows = $pdo->query("SELECT ir.id, ir.category, ir.item_name, ir.quantity_recorded,
    ir.item_condition, ir.inventory_note, ir.created_at,
    c.name AS class_name,
    t.name AS teacher_name, t.email AS teacher_email
  FROM inventory_records ir
  JOIN classes c ON c.id = ir.class_id
  JOIN users t ON t.id = ir.teacher_id
  WHERE ir.status = 'submitted'
  ORDER BY ir.created_at DESC
  LIMIT 300")->fetchAll();

$inventoryAllRows = $pdo->query("SELECT ir.id, ir.category, ir.item_name, ir.quantity_recorded,
    ir.item_condition, ir.inventory_note, ir.stock_take_quantity,
    ir.accountant_review, ir.status, ir.reviewed_at, ir.created_at,
    c.name AS class_name,
    t.name AS teacher_name, t.email AS teacher_email,
    reviewer.name AS reviewer_name
  FROM inventory_records ir
  JOIN classes c ON c.id = ir.class_id
  JOIN users t ON t.id = ir.teacher_id
  LEFT JOIN users reviewer ON reviewer.id = ir.reviewed_by
  ORDER BY ir.created_at DESC
  LIMIT 500")->fetchAll();

$inventorySubmittedCount = (int)$pdo->query("SELECT COUNT(*) FROM inventory_records WHERE status = 'submitted'")->fetchColumn();
$inventoryDiscrepancyCount = (int)$pdo->query("SELECT COUNT(*) FROM inventory_records WHERE status = 'discrepancy'")->fetchColumn();

$schoolAssetsRows = $pdo->query("SELECT sar.id, sar.source_inventory_id, sar.category, sar.item_name, sar.quantity,
    sar.item_condition, sar.inventory_note, sar.approved_at, sar.created_at,
    c.name AS class_name,
    t.name AS teacher_name, t.email AS teacher_email,
    approver.name AS approver_name
  FROM school_assets_register sar
  JOIN classes c ON c.id = sar.class_id
  JOIN users t ON t.id = sar.teacher_id
  LEFT JOIN users approver ON approver.id = sar.approved_by
  ORDER BY sar.approved_at DESC, sar.created_at DESC
  LIMIT 600")->fetchAll();

$transferRequestsForAccounts = $pdo->query("SELECT tr.id, tr.destination_school, tr.reason, tr.requested_at, tr.status,
    tr.teacher_status, tr.accountant_status, tr.accountant_comment, tr.accountant_reviewed_at,
    p.name AS parent_name,
    l.full_name AS learner_name, l.reg_number, c.name AS class_name
  FROM transfer_requests tr
  JOIN users p ON p.id = tr.parent_user_id
  JOIN learners l ON l.id = tr.learner_id
  JOIN classes c ON c.id = l.class_id
  ORDER BY tr.requested_at DESC
  LIMIT 400")->fetchAll();

$accountantActivityRowsStmt = $pdo->prepare("SELECT sl.created_at, sl.action, sl.details, sl.entity_type, sl.entity_id,
    sl.ip_address,
    u.name AS actor_name,
    u.email AS actor_email
  FROM system_logs sl
  LEFT JOIN users u ON u.id = sl.actor_id
  WHERE sl.actor_role = 'accountant'
  ORDER BY sl.created_at DESC
  LIMIT 500");
$accountantActivityRowsStmt->execute();
$accountantActivityRows = $accountantActivityRowsStmt->fetchAll();

$schoolAssetsCount = (int)$pdo->query("SELECT COUNT(*) FROM school_assets_register")->fetchColumn();

$totalInvoiced = (float)$pdo->query("SELECT COALESCE(SUM(amount_due), 0) FROM fee_invoices")->fetchColumn();
$totalCollected = (float)$pdo->query("SELECT COALESCE(SUM(COALESCE(amount_paid_usd, amount_paid)), 0) FROM fee_payments")->fetchColumn();
$currentMonthCollectedStmt = $pdo->prepare("SELECT COALESCE(SUM(COALESCE(amount_paid_usd, amount_paid)), 0)
  FROM fee_payments
  WHERE DATE_FORMAT(payment_date, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')");
$currentMonthCollectedStmt->execute();
$currentMonthCollected = (float)$currentMonthCollectedStmt->fetchColumn();
$totalTuckshopSalesUsd = 0.0;
try {
  $totalTuckshopSalesUsd = (float)$pdo->query("SELECT COALESCE(SUM(COALESCE(total_amount_usd, total_amount)), 0) FROM tp_sales WHERE workspace = 'tuckshop' AND status = 'completed'")->fetchColumn();
} catch (PDOException $e) {
  try {
    $totalTuckshopSalesUsd = (float)$pdo->query("SELECT COALESCE(SUM(total_amount), 0) FROM tp_sales WHERE workspace = 'tuckshop' AND status = 'completed'")->fetchColumn();
  } catch (PDOException $innerException) {
    $totalTuckshopSalesUsd = 0.0;
  }
}

$currentMonthTuckshopSalesUsd = 0.0;
try {
  $currentMonthTuckshopSalesUsdStmt = $pdo->prepare("SELECT COALESCE(SUM(COALESCE(total_amount_usd, total_amount)), 0)
    FROM tp_sales
    WHERE workspace = 'tuckshop' AND status = 'completed' AND DATE_FORMAT(sold_at, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')");
  $currentMonthTuckshopSalesUsdStmt->execute();
  $currentMonthTuckshopSalesUsd = (float)$currentMonthTuckshopSalesUsdStmt->fetchColumn();
} catch (PDOException $e) {
  try {
    $currentMonthTuckshopSalesUsdStmt = $pdo->prepare("SELECT COALESCE(SUM(total_amount), 0)
      FROM tp_sales
      WHERE workspace = 'tuckshop' AND status = 'completed' AND DATE_FORMAT(sold_at, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m')");
    $currentMonthTuckshopSalesUsdStmt->execute();
    $currentMonthTuckshopSalesUsd = (float)$currentMonthTuckshopSalesUsdStmt->fetchColumn();
  } catch (PDOException $innerException) {
    $currentMonthTuckshopSalesUsd = 0.0;
  }
}
$totalOperationalIncomeUsd = $totalCollected + $totalTuckshopSalesUsd;
$totalExpensesUsd = (float)$pdo->query("SELECT COALESCE(SUM(amount_usd), 0) FROM school_expenses")->fetchColumn();
$netCashPositionUsd = $totalOperationalIncomeUsd - $totalExpensesUsd;
$totalOutstanding = max(0, $totalInvoiced - $totalCollected);
$collectionRatePct = $totalInvoiced > 0 ? min(100, ($totalCollected / $totalInvoiced) * 100) : 0;
$expenseToIncomePct = $totalOperationalIncomeUsd > 0 ? min(100, ($totalExpensesUsd / $totalOperationalIncomeUsd) * 100) : 0;
$outstandingSharePct = $totalInvoiced > 0 ? min(100, ($totalOutstanding / $totalInvoiced) * 100) : 0;

$exchangeRateMode = get_exchange_rate_mode($pdo);

$rateRows = [];
try {
  $rateRows = $pdo->query("SELECT currency_code, rate_to_base, fetched_at FROM currency_rates ORDER BY currency_code")->fetchAll();
} catch (PDOException $e) {
  $rateRows = [];
}

$rateMap = [];
foreach ($rateRows as $rateRow) {
  $rateMap[strtoupper((string)$rateRow['currency_code'])] = (float)($rateRow['rate_to_base'] ?? 0);
}
$manualUsdRate = $rateMap['USD'] ?? 1.0;
$manualZigRate = $rateMap['ZIG'] ?? 0.03;
$manualRandRate = $rateMap['RAND'] ?? 0.055;

$expenseRows = $pdo->query("SELECT se.id, se.expense_date, se.category, se.payee, se.description,
    se.amount_original, se.currency_code, se.fx_rate_to_usd, se.amount_usd,
    se.payment_method, se.reference_no, se.note, se.proof_original_name, se.proof_file_path,
    se.created_at, u.name AS recorded_by_name
  FROM school_expenses se
  LEFT JOIN users u ON u.id = se.recorded_by
  ORDER BY se.expense_date DESC, se.created_at DESC
  LIMIT 600")->fetchAll();

$tuckshopCashbookRows = [];
try {
  $tuckshopCashbookRows = $pdo->query("SELECT
      COALESCE(sale_ref, CONCAT('legacy-', id)) AS sale_ref,
      MIN(sold_at) AS sold_at,
      MAX(COALESCE(currency_code, 'USD')) AS currency_code,
      SUM(total_amount) AS amount_original,
      SUM(COALESCE(total_amount_usd, total_amount)) AS amount_usd,
      MAX(payment_method) AS payment_method
    FROM tp_sales
    WHERE workspace = 'tuckshop' AND status = 'completed'
    GROUP BY COALESCE(sale_ref, CONCAT('legacy-', id))
    ORDER BY sold_at DESC
    LIMIT 1200")->fetchAll();
} catch (PDOException $e) {
  try {
    $tuckshopCashbookRows = $pdo->query("SELECT
        COALESCE(sale_ref, CONCAT('legacy-', id)) AS sale_ref,
        MIN(sold_at) AS sold_at,
        MAX(COALESCE(currency_code, 'USD')) AS currency_code,
        SUM(total_amount) AS amount_original,
        SUM(total_amount) AS amount_usd,
        MAX(payment_method) AS payment_method
      FROM tp_sales
      WHERE workspace = 'tuckshop' AND status = 'completed'
      GROUP BY COALESCE(sale_ref, CONCAT('legacy-', id))
      ORDER BY sold_at DESC
      LIMIT 1200")->fetchAll();
  } catch (PDOException $innerException) {
    $tuckshopCashbookRows = [];
  }
}

$cashBookRows = [];
foreach ($paymentRows as $payment) {
  $cashBookRows[] = [
    'entry_date' => (string)$payment['payment_date'],
    'entry_type' => 'INCOME',
    'description' => 'Fee payment - ' . (string)$payment['full_name'] . ' (' . (string)$payment['reg_number'] . ')',
    'reference' => (string)($payment['reference_no'] ?: ($payment['invoice_number'] ?: '-')),
    'currency' => (string)($payment['currency_code'] ?: 'USD'),
    'amount_original' => (float)$payment['amount_paid'],
    'amount_usd' => (float)($payment['amount_paid_usd'] ?: $payment['amount_paid']),
    'money_in_usd' => (float)($payment['amount_paid_usd'] ?: $payment['amount_paid']),
    'money_out_usd' => 0.0
  ];
}
foreach ($tuckshopCashbookRows as $sale) {
  $cashBookRows[] = [
    'entry_date' => (string)$sale['sold_at'],
    'entry_type' => 'INCOME',
    'description' => 'Tuckshop POS sale (' . strtoupper((string)($sale['payment_method'] ?: 'cash')) . ')',
    'reference' => (string)($sale['sale_ref'] ?: '-'),
    'currency' => (string)($sale['currency_code'] ?: 'USD'),
    'amount_original' => (float)$sale['amount_original'],
    'amount_usd' => (float)$sale['amount_usd'],
    'money_in_usd' => (float)$sale['amount_usd'],
    'money_out_usd' => 0.0
  ];
}
foreach ($expenseRows as $expense) {
  $cashBookRows[] = [
    'entry_date' => (string)$expense['expense_date'],
    'entry_type' => 'EXPENSE',
    'description' => (string)$expense['description'],
    'reference' => (string)($expense['reference_no'] ?: '-'),
    'currency' => (string)($expense['currency_code'] ?: 'USD'),
    'amount_original' => (float)$expense['amount_original'],
    'amount_usd' => (float)$expense['amount_usd'],
    'money_in_usd' => 0.0,
    'money_out_usd' => (float)$expense['amount_usd']
  ];
}
usort($cashBookRows, static function (array $a, array $b): int {
  return strcmp((string)$a['entry_date'], (string)$b['entry_date']);
});
$runningCashUsd = 0.0;
foreach ($cashBookRows as $idx => $entry) {
  $runningCashUsd += (float)$entry['money_in_usd'];
  $runningCashUsd -= (float)$entry['money_out_usd'];
  $cashBookRows[$idx]['balance_usd'] = round($runningCashUsd, 2);
}

$debtorsRows = [];
foreach ($learnerBalanceRows as $row) {
  $balance = max(0, (float)$row['total_invoiced'] - (float)$row['total_paid']);
  if ($balance > 0) {
    $debtorsRows[] = [
      'reg_number' => (string)$row['reg_number'],
      'learner_name' => (string)$row['full_name'],
      'class_name' => (string)$row['class_name'],
      'balance_usd' => $balance
    ];
  }
}
$activeDebtorsCount = count($debtorsRows);

$trialBalanceRows = [
  ['account' => 'Cash and Bank', 'debit' => max(0, $netCashPositionUsd), 'credit' => max(0, -$netCashPositionUsd)],
  ['account' => 'Debtors Control', 'debit' => $totalOutstanding, 'credit' => 0.0],
  ['account' => 'Fee Income', 'debit' => 0.0, 'credit' => $totalCollected],
  ['account' => 'Tuckshop Sales Income', 'debit' => 0.0, 'credit' => $totalTuckshopSalesUsd],
  ['account' => 'Operating Expenses', 'debit' => $totalExpensesUsd, 'credit' => 0.0]
];

$bankStatementBalanceUsd = (float)get_app_setting($pdo, 'bank_statement_balance_usd', (string)round($netCashPositionUsd, 2));
$bankReconciliationRows = [
  ['item' => 'Cashbook balance (USD)', 'amount_usd' => $netCashPositionUsd],
  ['item' => 'Bank statement balance (USD)', 'amount_usd' => $bankStatementBalanceUsd],
  ['item' => 'Difference (USD)', 'amount_usd' => $netCashPositionUsd - $bankStatementBalanceUsd]
];

$profitLossRows = [
  ['item' => 'Total Fee Income (USD)', 'amount_usd' => $totalCollected],
  ['item' => 'Total Tuckshop Income (USD)', 'amount_usd' => $totalTuckshopSalesUsd],
  ['item' => 'Total Operating Income (USD)', 'amount_usd' => $totalOperationalIncomeUsd],
  ['item' => 'Total Expenses (USD)', 'amount_usd' => -$totalExpensesUsd],
  ['item' => 'Net Profit / (Loss) (USD)', 'amount_usd' => $totalOperationalIncomeUsd - $totalExpensesUsd]
];

$balanceSheetRows = [
  ['section' => 'ASSETS', 'item' => 'Cash and Bank (USD)', 'amount_usd' => $netCashPositionUsd],
  ['section' => 'ASSETS', 'item' => 'Accounts Receivable / Debtors (USD)', 'amount_usd' => $totalOutstanding],
  ['section' => 'LIABILITIES', 'item' => 'Current Liabilities (USD)', 'amount_usd' => 0.0],
  ['section' => 'EQUITY', 'item' => 'Accumulated Surplus (USD)', 'amount_usd' => ($netCashPositionUsd + $totalOutstanding)]
];

$defaultSchoolName = 'MAVELA GOVERNMENT HIGH SCHOOL';
$defaultSchoolAddress = 'P.O.Box 12 Tsholotsho';
$defaultSchoolContact = 'Phone: +263 77 000 0000 | Email: admin@mavelahigh.org';
$defaultSchoolMotto = 'Imfundo Yinsika Yesizwe';
$defaultSchoolLogoPath = 'Uploads/Mavela_logo.png';

$normalizeHexColor = static function (string $raw, string $fallback): string {
  $value = strtoupper(trim($raw));
  if (preg_match('/^#[0-9A-F]{6}$/', $value)) {
    return $value;
  }
  return strtoupper($fallback);
};

$schoolName = trim(get_app_setting($pdo, 'school_name', $defaultSchoolName));
$schoolAddress = trim(get_app_setting($pdo, 'school_address', $defaultSchoolAddress));
$schoolContact = trim(get_app_setting($pdo, 'school_contact', $defaultSchoolContact));
$schoolMotto = trim(get_app_setting($pdo, 'school_motto', $defaultSchoolMotto));
$schoolLogoPath = trim(get_app_setting($pdo, 'school_logo_path', $defaultSchoolLogoPath));

if ($schoolName === '') {
  $schoolName = $defaultSchoolName;
}
if ($schoolAddress === '') {
  $schoolAddress = $defaultSchoolAddress;
}
if ($schoolContact === '') {
  $schoolContact = $defaultSchoolContact;
}
if ($schoolMotto === '') {
  $schoolMotto = $defaultSchoolMotto;
}
if ($schoolLogoPath === '') {
  $schoolLogoPath = $defaultSchoolLogoPath;
}

$resolvedSchoolLogoPath = $schoolLogoPath;
$resolvedSchoolLogoAbsolute = __DIR__ . '/' . ltrim($resolvedSchoolLogoPath, '/\\');
if (!is_file($resolvedSchoolLogoAbsolute)) {
  $fallbackLogoAbsolute = __DIR__ . '/' . ltrim($defaultSchoolLogoPath, '/\\');
  if (is_file($fallbackLogoAbsolute)) {
    $resolvedSchoolLogoPath = $defaultSchoolLogoPath;
    $resolvedSchoolLogoAbsolute = $fallbackLogoAbsolute;
  } else {
    $resolvedSchoolLogoPath = '';
    $resolvedSchoolLogoAbsolute = '';
  }
}

$paletteBgCream = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_cream', '#f6efe0'), '#f6efe0');
$paletteBgSand = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_sand', '#eadcc0'), '#eadcc0');
$paletteInk = $normalizeHexColor(get_app_setting($pdo, 'palette_ink', '#0a2f63'), '#0a2f63');
$paletteMuted = $normalizeHexColor(get_app_setting($pdo, 'palette_muted', '#4f5f7a'), '#4f5f7a');
$paletteBrandNavy = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy', '#0a3b79'), '#0a3b79');
$paletteBrandNavyDeep = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy_deep', '#082e60'), '#082e60');
$paletteBrandIce = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_ice', '#e8eef8'), '#e8eef8');
$palettePatchSky = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_sky', '#7cc9ff'), '#7cc9ff');

$schoolLogoDataUri = '';
if ($resolvedSchoolLogoAbsolute !== '' && is_file($resolvedSchoolLogoAbsolute)) {
  $schoolLogoBytes = @file_get_contents($resolvedSchoolLogoAbsolute);
  if ($schoolLogoBytes !== false) {
    $schoolLogoDataUri = 'data:image/png;base64,' . base64_encode($schoolLogoBytes);
  }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Accountant Desk | <?= h($schoolName) ?></title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@500;600;700;800&display=swap" rel="stylesheet">
  <style>
    :root {
      --bg-cream: <?= h($paletteBgCream) ?>;
      --bg-sand: <?= h($paletteBgSand) ?>;
      --ink: <?= h($paletteInk) ?>;
      --muted: <?= h($paletteMuted) ?>;
      --brand-navy: <?= h($paletteBrandNavy) ?>;
      --brand-navy-deep: <?= h($paletteBrandNavyDeep) ?>;
      --brand-ice: <?= h($paletteBrandIce) ?>;
      --patch-sky: <?= h($palettePatchSky) ?>;
      --line: #d8d4c9;
      --success: #166534;
      --danger: #9f1239;
      --panel: #ffffff;
      --shadow: 0 18px 45px rgba(10, 47, 99, 0.14);
    }

    * { box-sizing: border-box; }

    body {
      margin: 0;
      min-height: 100vh;
      font-family: 'Outfit', sans-serif;
      color: var(--ink);
      background:
        radial-gradient(circle at 15% 18%, rgba(248, 180, 0, 0.2) 0, rgba(248, 180, 0, 0) 40%),
        radial-gradient(circle at 80% 20%, rgba(124, 201, 255, 0.24) 0, rgba(124, 201, 255, 0) 38%),
        linear-gradient(170deg, var(--bg-cream) 0%, var(--bg-sand) 100%);
      padding: 14px;
    }

    .shell { max-width: 1320px; margin: 0 auto; display: grid; gap: 12px; }

    .header {
      border-radius: 16px;
      padding: 16px;
      background: linear-gradient(122deg, var(--brand-navy-deep), var(--brand-navy) 55%, var(--patch-sky));
      color: #fff;
      box-shadow: var(--shadow);
      display: flex;
      justify-content: space-between;
      gap: 10px;
      flex-wrap: wrap;
      align-items: center;
    }

    .header h1 { margin: 0; font-family: 'Plus Jakarta Sans', sans-serif; font-size: 1.3rem; }
    .header-brand { display:flex; align-items:center; gap:10px; }
    .header-logo { width:52px; height:52px; border-radius:12px; object-fit:contain; background:#fff; border:1px solid rgba(255,255,255,0.4); padding:4px; }
    .chip { border: 1px solid #f8b400; background: #ffd447; color: #12386d; border-radius: 999px; padding: 8px 12px; text-decoration: none; font-weight: 700; }

    .stats {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 10px;
    }

    .stat {
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: 12px;
      padding: 12px;
      box-shadow: var(--shadow);
    }

    .stat small { color: var(--muted); display: block; }
    .stat strong { font-size: 1.4rem; }

    .panel-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }

    .panel {
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: 14px;
      box-shadow: var(--shadow);
      padding: 14px;
    }

    .panel h2 { margin: 0 0 8px; }
    .sub { margin: 0 0 10px; color: var(--muted); font-size: 0.92rem; }

    .field { display: grid; gap: 6px; margin-bottom: 10px; }
    label { font-size: 0.82rem; text-transform: uppercase; color: var(--muted); font-weight: 700; }
    input, select, textarea {
      border: 1px solid #c8c5bc;
      border-radius: 10px;
      padding: 10px;
      font-family: inherit;
      color: var(--ink);
      width: 100%;
    }

    input[type="search"] {
      background:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23516f96' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") no-repeat 10px center,
        linear-gradient(90deg, #ffffff 0%, #f2f8ff 65%, #fff8df 100%);
      background-size: 15px 15px, auto;
      padding-left: 34px;
    }

    textarea { min-height: 72px; resize: vertical; }

    .btn {
      border: 0;
      border-radius: 10px;
      padding: 10px 12px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      cursor: pointer;
      background: linear-gradient(115deg, #ffd447, #f8b400);
      color: #17253f;
    }

    .btn:hover { background: #7cc9ff; color: #083b78; }

    .alert { padding: 9px 10px; border-radius: 9px; border: 1px solid; font-weight: 600; }
    .alert.success { background: #ecfdf3; color: var(--success); border-color: #86efac; }
    .alert.error { background: #fff1f2; color: var(--danger); border-color: #fda4af; }

    .table-wrap { overflow-x: auto; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid #d8def0; padding: 8px; text-align: left; font-size: 0.88rem; }
    th { background: #f0f5ff; color: #12386d; }
    .badge {
      display: inline-block;
      border-radius: 999px;
      padding: 2px 8px;
      font-size: 0.75rem;
      font-weight: 700;
      border: 1px solid #bfd4f4;
      color: #1a4a8a;
      background: #eaf0fb;
    }

    .num { font-variant-numeric: tabular-nums; }

    .workspace-layout {
      display: grid;
      grid-template-columns: 260px minmax(0, 1fr);
      gap: 12px;
      align-items: start;
    }

    .side-nav {
      position: sticky;
      top: 10px;
      max-height: calc(100vh - 24px);
      overflow: auto;
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: 14px;
      box-shadow: var(--shadow);
      padding: 10px;
      display: grid;
      gap: 8px;
    }

    .side-nav h3 {
      margin: 4px 4px 0;
      font-size: 0.88rem;
      color: #37517a;
      letter-spacing: 0.02em;
      text-transform: uppercase;
    }

    .nav-btn {
      border: 1px solid #cbd8f0;
      border-radius: 10px;
      background: #f4f8ff;
      color: #12386d;
      text-align: left;
      padding: 8px 10px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      font-size: 0.86rem;
      cursor: pointer;
      transition: transform 140ms ease, background 140ms ease, color 140ms ease;
    }

    .nav-btn.active {
      background: linear-gradient(122deg, var(--brand-navy-deep), var(--brand-navy));
      color: #fff;
      border-color: #0f3f78;
    }

    .workspace-main {
      display: grid;
      gap: 10px;
    }

    .workspace-section.hidden {
      display: none !important;
      visibility: hidden;
      height: 0;
      overflow: hidden;
    }
    
    .workspace-section:not(.hidden) {
      display: grid !important;
      gap: 12px;
      visibility: visible;
      height: auto;
      overflow: visible;
    }

    .report-switcher {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 8px;
      margin-bottom: 10px;
    }

    .report-btn {
      border: 1px solid #cbd8f0;
      border-radius: 10px;
      background: #f4f8ff;
      color: #12386d;
      text-align: left;
      padding: 8px 10px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      font-size: 0.84rem;
      cursor: pointer;
      transition: transform 140ms ease, background 140ms ease, color 140ms ease;
    }

    .report-btn.active {
      background: linear-gradient(122deg, var(--brand-navy-deep), var(--brand-navy));
      color: #fff;
      border-color: #0f3f78;
    }

    .financial-report-panel.report-hidden {
      display: none !important;
      visibility: hidden;
      height: 0;
      overflow: hidden;
    }

    .inventory-switcher {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 8px;
      margin-bottom: 10px;
    }

    .inventory-btn {
      border: 1px solid #cbd8f0;
      border-radius: 10px;
      background: #f4f8ff;
      color: #12386d;
      text-align: left;
      padding: 8px 10px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      font-size: 0.84rem;
      cursor: pointer;
      transition: transform 140ms ease, background 140ms ease, color 140ms ease;
    }

    .inventory-btn.active {
      background: linear-gradient(122deg, var(--brand-navy-deep), var(--brand-navy));
      color: #fff;
      border-color: #0f3f78;
    }

    .inventory-panel.inventory-hidden {
      display: none !important;
      visibility: hidden;
      height: 0;
      overflow: hidden;
    }

    .ledger-card-search {
      margin-bottom: 10px;
    }

    .ledger-card-actions {
      display: grid;
      grid-template-columns: 1fr 1fr auto auto;
      gap: 8px;
      margin-bottom: 10px;
      align-items: end;
    }

    @media (max-width: 860px) {
      .ledger-card-actions {
        grid-template-columns: 1fr;
      }
    }

    .ledger-card-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
      gap: 12px;
    }

    .ledger-card {
      position: relative;
      border: 1px solid #d8def0;
      border-radius: 14px;
      background: linear-gradient(145deg, #ffffff 0%, #f7fbff 100%);
      padding: 13px;
      box-shadow: 0 10px 24px rgba(10, 59, 121, 0.1);
      display: grid;
      gap: 8px;
      overflow: hidden;
    }

    .ledger-card::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 5px;
      background: linear-gradient(90deg, #1f4f93, #d2a94f 58%, #1f4f93);
    }

    .ledger-card h3 {
      margin: 0;
      font-size: 1rem;
      color: #12386d;
      font-family: Georgia, 'Times New Roman', serif;
      letter-spacing: 0.2px;
    }

    .ledger-card-head {
      display: flex;
      justify-content: space-between;
      gap: 8px;
      align-items: center;
      flex-wrap: wrap;
    }

    .ledger-pill {
      border: 1px solid #c7d5ef;
      background: #eef4ff;
      color: #1f4f93;
      border-radius: 999px;
      padding: 3px 9px;
      font-size: 0.73rem;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.4px;
    }

    .ledger-card .meta {
      color: #4a6287;
      font-size: 0.84rem;
    }

    .ledger-card .amount-row {
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 8px;
      font-size: 0.88rem;
    }

    .ledger-card .amount-row strong {
      font-family: 'Plus Jakarta Sans', sans-serif;
      color: #12386d;
    }

    .ledger-balance.good {
      color: #166534;
      font-weight: 800;
    }

    .ledger-balance.warn {
      color: #b91c1c;
      font-weight: 800;
    }

    .ledger-classic-rule {
      height: 1px;
      background: linear-gradient(90deg, transparent, #cfd9ec 16%, #cfd9ec 84%, transparent);
      margin: 2px 0;
    }

    .kpi-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }

    .kpi-card {
      border: 1px solid #d5dff1;
      border-radius: 12px;
      padding: 10px;
      background: #fbfdff;
    }

    .kpi-title { color: #486088; font-size: 0.84rem; }
    .kpi-value { font-weight: 800; font-size: 1.3rem; margin: 2px 0 8px; }

    .kpi-track {
      width: 100%;
      height: 9px;
      border-radius: 999px;
      background: #e4ebf9;
      overflow: hidden;
    }

    .kpi-fill {
      height: 100%;
      border-radius: 999px;
      background: linear-gradient(90deg, #1a4a8a, #7cc9ff);
    }

    .transaction-filter {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 8px;
      margin-bottom: 10px;
    }

    a:hover,
    button:hover,
    input:hover,
    select:hover,
    textarea:hover,
    [role="button"]:hover,
    .button:hover,
    .btn:hover,
    .submit:hover,
    .chip:hover,
    .meta-chip:hover,
    .side-btn:hover,
    .desk-nav-btn:not(.active):hover,
    .menu button:hover,
    table tbody tr:hover td,
    table tbody tr:hover th,
    .card:hover,
    .panel:hover,
    .item:hover,
    .metric:hover,
    .stat:hover {
      background-color: #dff4ff !important;
      border-color: #7cc9ff !important;
      color: #083b78 !important;
    }

    @media (max-width: 1000px) {
      .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      .panel-grid { grid-template-columns: 1fr; }
      .workspace-layout { grid-template-columns: 1fr; }
      .side-nav { position: static; }
      .transaction-filter { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }

    @media (max-width: 560px) {
      input,
      select,
      textarea {
        font-size: 16px;
      }

      .button,
      .side-btn {
        min-height: 44px;
      }

      .stats { grid-template-columns: 1fr; }
      .kpi-grid { grid-template-columns: 1fr; }
      .transaction-filter { grid-template-columns: 1fr; }
      body { padding: 10px; }
      th, td { padding: 7px; }
    }
  </style>
</head>
<body>
  <div class="shell">
    <header class="header">
      <div class="header-brand">
        <img class="header-logo" src="<?= h($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath) ?>" alt="<?= h($schoolName) ?> logo">
        <div>
          <h1>Accountant Desk</h1>
        <?php if ($isAdminReadOnlyView): ?>
          <div><?= h($schoolName) ?> | Admin read-only preview mode. Responsible for invoices, fee collection, and financial records.</div>
        <?php else: ?>
          <div><?= h($schoolName) ?> | Responsible for invoices, fee collection, and financial records.</div>
        <?php endif; ?>
        </div>
      </div>
      <div style="display:flex; gap:8px; flex-wrap:wrap;">
        <span class="chip" id="accountantDeskProgressChip">Step 1 of 8</span>
        <?php if ($isAdminReadOnlyView): ?>
          <a class="chip" href="admin.php">Back to Admin Portal</a>
        <?php endif; ?>
        <span class="chip"><?= h($_SESSION['name'] ?? 'Accountant') ?></span>
        <a class="chip" href="logout.php">Logout</a>
      </div>
    </header>

    <?php foreach ($alerts as $alert): ?>
      <div class="alert <?= $alert['type'] === 'success' ? 'success' : 'error' ?>"><?= h($alert['text']) ?></div>
    <?php endforeach; ?>

    <div class="workspace-layout">
      <aside class="side-nav">
        <button class="nav-btn active" type="button" data-group="overview">Overview & Analysis</button>
        <button class="nav-btn" type="button" data-group="profile">My Profile</button>
        <button class="nav-btn" type="button" data-group="transactions">Transactions</button>
        <button class="nav-btn" type="button" data-group="ledgercards">Student Ledger Cards</button>
        <button class="nav-btn" type="button" data-group="expenses">Expenses</button>
        <button class="nav-btn" type="button" data-group="payroll">Ancillary Payroll</button>
        <h3>Reporting</h3>
        <button class="nav-btn" type="button" data-group="reports">Financial Reports</button>
        <button class="nav-btn" type="button" data-group="inventory">Inventory & Assets</button>
        <button class="nav-btn" type="button" data-group="transfers">Transfer Clearances</button>
        <button class="nav-btn" type="button" data-group="all">Focus Summary</button>
      </aside>

      <main class="workspace-main">

    <section class="panel workspace-section" data-group="profile">
      <h2>My Profile</h2>
      <?php if ($isAdminReadOnlyView): ?>
        <p class="sub">Profile editing is disabled in admin read-only preview mode.</p>
      <?php else: ?>
        <p class="sub">Update your accountant account information and password.</p>
        <div class="panel-grid" style="grid-template-columns:repeat(auto-fit,minmax(280px,1fr));">
          <article class="panel" style="margin:0;">
            <h3 style="margin:0 0 8px; color:#12345f;">Account Details</h3>
            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="accountant_profile_name">Full Name</label>
                <input id="accountant_profile_name" name="profile_name" value="<?= h((string)($accountantProfile['name'] ?? '')) ?>" required>
              </div>
              <div class="field">
                <label for="accountant_profile_email">Email Address</label>
                <input id="accountant_profile_email" type="email" name="profile_email" value="<?= h((string)($accountantProfile['email'] ?? '')) ?>" required>
              </div>
              <button class="btn" type="submit" name="save_accountant_profile">Save Profile</button>
            </form>
          </article>

          <article class="panel" style="margin:0;">
            <h3 style="margin:0 0 8px; color:#12345f;">Change Password</h3>
            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="accountant_current_password">Current Password</label>
                <input id="accountant_current_password" type="password" name="current_password" required>
              </div>
              <div class="field">
                <label for="accountant_new_password">New Password</label>
                <input id="accountant_new_password" type="password" name="new_password" minlength="10" autocomplete="new-password" required>
              </div>
              <div class="field">
                <label for="accountant_confirm_password">Confirm New Password</label>
                <input id="accountant_confirm_password" type="password" name="confirm_password" minlength="10" autocomplete="new-password" required>
              </div>
              <button class="btn" type="submit" name="change_accountant_password">Change Password</button>
            </form>
          </article>
        </div>
      <?php endif; ?>
    </section>

    <section class="stats workspace-section" data-group="overview">
      <article class="stat"><small>Total Invoiced (USD Base)</small><strong class="num">$<?= h(number_format($totalInvoiced, 2)) ?></strong></article>
      <article class="stat"><small>Total Collected (USD Base)</small><strong class="num">$<?= h(number_format($totalCollected, 2)) ?></strong></article>
      <article class="stat"><small>Tuckshop Income (USD Base)</small><strong class="num">$<?= h(number_format($totalTuckshopSalesUsd, 2)) ?></strong></article>
      <article class="stat"><small>Outstanding Balance (USD)</small><strong class="num">$<?= h(number_format($totalOutstanding, 2)) ?></strong></article>
      <article class="stat"><small>Collected This Month (USD)</small><strong class="num">$<?= h(number_format($currentMonthCollected, 2)) ?></strong></article>
      <article class="stat"><small>Tuckshop This Month (USD)</small><strong class="num">$<?= h(number_format($currentMonthTuckshopSalesUsd, 2)) ?></strong></article>
      <article class="stat"><small>Total Expenses (USD)</small><strong class="num">$<?= h(number_format($totalExpensesUsd, 2)) ?></strong></article>
      <article class="stat"><small>Net Cash Position (USD)</small><strong class="num">$<?= h(number_format($netCashPositionUsd, 2)) ?></strong></article>
      <article class="stat"><small>Inventory Awaiting Stock-Take</small><strong><?= h($inventorySubmittedCount) ?></strong></article>
      <article class="stat"><small>Inventory with Discrepancies</small><strong><?= h($inventoryDiscrepancyCount) ?></strong></article>
      <article class="stat"><small>School Assets in Register</small><strong><?= h($schoolAssetsCount) ?></strong></article>
    </section>

    <section class="panel workspace-section" data-group="overview">
      <h2>Analysis Dashboard</h2>
      <p class="sub">Quick health indicators for collections, receivables, and spending efficiency.</p>
      <div class="kpi-grid">
        <article class="kpi-card">
          <div class="kpi-title">Collection Rate</div>
          <div class="kpi-value num"><?= h(number_format($collectionRatePct, 1)) ?>%</div>
          <div class="kpi-track"><div class="kpi-fill" style="width: <?= h(number_format($collectionRatePct, 1, '.', '')) ?>%;"></div></div>
        </article>
        <article class="kpi-card">
          <div class="kpi-title">Outstanding Share</div>
          <div class="kpi-value num"><?= h(number_format($outstandingSharePct, 1)) ?>%</div>
          <div class="kpi-track"><div class="kpi-fill" style="width: <?= h(number_format($outstandingSharePct, 1, '.', '')) ?>%;"></div></div>
        </article>
        <article class="kpi-card">
          <div class="kpi-title">Expense to Income Ratio</div>
          <div class="kpi-value num"><?= h(number_format($expenseToIncomePct, 1)) ?>%</div>
          <div class="kpi-track"><div class="kpi-fill" style="width: <?= h(number_format($expenseToIncomePct, 1, '.', '')) ?>%;"></div></div>
        </article>
        <article class="kpi-card">
          <div class="kpi-title">Active Debtors</div>
          <div class="kpi-value num"><?= h(number_format($activeDebtorsCount)) ?></div>
          <div class="sub" style="margin:0;">Learners currently with unpaid balances.</div>
        </article>
      </div>
    </section>

    <section class="panel workspace-section" data-group="overview">
      <h2>Exchange Rates (Base Currency: USD)</h2>
      <p class="sub">Stored value is USD equivalent for 1 unit of each currency. Current mode: <strong><?= h(strtoupper($exchangeRateMode)) ?></strong>.</p>

      <div class="panel" style="margin-bottom:12px; border:1px solid #dde7f7;">
        <h3 style="margin:0 0 8px; color:#12345f;">Manual Rate Input</h3>
        <p class="sub" style="margin-top:0;">Enter rates directly and save to lock rates manually. Example: if 1 RAND equals 0.055 USD, enter 0.05500000.</p>
        <form method="POST" autocomplete="off" style="display:grid; gap:10px; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); align-items:end;">
          <div class="field" style="margin:0;">
            <label for="rate_usd">USD to USD</label>
            <input id="rate_usd" name="rate_usd" type="number" step="0.00000001" min="0.00000001" value="<?= h(number_format((float)$manualUsdRate, 8, '.', '')) ?>" required>
          </div>
          <div class="field" style="margin:0;">
            <label for="rate_zig">ZIG to USD</label>
            <input id="rate_zig" name="rate_zig" type="number" step="0.00000001" min="0.00000001" value="<?= h(number_format((float)$manualZigRate, 8, '.', '')) ?>" required>
          </div>
          <div class="field" style="margin:0;">
            <label for="rate_rand">RAND to USD</label>
            <input id="rate_rand" name="rate_rand" type="number" step="0.00000001" min="0.00000001" value="<?= h(number_format((float)$manualRandRate, 8, '.', '')) ?>" required>
          </div>
          <button class="btn" type="submit" name="save_manual_exchange_rates">Save Manual Rates</button>
        </form>

        <form method="POST" style="margin-top:10px;">
          <button class="btn" type="submit" name="use_auto_exchange_rates">Switch to Automatic Online Rates</button>
        </form>
      </div>

      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Currency</th>
              <th>Rate to USD</th>
              <th>Last Updated</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($rateRows)): ?>
              <tr><td colspan="3">No exchange rates available.</td></tr>
            <?php else: ?>
              <?php foreach ($rateRows as $rate): ?>
                <tr>
                  <td><?= h((string)$rate['currency_code']) ?></td>
                  <td class="num"><?= h(number_format((float)$rate['rate_to_base'], 8)) ?></td>
                  <td><?= h((string)$rate['fetched_at']) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel-grid workspace-section" data-group="transactions">
      <article class="panel">
        <h2>Create Learner Invoice</h2>
        <p class="sub">Generate invoices with automatic recurring fees: GPF $20, SSF $20, and SDC $80. Enter Registration Fees and ZIMSEC manually for once-off charges.</p>
        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="invoice_learner_id">Learner</label>
            <input type="search" id="invoice_learner_search" placeholder="Search learner name, class, or reg number...">
            <select id="invoice_learner_id" name="invoice_learner_id" required>
              <option value="">Choose learner</option>
              <?php foreach ($learners as $learner): ?>
                <option value="<?= h($learner['id']) ?>"><?= h($learner['full_name']) ?> - <?= h($learner['class_name']) ?> (<?= h($learner['reg_number']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field">
            <label for="invoice_description">Invoice Description</label>
            <input id="invoice_description" name="invoice_description" placeholder="e.g. Term 3 School Fees" required>
          </div>
          <div class="field">
            <label for="invoice_fee_gpf">GPF Amount (Auto)</label>
            <input id="invoice_fee_gpf" name="invoice_fee_gpf" type="number" step="0.01" min="0" value="20.00" required readonly>
          </div>
          <div class="field">
            <label for="invoice_fee_ssf">SSF Amount (Auto)</label>
            <input id="invoice_fee_ssf" name="invoice_fee_ssf" type="number" step="0.01" min="0" value="20.00" required readonly>
          </div>
          <div class="field">
            <label for="invoice_fee_sdc">SDC Amount (Auto)</label>
            <input id="invoice_fee_sdc" name="invoice_fee_sdc" type="number" step="0.01" min="0" value="80.00" required readonly>
          </div>
          <div class="field">
            <label for="invoice_fee_registration">Registration Fees Amount</label>
            <input id="invoice_fee_registration" name="invoice_fee_registration" type="number" step="0.01" min="0" value="0.00" required>
          </div>
          <div class="field">
            <label for="invoice_fee_zimsec">ZIMSEC Amount</label>
            <input id="invoice_fee_zimsec" name="invoice_fee_zimsec" type="number" step="0.01" min="0" value="0.00" required>
          </div>
          <div class="field">
            <label for="invoice_amount_due">Amount Due (Auto Total)</label>
            <input id="invoice_amount_due" name="invoice_amount_due" type="number" step="0.01" min="0.01" required readonly>
            <small class="sub">Amount Due is calculated as GPF + SSF + SDC + Registration Fees + ZIMSEC.</small>
          </div>
          <div class="field">
            <label for="invoice_due_date">Due Date (Optional)</label>
            <input id="invoice_due_date" name="invoice_due_date" type="date">
          </div>
          <button class="btn" type="submit" name="create_invoice">Create Invoice</button>
        </form>
      </article>

      <article class="panel">
        <h2>Collect Fee Payment</h2>
        <p class="sub">Record all received payments and optionally attach them to invoices. Each payment is auto-allocated by ratio: GPF 20, SSF 20, SDC 80.</p>
        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="payment_learner_id">Learner</label>
            <input type="search" id="payment_learner_search" placeholder="Search learner name, class, or reg number...">
            <select id="payment_learner_id" name="payment_learner_id" required>
              <option value="">Choose learner</option>
              <?php foreach ($learners as $learner): ?>
                <option value="<?= h($learner['id']) ?>"><?= h($learner['full_name']) ?> - <?= h($learner['class_name']) ?> (<?= h($learner['reg_number']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field">
            <label for="payment_invoice_id">Apply to Invoice (Optional)</label>
            <input type="search" id="payment_invoice_search" placeholder="Search invoice number or learner...">
            <select id="payment_invoice_id" name="payment_invoice_id">
              <option value="0">General payment (no specific invoice)</option>
              <?php foreach ($openInvoices as $invoice): ?>
                <?php $invoiceOutstanding = max(0, (float)$invoice['amount_due'] - (float)$invoice['paid_total']); ?>
                <option value="<?= h($invoice['id']) ?>">
                  <?= h($invoice['invoice_number']) ?> - <?= h($invoice['full_name']) ?> - Outstanding $<?= h(number_format($invoiceOutstanding, 2)) ?>
                </option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field">
            <label for="payment_amount">Amount Paid</label>
            <input id="payment_amount" name="payment_amount" type="number" step="0.01" min="0.01" required>
            <small id="paymentAllocationPreview" class="sub">Auto split preview: GPF 0.00 (16.67%) | SSF 0.00 (16.67%) | SDC 0.00 (66.67%)</small>
          </div>
          <div class="field">
            <label for="payment_currency_code">Payment Currency</label>
            <select id="payment_currency_code" name="payment_currency_code" required>
              <option value="USD">USD</option>
              <option value="ZIG">ZIG</option>
              <option value="RAND">RAND</option>
            </select>
          </div>
          <div class="field">
            <label for="payment_date">Payment Date</label>
            <input id="payment_date" name="payment_date" type="date" value="<?= h(date('Y-m-d')) ?>" required>
          </div>
          <div class="field">
            <label for="payment_method">Payment Method</label>
            <select id="payment_method" name="payment_method" required>
              <option value="cash">Cash</option>
              <option value="ecocash">EcoCash</option>
              <option value="bank_transfer">Bank Transfer</option>
              <option value="pos">POS</option>
              <option value="other">Other</option>
            </select>
          </div>
          <div class="field">
            <label for="payment_reference">Receipt Number</label>
            <input id="payment_reference" name="payment_reference" placeholder="Enter manual receipt number" required>
          </div>
          <div class="field">
            <label for="payment_note">Notes (Optional)</label>
            <textarea id="payment_note" name="payment_note" placeholder="Any transaction note..."></textarea>
          </div>
          <button class="btn" type="submit" name="record_payment">Record Payment</button>
        </form>
      </article>
    </section>

    <section class="panel workspace-section" data-group="transactions">
      <h2>Invoice Register</h2>
      <p class="sub">All created invoices with paid amounts and outstanding balances.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Invoice #</th>
              <th>Learner</th>
              <th>Class</th>
              <th>Description</th>
              <th>Amount Due</th>
              <th>GPF</th>
              <th>SSF</th>
              <th>SDC</th>
              <th>Registration Fees</th>
              <th>ZIMSEC</th>
              <th>Paid</th>
              <th>Outstanding</th>
              <th>Due Date</th>
              <th>Status</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($invoiceRows)): ?>
              <tr><td colspan="14">No invoices created yet.</td></tr>
            <?php else: ?>
              <?php foreach ($invoiceRows as $invoice): ?>
                <?php $outstanding = max(0, (float)$invoice['amount_due'] - (float)$invoice['paid_total']); ?>
                <tr>
                  <td><?= h($invoice['invoice_number']) ?></td>
                  <td><?= h($invoice['full_name']) ?> (<?= h($invoice['reg_number']) ?>)</td>
                  <td><?= h($invoice['class_name']) ?></td>
                  <td><?= h($invoice['description']) ?></td>
                  <td class="num">$<?= h(number_format((float)$invoice['amount_due'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)($invoice['fee_gpf'] ?? 0), 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)($invoice['fee_ssf'] ?? 0), 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)($invoice['fee_sdc'] ?? 0), 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)($invoice['fee_registration'] ?? 0), 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)($invoice['fee_zimsec'] ?? 0), 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$invoice['paid_total'], 2)) ?></td>
                  <td class="num">$<?= h(number_format($outstanding, 2)) ?></td>
                  <td><?= h($invoice['due_date'] ?: '-') ?></td>
                  <td><span class="badge"><?= h(str_replace('_', ' ', strtoupper((string)$invoice['status']))) ?></span></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel workspace-section" data-group="transactions" id="paymentTransactionsSection">
      <h2>Payment Transactions</h2>
      <p class="sub">Recent fee collections with source currency and USD converted value for base-ledger consistency.</p>
      <div class="transaction-filter">
        <input type="search" id="paymentSearchInput" placeholder="Search learner, receipt number, invoice...">
        <select id="paymentMethodFilter">
          <option value="">All methods</option>
          <option value="CASH">Cash</option>
          <option value="ECOCASH">EcoCash</option>
          <option value="BANK TRANSFER">Bank Transfer</option>
          <option value="POS">POS</option>
          <option value="OTHER">Other</option>
        </select>
        <select id="paymentCurrencyFilter">
          <option value="">All currencies</option>
          <option value="USD">USD</option>
          <option value="ZIG">ZIG</option>
          <option value="RAND">RAND</option>
        </select>
        <input type="date" id="paymentDateFilter">
      </div>
      <div class="table-wrap">
        <table id="paymentTransactionsTable">
          <thead>
            <tr>
              <th>Date</th>
              <th>Learner</th>
              <th>Class</th>
              <th>Invoice #</th>
              <th>Amount (Original)</th>
              <th>Rate to USD</th>
              <th>Amount (USD)</th>
              <th>Fee Type</th>
              <th>Method</th>
              <th>Receipt No.</th>
              <th>Note</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($paymentRows)): ?>
              <tr><td colspan="11">No payments recorded yet.</td></tr>
            <?php else: ?>
              <?php foreach ($paymentRows as $payment): ?>
                <tr>
                  <td><?= h($payment['payment_date']) ?></td>
                  <td><?= h($payment['full_name']) ?> (<?= h($payment['reg_number']) ?>)</td>
                  <td><?= h($payment['class_name']) ?></td>
                  <td><?= h($payment['invoice_number'] ?: '-') ?></td>
                  <td class="num"><?= h((string)$payment['currency_code']) ?> <?= h(number_format((float)$payment['amount_paid'], 2)) ?></td>
                  <td class="num"><?= h(number_format((float)$payment['fx_rate_to_usd'], 8)) ?></td>
                  <td class="num">$<?= h(number_format((float)($payment['amount_paid_usd'] ?: $payment['amount_paid']), 2)) ?></td>
                  <td><?= h(strtoupper((string)($payment['fee_component'] ?? '-'))) ?></td>
                  <td><?= h(strtoupper(str_replace('_', ' ', (string)$payment['payment_method']))) ?></td>
                  <td><?= h($payment['reference_no'] ?: '-') ?></td>
                  <td><?= h($payment['note'] ?: '-') ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel workspace-section" data-group="ledgercards">
      <h2>Student Ledger Cards</h2>
      <p class="sub">Quick ledger snapshots per learner. Print or download a formatted fees ledger card with FORM mapped to class.</p>

      <div class="ledger-card-actions">
        <div class="field" style="margin:0;">
          <label for="ledgerCardLearnerSearch">Search Learner</label>
          <input id="ledgerCardLearnerSearch" type="search" placeholder="Search learner name, reg number, or class...">
        </div>

        <div class="field" style="margin:0;">
          <label for="ledgerCardLearnerSelect">Select Learner Card</label>
          <select id="ledgerCardLearnerSelect">
            <option value="">Choose learner</option>
            <?php foreach ($ledgerCardRows as $ledgerRow): ?>
              <option value="<?= h((int)$ledgerRow['id']) ?>"><?= h((string)$ledgerRow['full_name']) ?> (<?= h((string)$ledgerRow['reg_number']) ?>) - <?= h((string)$ledgerRow['class_name']) ?></option>
            <?php endforeach; ?>
          </select>
        </div>

        <button class="btn" type="button" id="printLedgerCardBtn">Print Ledger Card</button>
        <button class="btn" type="button" id="downloadLedgerCardBtn">Download Ledger Card</button>
      </div>

      <div class="ledger-card-search">
        <input id="ledgerCardSearchInput" type="search" placeholder="Search learner, reg number, or class...">
      </div>

      <div class="ledger-card-grid" id="ledgerCardGrid">
        <?php if (empty($ledgerCardRows)): ?>
          <article class="ledger-card">
            <h3>No learner ledger cards available.</h3>
            <div class="meta">Create invoices and record payments to populate this tab.</div>
          </article>
        <?php else: ?>
          <?php foreach ($ledgerCardRows as $ledgerRow): ?>
            <?php
              $ledgerInvoiced = (float)$ledgerRow['total_invoiced'];
              $ledgerPaid = (float)$ledgerRow['total_paid'];
              $ledgerOutstanding = max(0, $ledgerInvoiced - $ledgerPaid);
              $ledgerBalanceClass = $ledgerOutstanding <= 0.01 ? 'good' : 'warn';
              $ledgerSearchText = strtolower(trim((string)$ledgerRow['full_name'] . ' ' . (string)$ledgerRow['reg_number'] . ' ' . (string)$ledgerRow['class_name']));
            ?>
            <article class="ledger-card" data-search="<?= h($ledgerSearchText) ?>">
              <div class="ledger-card-head">
                <h3><?= h((string)$ledgerRow['full_name']) ?></h3>
                <span class="ledger-pill"><?= h((string)$ledgerRow['class_name']) ?></span>
              </div>
              <div class="meta">Reg: <?= h((string)$ledgerRow['reg_number']) ?> | Class: <?= h((string)$ledgerRow['class_name']) ?></div>
              <div class="meta">Invoices: <?= h((int)$ledgerRow['invoice_count']) ?> | Payments: <?= h((int)$ledgerRow['payment_count']) ?></div>
              <div class="meta">Last Payment: <?= h((string)($ledgerRow['last_payment_date'] ?: '-')) ?></div>
              <div class="ledger-classic-rule"></div>
              <div class="amount-row"><span>Total Invoiced</span><strong class="num">$<?= h(number_format($ledgerInvoiced, 2)) ?></strong></div>
              <div class="amount-row"><span>Total Paid</span><strong class="num">$<?= h(number_format($ledgerPaid, 2)) ?></strong></div>
              <div class="amount-row"><span>Outstanding</span><strong class="num ledger-balance <?= h($ledgerBalanceClass) ?>">$<?= h(number_format($ledgerOutstanding, 2)) ?></strong></div>
            </article>
          <?php endforeach; ?>
        <?php endif; ?>
      </div>
    </section>

    <section class="panel-grid workspace-section" data-group="expenses">
      <article class="panel">
        <h2>Record Expense</h2>
        <p class="sub">Capture operating expenses with proof upload. Expenses reduce net income.</p>
        <form method="POST" enctype="multipart/form-data" autocomplete="off">
          <div class="field">
            <label for="expense_date">Expense Date</label>
            <input id="expense_date" name="expense_date" type="date" value="<?= h(date('Y-m-d')) ?>" required>
          </div>
          <div class="field">
            <label for="expense_category">Category</label>
            <input id="expense_category" name="expense_category" placeholder="e.g. Utilities, Repairs, Stationery" required>
          </div>
          <div class="field">
            <label for="expense_payee">Payee (Optional)</label>
            <input id="expense_payee" name="expense_payee" placeholder="Supplier or person paid">
          </div>
          <div class="field">
            <label for="expense_description">Description</label>
            <input id="expense_description" name="expense_description" placeholder="What was purchased/paid for" required>
          </div>
          <div class="field">
            <label for="expense_amount">Amount</label>
            <input id="expense_amount" name="expense_amount" type="number" step="0.01" min="0.01" required>
          </div>
          <div class="field">
            <label for="expense_currency_code">Currency</label>
            <select id="expense_currency_code" name="expense_currency_code" required>
              <option value="USD">USD</option>
              <option value="ZIG">ZIG</option>
              <option value="RAND">RAND</option>
            </select>
          </div>
          <div class="field">
            <label for="expense_method">Payment Method (Optional)</label>
            <input id="expense_method" name="expense_method" placeholder="Cash, Transfer, POS, etc.">
          </div>
          <div class="field">
            <label for="expense_reference">Reference (Optional)</label>
            <input id="expense_reference" name="expense_reference" placeholder="Receipt no / transfer ref">
          </div>
          <div class="field">
            <label for="expense_note">Note (Optional)</label>
            <textarea id="expense_note" name="expense_note" placeholder="Extra details"></textarea>
          </div>
          <div class="field">
            <label for="expense_proof">Proof Upload (PDF/JPG/PNG/WEBP, required)</label>
            <input id="expense_proof" name="expense_proof" type="file" accept=".pdf,.jpg,.jpeg,.png,.webp" required>
          </div>
          <button class="btn" type="submit" name="record_expense">Save Expense</button>
        </form>
      </article>

      <article class="panel">
        <h2>Payments Register</h2>
        <p class="sub">Consolidated list of all fee payment receipts with original currency and USD conversion.</p>
        <div class="table-wrap">
          <table id="paymentsRegisterTable">
            <thead>
              <tr>
                <th>Date</th>
                <th>Learner</th>
                <th>Class</th>
                <th>Invoice</th>
                <th>Original</th>
                <th>Rate</th>
                <th>USD</th>
                <th>Fee Type</th>
                <th>Method</th>
                <th>Receipt No.</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($paymentRows)): ?>
                <tr><td colspan="10">No payment records yet.</td></tr>
              <?php else: ?>
                <?php foreach ($paymentRows as $payment): ?>
                  <tr>
                    <td><?= h((string)$payment['payment_date']) ?></td>
                    <td><?= h((string)$payment['full_name']) ?> (<?= h((string)$payment['reg_number']) ?>)</td>
                    <td><?= h((string)$payment['class_name']) ?></td>
                    <td><?= h((string)($payment['invoice_number'] ?: '-')) ?></td>
                    <td class="num"><?= h((string)$payment['currency_code']) ?> <?= h(number_format((float)$payment['amount_paid'], 2)) ?></td>
                    <td class="num"><?= h(number_format((float)$payment['fx_rate_to_usd'], 8)) ?></td>
                    <td class="num">$<?= h(number_format((float)($payment['amount_paid_usd'] ?: $payment['amount_paid']), 2)) ?></td>
                    <td><?= h(strtoupper((string)($payment['fee_component'] ?? '-'))) ?></td>
                    <td><?= h(strtoupper(str_replace('_', ' ', (string)$payment['payment_method']))) ?></td>
                    <td><?= h((string)($payment['reference_no'] ?: '-')) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section class="panel workspace-section" data-group="expenses">
      <h2>Expense Register</h2>
      <p class="sub">Recorded expenses including proof documents and USD base conversion.</p>
      <div class="table-wrap">
        <table id="expenseRegisterTable">
          <thead>
            <tr>
              <th>Date</th>
              <th>Category</th>
              <th>Description</th>
              <th>Original</th>
              <th>Rate</th>
              <th>USD</th>
              <th>Method</th>
              <th>Reference</th>
              <th>Proof</th>
              <th>Recorded By</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($expenseRows)): ?>
              <tr><td colspan="10">No expenses recorded yet.</td></tr>
            <?php else: ?>
              <?php foreach ($expenseRows as $expense): ?>
                <tr>
                  <td><?= h((string)$expense['expense_date']) ?></td>
                  <td><?= h((string)$expense['category']) ?></td>
                  <td><?= h((string)$expense['description']) ?></td>
                  <td class="num"><?= h((string)$expense['currency_code']) ?> <?= h(number_format((float)$expense['amount_original'], 2)) ?></td>
                  <td class="num"><?= h(number_format((float)$expense['fx_rate_to_usd'], 8)) ?></td>
                  <td class="num">$<?= h(number_format((float)$expense['amount_usd'], 2)) ?></td>
                  <td><?= h((string)($expense['payment_method'] ?: '-')) ?></td>
                  <td><?= h((string)($expense['reference_no'] ?: '-')) ?></td>
                  <td>
                    <?php if (!empty($expense['proof_file_path'])): ?>
                      <a href="<?= h((string)$expense['proof_file_path']) ?>" target="_blank" rel="noopener">View Proof</a>
                    <?php else: ?>
                      -
                    <?php endif; ?>
                  </td>
                  <td><?= h((string)($expense['recorded_by_name'] ?: '-')) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel-grid workspace-section" data-group="payroll">
      <article class="panel">
        <h2>Post Ancillary Salary</h2>
        <p class="sub">Maintain the all-staff salary register for ancillary workers. One entry per worker per month.</p>
        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="salary_ancillary_id">Ancillary Staff Member</label>
            <select id="salary_ancillary_id" name="salary_ancillary_id" required>
              <option value="">Choose ancillary staff</option>
              <?php foreach ($ancillaryWorkers as $worker): ?>
                <option value="<?= h((string)$worker['id']) ?>">
                  <?= h((string)$worker['name']) ?>
                  <?php if (!empty($worker['work_profile'])): ?> - <?= h((string)$worker['work_profile']) ?><?php endif; ?>
                </option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field">
            <label for="salary_month">Salary Month</label>
            <input id="salary_month" name="salary_month" type="month" value="<?= h(date('Y-m')) ?>" required>
          </div>
          <div class="field">
            <label for="salary_base">Base Salary (USD)</label>
            <input id="salary_base" name="salary_base" type="number" step="0.01" min="0" required>
          </div>
          <div class="field">
            <label for="salary_allowance">Allowances (USD)</label>
            <input id="salary_allowance" name="salary_allowance" type="number" step="0.01" min="0" value="0.00" required>
          </div>
          <div class="field">
            <label for="salary_deduction">Deductions (USD)</label>
            <input id="salary_deduction" name="salary_deduction" type="number" step="0.01" min="0" value="0.00" required>
          </div>
          <div class="field">
            <label for="salary_pay_date">Pay Date</label>
            <input id="salary_pay_date" name="salary_pay_date" type="date" value="<?= h(date('Y-m-d')) ?>">
          </div>
          <div class="field">
            <label for="salary_note">Note</label>
            <textarea id="salary_note" name="salary_note" placeholder="Optional payroll note..."></textarea>
          </div>
          <button class="btn" type="submit" name="save_ancillary_salary_record">Save Salary Register Entry</button>
        </form>
      </article>

      <article class="panel">
        <div style="display:flex; justify-content:space-between; gap:10px; align-items:center; flex-wrap:wrap;">
          <div>
            <h2 style="margin:0;">Ancillary Salary Register (All Staff)</h2>
            <p class="sub" style="margin:6px 0 0;">Use this register for payroll audits and payslip traceability.</p>
          </div>
          <button type="button" class="btn" style="width:auto;" id="printAncillarySalaryRegisterBtn">Print Register</button>
        </div>
        <div class="table-wrap" style="margin-top:10px;">
          <table id="ancillarySalaryRegisterTable">
            <thead>
              <tr>
                <th>Month</th>
                <th>Worker</th>
                <th>Profile</th>
                <th>Base</th>
                <th>Allowances</th>
                <th>Deductions</th>
                <th>Net</th>
                <th>Pay Date</th>
                <th>Recorded By</th>
                <th>Note</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($ancillarySalaryRows)): ?>
                <tr><td colspan="10">No ancillary salary records yet.</td></tr>
              <?php else: ?>
                <?php foreach ($ancillarySalaryRows as $salary): ?>
                  <tr>
                    <td><?= h((string)$salary['salary_month']) ?></td>
                    <td>
                      <?= h((string)$salary['ancillary_name']) ?><br>
                      <small><?= h((string)$salary['ancillary_email']) ?></small>
                    </td>
                    <td><?= h((string)($salary['work_profile'] ?? '-')) ?></td>
                    <td class="num">$<?= h(number_format((float)$salary['base_salary'], 2)) ?></td>
                    <td class="num">$<?= h(number_format((float)$salary['allowance_amount'], 2)) ?></td>
                    <td class="num">$<?= h(number_format((float)$salary['deduction_amount'], 2)) ?></td>
                    <td class="num"><strong>$<?= h(number_format((float)$salary['net_salary'], 2)) ?></strong></td>
                    <td><?= h((string)($salary['pay_date'] ?? '-')) ?></td>
                    <td><?= h((string)($salary['recorded_by_name'] ?? '-')) ?></td>
                    <td><?= h((string)($salary['note'] ?? '-')) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section class="panel workspace-section" data-group="reports">
      <h2>Financial Reports Workspace</h2>
      <p class="sub">Choose one report at a time to reduce clutter and focus on a single financial view.</p>
      <div class="report-switcher" id="financialReportSwitcher">
        <button class="report-btn active" type="button" data-report-target="reportCashBookPanel">Cash Book</button>
        <button class="report-btn" type="button" data-report-target="reportDebtorsTrialPanel">Debtors and Trial Balance</button>
        <button class="report-btn" type="button" data-report-target="reportBankProfitPanel">Bank Reconciliation and Profit &amp; Loss</button>
        <button class="report-btn" type="button" data-report-target="reportBalanceSheetPanel">Balance Sheet</button>
        <button class="report-btn" type="button" data-report-target="reportLearnerBalancePanel">Learner Balance Summary</button>
        <button class="report-btn" type="button" data-report-target="reportActivityLogPanel">Accountant Activity Log</button>
      </div>
    </section>

    <section id="reportCashBookPanel" class="panel workspace-section financial-report-panel" data-group="reports">
      <h2>Cash Book</h2>
      <p class="sub">All cash movements combining fee income and expenses with running USD balance.</p>
      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printCashBookBtn">Print Cash Book</button>
        <button class="btn" type="button" id="downloadCashBookPdfBtn">Download Cash Book PDF</button>
        <button class="btn" type="button" id="downloadCashBookCsvBtn">Download Cash Book CSV</button>
      </div>
      <div class="table-wrap">
        <table id="cashBookTable">
          <thead>
            <tr>
              <th>Date</th>
              <th>Type</th>
              <th>Description</th>
              <th>Receipt/Reference</th>
              <th>Original Amount</th>
              <th>USD In</th>
              <th>USD Out</th>
              <th>Running USD Balance</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($cashBookRows)): ?>
              <tr><td colspan="8">No cash book entries available.</td></tr>
            <?php else: ?>
              <?php foreach ($cashBookRows as $row): ?>
                <tr>
                  <td><?= h((string)$row['entry_date']) ?></td>
                  <td><?= h((string)$row['entry_type']) ?></td>
                  <td><?= h((string)$row['description']) ?></td>
                  <td><?= h((string)$row['reference']) ?></td>
                  <td class="num"><?= h((string)$row['currency']) ?> <?= h(number_format((float)$row['amount_original'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['money_in_usd'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['money_out_usd'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['balance_usd'], 2)) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="reportDebtorsTrialPanel" class="panel-grid workspace-section financial-report-panel" data-group="reports">
      <article class="panel">
        <h2>Debtors List</h2>
        <p class="sub">Learners with unpaid balances.</p>
        <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
          <button class="btn" type="button" id="printDebtorsBtn">Print Debtors List</button>
          <button class="btn" type="button" id="downloadDebtorsPdfBtn">Download Debtors PDF</button>
          <button class="btn" type="button" id="downloadDebtorsCsvBtn">Download Debtors CSV</button>
        </div>
        <div class="table-wrap">
          <table id="debtorsTable">
            <thead>
              <tr>
                <th>Reg #</th>
                <th>Learner</th>
                <th>Class</th>
                <th>Balance USD</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($debtorsRows)): ?>
                <tr><td colspan="4">No debtors at the moment.</td></tr>
              <?php else: ?>
                <?php foreach ($debtorsRows as $row): ?>
                  <tr>
                    <td><?= h((string)$row['reg_number']) ?></td>
                    <td><?= h((string)$row['learner_name']) ?></td>
                    <td><?= h((string)$row['class_name']) ?></td>
                    <td class="num">$<?= h(number_format((float)$row['balance_usd'], 2)) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>

      <article class="panel">
        <h2>Trial Balance</h2>
        <p class="sub">Simple trial balance snapshot from current income, expenses, debtors, and cash.</p>
        <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
          <button class="btn" type="button" id="printTrialBalanceBtn">Print Trial Balance</button>
          <button class="btn" type="button" id="downloadTrialBalancePdfBtn">Download Trial Balance PDF</button>
          <button class="btn" type="button" id="downloadTrialBalanceCsvBtn">Download Trial Balance CSV</button>
        </div>
        <div class="table-wrap">
          <table id="trialBalanceTable">
            <thead>
              <tr>
                <th>Account</th>
                <th>Debit (USD)</th>
                <th>Credit (USD)</th>
              </tr>
            </thead>
            <tbody>
              <?php foreach ($trialBalanceRows as $row): ?>
                <tr>
                  <td><?= h((string)$row['account']) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['debit'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['credit'], 2)) ?></td>
                </tr>
              <?php endforeach; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="reportBankProfitPanel" class="panel-grid workspace-section financial-report-panel" data-group="reports">
      <article class="panel">
        <h2>Bank Reconciliation Statement</h2>
        <p class="sub">Compare cashbook net balance against statement balance.</p>
        <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
          <button class="btn" type="button" id="printBankRecBtn">Print Bank Reconciliation</button>
          <button class="btn" type="button" id="downloadBankRecPdfBtn">Download Bank Reconciliation PDF</button>
          <button class="btn" type="button" id="downloadBankRecCsvBtn">Download Bank Reconciliation CSV</button>
        </div>
        <div class="table-wrap">
          <table id="bankReconciliationTable">
            <thead>
              <tr>
                <th>Item</th>
                <th>Amount (USD)</th>
              </tr>
            </thead>
            <tbody>
              <?php foreach ($bankReconciliationRows as $row): ?>
                <tr>
                  <td><?= h((string)$row['item']) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['amount_usd'], 2)) ?></td>
                </tr>
              <?php endforeach; ?>
            </tbody>
          </table>
        </div>
      </article>

      <article class="panel">
        <h2>Trading Profit and Loss</h2>
        <p class="sub">Income minus expenses in USD base.</p>
        <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
          <button class="btn" type="button" id="printProfitLossBtn">Print Profit &amp; Loss</button>
          <button class="btn" type="button" id="downloadProfitLossPdfBtn">Download Profit &amp; Loss PDF</button>
          <button class="btn" type="button" id="downloadProfitLossCsvBtn">Download Profit &amp; Loss CSV</button>
        </div>
        <div class="table-wrap">
          <table id="profitLossTable">
            <thead>
              <tr>
                <th>Line Item</th>
                <th>Amount (USD)</th>
              </tr>
            </thead>
            <tbody>
              <?php foreach ($profitLossRows as $row): ?>
                <tr>
                  <td><?= h((string)$row['item']) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['amount_usd'], 2)) ?></td>
                </tr>
              <?php endforeach; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="reportBalanceSheetPanel" class="panel workspace-section financial-report-panel" data-group="reports">
      <h2>Balance Sheet</h2>
      <p class="sub">Snapshot of assets, liabilities, and equity in USD base.</p>
      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printBalanceSheetBtn">Print Balance Sheet</button>
        <button class="btn" type="button" id="downloadBalanceSheetPdfBtn">Download Balance Sheet PDF</button>
        <button class="btn" type="button" id="downloadBalanceSheetCsvBtn">Download Balance Sheet CSV</button>
      </div>
      <div class="table-wrap">
        <table id="balanceSheetTable">
          <thead>
            <tr>
              <th>Section</th>
              <th>Item</th>
              <th>Amount (USD)</th>
            </tr>
          </thead>
          <tbody>
            <?php foreach ($balanceSheetRows as $row): ?>
              <tr>
                <td><?= h((string)$row['section']) ?></td>
                <td><?= h((string)$row['item']) ?></td>
                <td class="num">$<?= h(number_format((float)$row['amount_usd'], 2)) ?></td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="reportLearnerBalancePanel" class="panel workspace-section financial-report-panel" data-group="reports">
      <h2>Learner Balance Summary</h2>
      <p class="sub">Per learner financial position from invoices and payments.</p>
      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printLearnerBalanceSummaryBtn">Print Learner Balance Summary</button>
        <button class="btn" type="button" id="downloadLearnerBalanceSummaryPdfBtn">Download Learner Balance Summary PDF</button>
        <button class="btn" type="button" id="downloadLearnerBalanceSummaryCsvBtn">Download Learner Balance Summary CSV</button>
      </div>
      <div class="table-wrap">
        <table id="learnerBalanceSummaryTable">
          <thead>
            <tr>
              <th>Learner</th>
              <th>Class</th>
              <th>Total Invoiced</th>
              <th>Total Paid</th>
              <th>Balance</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($learnerBalanceRows)): ?>
              <tr><td colspan="5">No learner balances available yet.</td></tr>
            <?php else: ?>
              <?php foreach ($learnerBalanceRows as $row): ?>
                <?php $balance = max(0, (float)$row['total_invoiced'] - (float)$row['total_paid']); ?>
                <tr>
                  <td><?= h($row['full_name']) ?> (<?= h($row['reg_number']) ?>)</td>
                  <td><?= h($row['class_name']) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['total_invoiced'], 2)) ?></td>
                  <td class="num">$<?= h(number_format((float)$row['total_paid'], 2)) ?></td>
                  <td class="num">$<?= h(number_format($balance, 2)) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="reportActivityLogPanel" class="panel workspace-section financial-report-panel" data-group="reports">
      <h2>Accountant Activity Log</h2>
      <p class="sub">Auditable trail of accountant actions (invoices, payments, expenses, inventory and transfer reviews, profile and rate changes).</p>
      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printAccountantLogBtn">Print Activity Log</button>
        <button class="btn" type="button" id="downloadAccountantLogPdfBtn">Download Activity Log PDF</button>
        <button class="btn" type="button" id="downloadAccountantLogCsvBtn">Download Activity Log CSV</button>
      </div>
      <div class="table-wrap">
        <table id="accountantActivityLogTable">
          <thead>
            <tr>
              <th>Time</th>
              <th>Accountant</th>
              <th>Action</th>
              <th>Details</th>
              <th>Entity</th>
              <th>IP</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($accountantActivityRows)): ?>
              <tr><td colspan="6">No accountant activity logged yet.</td></tr>
            <?php else: ?>
              <?php foreach ($accountantActivityRows as $logRow): ?>
                <tr>
                  <td><?= h((string)($logRow['created_at'] ?? '')) ?></td>
                  <td>
                    <?= h((string)($logRow['actor_name'] ?? '-')) ?><br>
                    <small><?= h((string)($logRow['actor_email'] ?? '')) ?></small>
                  </td>
                  <td><?= h((string)($logRow['action'] ?? '-')) ?></td>
                  <td><?= h((string)($logRow['details'] ?? '-')) ?></td>
                  <td><?= h((string)($logRow['entity_type'] ?? '-')) ?><?= !empty($logRow['entity_id']) ? ' #' . h((string)$logRow['entity_id']) : '' ?></td>
                  <td><?= h((string)($logRow['ip_address'] ?? '-')) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel workspace-section" data-group="inventory">
      <h2>Inventory and Assets Workspace</h2>
      <p class="sub">Choose one inventory view at a time for a cleaner and focused workflow.</p>
      <div class="inventory-switcher" id="inventoryPanelSwitcher">
        <button class="inventory-btn active" type="button" data-inventory-target="inventoryVerificationPanel">Stock-Take Verification</button>
        <button class="inventory-btn" type="button" data-inventory-target="inventoryAuditPanel">Inventory Audit Register</button>
        <button class="inventory-btn" type="button" data-inventory-target="inventoryAssetsPanel">School Assets Register</button>
      </div>
    </section>

    <section id="inventoryVerificationPanel" class="panel workspace-section inventory-panel" data-group="inventory">
      <h2>Teacher Inventory Stock-Take Verification</h2>
      <p class="sub">Review teacher-submitted inventory records, verify through physical stock take, and send feedback back to teacher desk.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Submitted</th>
              <th>Teacher</th>
              <th>Class</th>
              <th>Category</th>
              <th>Item Details</th>
              <th>Recorded Qty</th>
              <th>Verification</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($inventoryPendingRows)): ?>
              <tr><td colspan="7">No inventory records are awaiting stock-take verification.</td></tr>
            <?php else: ?>
              <?php foreach ($inventoryPendingRows as $inventory): ?>
                <tr>
                  <td><?= h($inventory['created_at']) ?></td>
                  <td>
                    <strong><?= h($inventory['teacher_name']) ?></strong><br>
                    <small><?= h($inventory['teacher_email']) ?></small>
                  </td>
                  <td><?= h($inventory['class_name']) ?></td>
                  <td><?= h(inventory_category_label((string)$inventory['category'])) ?></td>
                  <td>
                    <strong><?= h($inventory['item_name']) ?></strong>
                    <?php if (!empty($inventory['item_condition'])): ?><br><small>Condition: <?= h($inventory['item_condition']) ?></small><?php endif; ?>
                    <?php if (!empty($inventory['inventory_note'])): ?><br><small><?= h($inventory['inventory_note']) ?></small><?php endif; ?>
                  </td>
                  <td><?= h((int)$inventory['quantity_recorded']) ?></td>
                  <td>
                    <form method="POST" style="display:grid; gap:6px; min-width: 240px;">
                      <input type="hidden" name="inventory_record_id" value="<?= h($inventory['id']) ?>">
                      <label for="stock_take_quantity_<?= h($inventory['id']) ?>">Physical Count</label>
                      <input id="stock_take_quantity_<?= h($inventory['id']) ?>" name="stock_take_quantity" type="number" min="0" step="1" value="<?= h((int)$inventory['quantity_recorded']) ?>" required>
                      <label for="verification_status_<?= h($inventory['id']) ?>">Status</label>
                      <select id="verification_status_<?= h($inventory['id']) ?>" name="verification_status" required>
                        <option value="verified">Verified</option>
                        <option value="discrepancy">Discrepancy</option>
                      </select>
                      <label for="inventory_review_<?= h($inventory['id']) ?>">Review Note</label>
                      <textarea id="inventory_review_<?= h($inventory['id']) ?>" name="inventory_review" placeholder="e.g. Two projectors missing power cables"></textarea>
                      <button class="btn" type="submit" name="verify_inventory_record">Send Review to Teacher</button>
                    </form>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="inventoryAuditPanel" class="panel workspace-section inventory-panel" data-group="inventory">
      <h2>Inventory Audit Register</h2>
      <p class="sub">Full inventory trail from teacher submission to accountant verification status.</p>

      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printInventoryAuditBtn">Print Inventory Audit</button>
        <button class="btn" type="button" id="downloadInventoryAuditPdfBtn">Download Inventory Audit PDF</button>
        <button class="btn" type="button" id="downloadInventoryAuditCsvBtn">Download Inventory Audit CSV</button>
      </div>

      <div class="table-wrap">
        <table id="inventoryAuditTable">
          <thead>
            <tr>
              <th>Submitted</th>
              <th>Teacher</th>
              <th>Class</th>
              <th>Category</th>
              <th>Item</th>
              <th>Recorded Qty</th>
              <th>Stock-Take Qty</th>
              <th>Status</th>
              <th>Review</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($inventoryAllRows)): ?>
              <tr><td colspan="9">No inventory audit records available yet.</td></tr>
            <?php else: ?>
              <?php foreach ($inventoryAllRows as $inventory): ?>
                <tr>
                  <td><?= h($inventory['created_at']) ?></td>
                  <td>
                    <strong><?= h($inventory['teacher_name']) ?></strong><br>
                    <small><?= h($inventory['teacher_email']) ?></small>
                  </td>
                  <td><?= h($inventory['class_name']) ?></td>
                  <td><?= h(inventory_category_label((string)$inventory['category'])) ?></td>
                  <td>
                    <strong><?= h($inventory['item_name']) ?></strong>
                    <?php if (!empty($inventory['item_condition'])): ?><br><small>Condition: <?= h($inventory['item_condition']) ?></small><?php endif; ?>
                    <?php if (!empty($inventory['inventory_note'])): ?><br><small><?= h($inventory['inventory_note']) ?></small><?php endif; ?>
                  </td>
                  <td><?= h((int)$inventory['quantity_recorded']) ?></td>
                  <td><?= h($inventory['stock_take_quantity'] !== null ? (int)$inventory['stock_take_quantity'] : '-') ?></td>
                  <td><span class="badge"><?= h(str_replace('_', ' ', ucfirst((string)$inventory['status']))) ?></span></td>
                  <td>
                    <?php if (!empty($inventory['accountant_review'])): ?>
                      <?= nl2br(h($inventory['accountant_review'])) ?>
                      <?php if (!empty($inventory['reviewed_at'])): ?><br><small><?= h($inventory['reviewed_at']) ?></small><?php endif; ?>
                      <?php if (!empty($inventory['reviewer_name'])): ?><br><small>By: <?= h($inventory['reviewer_name']) ?></small><?php endif; ?>
                    <?php else: ?>
                      <span class="tiny">No review note.</span>
                    <?php endif; ?>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="inventoryAssetsPanel" class="panel workspace-section inventory-panel" data-group="inventory">
      <h2>School Assets Register</h2>
      <p class="sub">Approved inventory records are published here as official school assets and shared with admin desk.</p>

      <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:10px;">
        <button class="btn" type="button" id="printSchoolAssetsBtn">Print School Assets Register</button>
        <button class="btn" type="button" id="downloadSchoolAssetsPdfBtn">Download School Assets PDF</button>
        <button class="btn" type="button" id="downloadSchoolAssetsCsvBtn">Download School Assets CSV</button>
      </div>

      <div class="table-wrap">
        <table id="schoolAssetsTable">
          <thead>
            <tr>
              <th>Approved On</th>
              <th>Teacher</th>
              <th>Class</th>
              <th>Category</th>
              <th>Asset Item</th>
              <th>Quantity</th>
              <th>Condition</th>
              <th>Source Record</th>
              <th>Approved By</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($schoolAssetsRows)): ?>
              <tr><td colspan="9">No approved assets have been published yet.</td></tr>
            <?php else: ?>
              <?php foreach ($schoolAssetsRows as $asset): ?>
                <tr>
                  <td><?= h($asset['approved_at'] ?: $asset['created_at']) ?></td>
                  <td>
                    <strong><?= h($asset['teacher_name']) ?></strong><br>
                    <small><?= h($asset['teacher_email']) ?></small>
                  </td>
                  <td><?= h($asset['class_name']) ?></td>
                  <td><?= h(inventory_category_label((string)$asset['category'])) ?></td>
                  <td>
                    <strong><?= h($asset['item_name']) ?></strong>
                    <?php if (!empty($asset['inventory_note'])): ?><br><small><?= h($asset['inventory_note']) ?></small><?php endif; ?>
                  </td>
                  <td><?= h((int)$asset['quantity']) ?></td>
                  <td><?= h($asset['item_condition'] ?: '-') ?></td>
                  <td>#<?= h((int)$asset['source_inventory_id']) ?></td>
                  <td><?= h($asset['approver_name'] ?: '-') ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section class="panel workspace-section" data-group="transfers">
      <h2>Learner Transfer Clearance Desk</h2>
      <p class="sub">Review financial clearance for transfer requests once admin starts the clearance process.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Requested</th>
              <th>Learner</th>
              <th>Parent</th>
              <th>Destination</th>
              <th>Teacher Status</th>
              <th>Accounts Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($transferRequestsForAccounts)): ?>
              <tr><td colspan="7">No transfer requests recorded yet.</td></tr>
            <?php else: ?>
              <?php foreach ($transferRequestsForAccounts as $transfer): ?>
                <tr>
                  <td><?= h($transfer['requested_at']) ?></td>
                  <td><?= h($transfer['learner_name']) ?><br><small><?= h($transfer['reg_number']) ?> | <?= h($transfer['class_name']) ?></small></td>
                  <td><?= h($transfer['parent_name']) ?></td>
                  <td><?= h($transfer['destination_school']) ?><br><small><?= h($transfer['reason']) ?></small></td>
                  <td><span class="badge"><?= h(ucfirst((string)$transfer['teacher_status'])) ?></span></td>
                  <td>
                    <span class="badge"><?= h(ucfirst((string)$transfer['accountant_status'])) ?></span>
                    <?php if (!empty($transfer['accountant_comment'])): ?><br><small><?= h($transfer['accountant_comment']) ?></small><?php endif; ?>
                  </td>
                  <td>
                    <?php if ($transfer['status'] === 'clearance_requested' && $transfer['accountant_status'] === 'pending'): ?>
                      <form method="POST" style="display:grid;gap:6px;min-width:230px;">
                        <input type="hidden" name="transfer_request_id" value="<?= h($transfer['id']) ?>">
                        <input type="text" name="accountant_transfer_comment" placeholder="Comment (optional)">
                        <input type="hidden" name="accountant_transfer_decision" value="approve">
                        <div style="display:flex;gap:6px;">
                          <button class="btn" type="submit" name="review_transfer_clearance_accountant" onclick="this.form.accountant_transfer_decision.value='approve'">Approve</button>
                          <button class="btn" type="submit" name="review_transfer_clearance_accountant" onclick="this.form.accountant_transfer_decision.value='reject'">Reject</button>
                        </div>
                      </form>
                    <?php else: ?>
                      <span class="sub">No action required.</span>
                    <?php endif; ?>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

      </main>
    </div>
  </div>

  <script>
    const isAdminReadOnlyView = <?= $isAdminReadOnlyView ? 'true' : 'false' ?>;

    const navButtons = Array.from(document.querySelectorAll('.nav-btn[data-group]'));
    const workspaceSections = Array.from(document.querySelectorAll('.workspace-section[data-group]'));
    const accountantDeskProgressChip = document.getElementById('accountantDeskProgressChip');
    const reportNavButtons = Array.from(document.querySelectorAll('.report-btn[data-report-target]'));
    const reportPanels = Array.from(document.querySelectorAll('.financial-report-panel[data-group="reports"]'));
    let activeReportPanelId = reportPanels.length ? reportPanels[0].id : '';
    const inventoryNavButtons = Array.from(document.querySelectorAll('.inventory-btn[data-inventory-target]'));
    const inventoryPanels = Array.from(document.querySelectorAll('.inventory-panel[data-group="inventory"]'));
    let activeInventoryPanelId = inventoryPanels.length ? inventoryPanels[0].id : '';
    const ledgerCardSearchInput = document.getElementById('ledgerCardSearchInput');
    const ledgerCardLearnerSearch = document.getElementById('ledgerCardLearnerSearch');
    const ledgerCardLearnerSelect = document.getElementById('ledgerCardLearnerSelect');
    const printLedgerCardBtn = document.getElementById('printLedgerCardBtn');
    const downloadLedgerCardBtn = document.getElementById('downloadLedgerCardBtn');
    const ledgerCards = Array.from(document.querySelectorAll('#ledgerCardGrid .ledger-card[data-search]'));
    const ledgerCardDataset = <?= json_encode($ledgerCardRows, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const ledgerInvoiceDataset = <?= json_encode($invoiceRows, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const ledgerPaymentDataset = <?= json_encode($paymentRows, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;

    function activateReportPanel(panelId) {
      if (!reportPanels.length) {
        return;
      }

      const targetId = reportPanels.some(panel => panel.id === panelId)
        ? panelId
        : reportPanels[0].id;

      reportPanels.forEach(panel => {
        panel.classList.toggle('report-hidden', panel.id !== targetId);
      });

      reportNavButtons.forEach(btn => {
        btn.classList.toggle('active', (btn.dataset.reportTarget || '') === targetId);
      });

      activeReportPanelId = targetId;
    }

    function activateInventoryPanel(panelId) {
      if (!inventoryPanels.length) {
        return;
      }

      const targetId = inventoryPanels.some(panel => panel.id === panelId)
        ? panelId
        : inventoryPanels[0].id;

      inventoryPanels.forEach(panel => {
        panel.classList.toggle('inventory-hidden', panel.id !== targetId);
      });

      inventoryNavButtons.forEach(btn => {
        btn.classList.toggle('active', (btn.dataset.inventoryTarget || '') === targetId);
      });

      activeInventoryPanelId = targetId;
    }

    function activateWorkspaceGroup(groupName) {
      const normalizedGroup = groupName === 'all' ? 'overview' : groupName;

      workspaceSections.forEach(section => {
        section.classList.remove('hidden');
      });
      
      workspaceSections.forEach(section => {
        const group = section.dataset.group || '';
        const visible = normalizedGroup === 'overview' ? group === 'overview' || group === 'profile' : group === normalizedGroup;
        if (!visible) {
          section.classList.add('hidden');
        }
      });

      if (normalizedGroup === 'reports') {
        activateReportPanel(activeReportPanelId);
      }

      if (normalizedGroup === 'inventory') {
        activateInventoryPanel(activeInventoryPanelId);
      }

      // Explicitly remove active class from ALL buttons
      navButtons.forEach(btn => {
        btn.classList.remove('active');
      });
      
      // Explicitly add active class to matching buttons
      navButtons.forEach(btn => {
        const btnGroup = btn.dataset.group || '';
        if (btnGroup === normalizedGroup || (btnGroup === 'all' && normalizedGroup === 'overview')) {
          btn.classList.add('active');
        }
      });

      const progressButtons = navButtons.filter(btn => (btn.dataset.group || '') !== 'all');
      const activeIndex = progressButtons.findIndex(btn => btn.classList.contains('active'));
      if (accountantDeskProgressChip && activeIndex >= 0) {
        const activeBtn = progressButtons[activeIndex] || null;
        const activeLabel = String(activeBtn?.childNodes?.[0]?.textContent || activeBtn?.textContent || 'Current Section').trim().replace(/\s+/g, ' ');
        accountantDeskProgressChip.textContent = `Step ${activeIndex + 1} of ${progressButtons.length} | ${activeLabel}`;
      }
    }

    navButtons.forEach(btn => {
      btn.addEventListener('click', function () {
        activateWorkspaceGroup(this.dataset.group || 'overview');
      });
    });

    reportNavButtons.forEach(btn => {
      btn.addEventListener('click', function () {
        const target = String(this.dataset.reportTarget || '').trim();
        if (target !== '') {
          activateReportPanel(target);
        }
      });
    });

    inventoryNavButtons.forEach(btn => {
      btn.addEventListener('click', function () {
        const target = String(this.dataset.inventoryTarget || '').trim();
        if (target !== '') {
          activateInventoryPanel(target);
        }
      });
    });

    if (ledgerCardSearchInput && ledgerCards.length > 0) {
      ledgerCardSearchInput.addEventListener('input', function () {
        const term = String(this.value || '').trim().toLowerCase();
        ledgerCards.forEach(card => {
          const haystack = String(card.dataset.search || '');
          card.style.display = term === '' || haystack.includes(term) ? '' : 'none';
        });
      });
    }

    wireSelectSearch(ledgerCardLearnerSearch, ledgerCardLearnerSelect, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

    function ledgerTermFromDate(dateString) {
      const raw = String(dateString || '').trim();
      if (raw === '') {
        return '';
      }
      const monthNum = Number(raw.slice(5, 7));
      if (!Number.isFinite(monthNum) || monthNum <= 0) {
        return '';
      }
      if (monthNum <= 4) {
        return 'TERM 1';
      }
      if (monthNum <= 8) {
        return 'TERM 2';
      }
      return 'TERM 3';
    }

    function ledgerYearFromDate(dateString) {
      const raw = String(dateString || '').trim();
      return /^\d{4}/.test(raw) ? raw.slice(0, 4) : '';
    }

    function ledgerEscape(value) {
      return String(value ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    }

    function getLedgerCardByLearnerId(learnerId) {
      return ledgerCardDataset.find(row => Number(row.id || 0) === Number(learnerId || 0)) || null;
    }

    function buildLedgerEntries(learnerId) {
      const targetLearnerId = Number(learnerId || 0);
      if (targetLearnerId <= 0) {
        return [];
      }

      const invoiceEntries = ledgerInvoiceDataset
        .filter(row => Number(row.learner_id || 0) === targetLearnerId)
        .map(row => {
          const txDate = String(row.created_at || row.due_date || '').slice(0, 10);
          return {
            formClass: String(row.class_name || ''),
            date: txDate,
            description: String(row.description || 'Invoice charge'),
            invoiceNo: String(row.invoice_number || '-'),
            receiptNo: '',
            term: ledgerTermFromDate(txDate),
            year: ledgerYearFromDate(txDate),
            dr: Number(row.amount_due || 0),
            cr: 0,
            sortRank: 1
          };
        });

      const paymentGroupMap = new Map();
      ledgerPaymentDataset
        .filter(row => Number(row.learner_id || 0) === targetLearnerId)
        .forEach(row => {
          const txDate = String(row.payment_date || row.created_at || '').slice(0, 10);
          const receiptNo = String(row.reference_no || '').trim();
          const amountUsd = Number(row.amount_paid_usd || row.amount_paid || 0);
          const invoiceNo = String(row.invoice_number || '-');
          const method = String(row.payment_method || '').toUpperCase().replace(/_/g, ' ');
          const currency = String(row.currency_code || 'USD').toUpperCase();
          const paymentId = Number(row.id || 0);
          const groupKey = receiptNo !== ''
            ? ['R', txDate, receiptNo, invoiceNo, method, currency].join('|')
            : ['I', String(paymentId)].join('|');

          if (!paymentGroupMap.has(groupKey)) {
            paymentGroupMap.set(groupKey, {
              formClass: String(row.class_name || ''),
              date: txDate,
              invoiceNo,
              receiptNo,
              method,
              currency,
              term: ledgerTermFromDate(txDate),
              year: ledgerYearFromDate(txDate),
              cr: 0,
              components: []
            });
          }

          const group = paymentGroupMap.get(groupKey);
          if (group) {
            const component = String(row.fee_component || '').toUpperCase().trim();
            if (component !== '' && !group.components.includes(component)) {
              group.components.push(component);
            }
            group.cr += amountUsd;
          }
        });

      const paymentEntries = Array.from(paymentGroupMap.values()).map(group => {
        const componentLabel = group.components.length ? group.components.join('/') : 'GENERAL';
        return {
          formClass: group.formClass,
          date: group.date,
          description: `Payment ${componentLabel} ${group.method} (${group.currency})`.trim(),
          invoiceNo: group.invoiceNo,
          receiptNo: group.receiptNo,
          term: group.term,
          year: group.year,
          dr: 0,
          cr: group.cr,
          sortRank: 2
        };
      });

      const merged = invoiceEntries.concat(paymentEntries);
      merged.sort((a, b) => {
        const dateA = String(a.date || '');
        const dateB = String(b.date || '');
        if (dateA < dateB) return -1;
        if (dateA > dateB) return 1;
        return Number(a.sortRank || 0) - Number(b.sortRank || 0);
      });

      let runningBalance = 0;
      return merged.map(entry => {
        runningBalance += Number(entry.dr || 0) - Number(entry.cr || 0);
        return {
          ...entry,
          balance: runningBalance
        };
      });
    }

    function buildLedgerCardMarkup(learner, entries) {
      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath;
      const outstandingTotal = entries.length > 0
        ? Math.max(0, Number(entries[entries.length - 1]?.balance || 0))
        : 0;
      const tableRows = [];

      if (entries.length === 0) {
        tableRows.push(`
          <tr>
            <td colspan="10" style="text-align:center; color:#64748b;">No ledger entries recorded yet.</td>
          </tr>
        `);
      } else {
        entries.forEach(entry => {
          tableRows.push(`
            <tr>
              <td>${ledgerEscape(entry.formClass || learner.class_name || '')}</td>
              <td>${ledgerEscape(entry.date || '')}</td>
              <td>${ledgerEscape(entry.description || '')}</td>
              <td>${ledgerEscape(entry.invoiceNo || '')}</td>
              <td>${ledgerEscape(entry.receiptNo || '')}</td>
              <td>${ledgerEscape(entry.term || '')}</td>
              <td>${ledgerEscape(entry.year || '')}</td>
              <td style="text-align:right;">${Number(entry.dr || 0).toFixed(2)}</td>
              <td style="text-align:right;">${Number(entry.cr || 0).toFixed(2)}</td>
              <td style="text-align:right;">${Number(entry.balance || 0).toFixed(2)}</td>
            </tr>
          `);
        });
      }

      return `
        <html>
          <head>
            <title>${ledgerEscape(reportMeta.schoolName)} - Fees Ledger Card</title>
            <style>
              @page { size: A4 portrait; margin: 8mm; }
              body {
                font-family: 'Segoe UI', Tahoma, sans-serif;
                color: #172033;
                margin: 0;
                background: linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
              }
              .page-frame {
                position: fixed;
                inset: 2mm;
                border: 0.8px solid #c7d2e5;
                border-radius: 8px;
                pointer-events: none;
                z-index: 0;
              }
              .sheet {
                width: 190mm;
                margin: 0 auto;
                border: 1px solid #1f2937;
                border-radius: 10px;
                padding: 8px;
                background: #fff;
                box-shadow: 0 8px 24px rgba(15, 23, 42, 0.1);
              }
              .head {
                display: grid;
                grid-template-columns: 46px 1fr;
                gap: 8px;
                align-items: center;
                border-bottom: 2px solid #1f2937;
                padding-bottom: 6px;
              }
              .head img { width: 42px; height: 42px; object-fit: contain; border: 1px solid #9ca3af; }
              .head .title-top {
                text-align: center;
                font-size: 12px;
                font-weight: 800;
                letter-spacing: 0.5px;
                color: #7a5a2a;
              }
              .head .school {
                text-align: center;
                font-size: 31px;
                font-weight: 800;
                letter-spacing: 0.4px;
                font-family: Georgia, 'Times New Roman', serif;
                color: #12386d;
              }
              .head .address { text-align: center; font-size: 13px; margin-top: 2px; }
              .ledger-total {
                margin-top: 7px;
                border: 1px solid #fecaca;
                background: linear-gradient(120deg, #fff1f2 0%, #ffe4e6 100%);
                color: #991b1b;
                font-size: 24px;
                font-weight: 900;
                border-radius: 8px;
                padding: 10px 12px;
                text-align: center;
                line-height: 1.2;
                letter-spacing: 0.3px;
              }
              .info { margin-top: 8px; display: grid; gap: 5px; font-size: 12px; }
              .info-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 8px; }
              .line { border-bottom: 1px dotted #374151; min-height: 16px; display: flex; align-items: center; }
              .line strong { margin-right: 4px; }
              table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 10.8px; }
              th, td { border: 1px solid #111827; padding: 4px; }
              th {
                background: linear-gradient(180deg, #eef3ff 0%, #dbe6ff 100%);
                color: #12386d;
                font-size: 10px;
                text-transform: uppercase;
                letter-spacing: 0.3px;
              }
              tbody tr:nth-child(even) td { background: #f9fbff; }
              th:nth-child(1) { width: 9%; }
              th:nth-child(2) { width: 10%; }
              th:nth-child(3) { width: 25%; }
              th:nth-child(4) { width: 9%; }
              th:nth-child(5) { width: 9%; }
              th:nth-child(6) { width: 7%; }
              th:nth-child(7) { width: 7%; }
              th:nth-child(8) { width: 8%; }
              th:nth-child(9) { width: 8%; }
              th:nth-child(10) { width: 8%; }
            </style>
          </head>
          <body>
            <div class="page-frame"></div>
            <div class="sheet">
              <div class="head">
                <img src="${ledgerEscape(logoSrc)}" alt="School logo">
                <div>
                  <div class="title-top">FEES LEDGER CARD</div>
                  <div class="school">${ledgerEscape(reportMeta.schoolName)}</div>
                  <div class="address">${ledgerEscape(String(reportMeta.schoolAddress || '').replace(/^P\.O\.?Box\s*/i, 'Box '))}</div>
                </div>
              </div>
              <div class="ledger-total">Outstanding Balance: $${outstandingTotal.toFixed(2)}</div>

              <div class="info">
                <div class="info-row">
                  <div class="line"><strong>NAME OF PUPIL:</strong>${ledgerEscape(learner.full_name || '')}</div>
                  <div class="line"><strong>SEX:</strong></div>
                  <div class="line"><strong>D.O.B:</strong></div>
                  <div class="line"><strong>CLASS:</strong>${ledgerEscape(learner.class_name || '')}</div>
                </div>
                <div class="info-row">
                  <div class="line"><strong>ADMISSION NO.:</strong>${ledgerEscape(learner.reg_number || '')}</div>
                  <div class="line"><strong>DATE OF ADMISSION:</strong></div>
                  <div class="line"><strong>ADDRESS:</strong></div>
                  <div class="line"><strong>EMAIL:</strong>-</div>
                </div>
                <div class="info-row">
                  <div class="line"><strong>NAME OF PARENT:</strong></div>
                  <div class="line"><strong>CELL:</strong></div>
                  <div class="line"><strong>ID NO.:</strong></div>
                  <div class="line"></div>
                </div>
              </div>

              <table>
                <thead>
                  <tr>
                    <th>FORM</th>
                    <th>DATE</th>
                    <th>DESCRIPTION</th>
                    <th>INVOICE NO.</th>
                    <th>RECEIPT NO.</th>
                    <th>TERM</th>
                    <th>YEAR</th>
                    <th>DR</th>
                    <th>CR</th>
                    <th>BALANCE</th>
                  </tr>
                </thead>
                <tbody>
                  ${tableRows.join('')}
                </tbody>
              </table>
            </div>
          </body>
        </html>
      `;
    }

    function openLedgerCardWindow(mode) {
      const learnerId = Number(ledgerCardLearnerSelect?.value || 0);
      if (learnerId <= 0) {
        window.alert('Choose a learner first.');
        return;
      }

      const learner = getLedgerCardByLearnerId(learnerId);
      if (!learner) {
        window.alert('Selected learner could not be found.');
        return;
      }

      const entries = buildLedgerEntries(learnerId);
      const html = buildLedgerCardMarkup(learner, entries);

      if (mode === 'print') {
        const win = window.open('', '_blank');
        if (!win) {
          window.alert('Popup blocked. Please allow popups and try again.');
          return;
        }
        win.document.write(html);
        win.document.close();
        win.focus();
        win.print();
        return;
      }

      const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = `${schoolFilePrefix}_${String(learner.reg_number || 'ledger_card').toLowerCase()}_fees_ledger_card.html`;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(url);
    }

    if (printLedgerCardBtn) {
      printLedgerCardBtn.addEventListener('click', function () {
        openLedgerCardWindow('print');
      });
    }

    if (downloadLedgerCardBtn) {
      downloadLedgerCardBtn.addEventListener('click', function () {
        openLedgerCardWindow('download');
      });
    }

    activateWorkspaceGroup('overview');

    if (isAdminReadOnlyView) {
      Array.from(document.querySelectorAll('form[method="POST"], form[method="post"]')).forEach(form => {
        form.addEventListener('submit', function (event) {
          event.preventDefault();
          window.alert('Admin preview mode is read-only.');
        });

        Array.from(form.querySelectorAll('button[type="submit"], input[type="submit"]')).forEach(btn => {
          btn.disabled = true;
          btn.title = 'Disabled in admin read-only preview mode';
        });
      });
    }

    const inventoryAuditTable = document.getElementById('inventoryAuditTable');
    const schoolAssetsTable = document.getElementById('schoolAssetsTable');
    const paymentTransactionsTable = document.getElementById('paymentTransactionsTable');
    const cashBookTable = document.getElementById('cashBookTable');
    const debtorsTable = document.getElementById('debtorsTable');
    const learnerBalanceSummaryTable = document.getElementById('learnerBalanceSummaryTable');
    const trialBalanceTable = document.getElementById('trialBalanceTable');
    const bankReconciliationTable = document.getElementById('bankReconciliationTable');
    const profitLossTable = document.getElementById('profitLossTable');
    const balanceSheetTable = document.getElementById('balanceSheetTable');
    const accountantActivityLogTable = document.getElementById('accountantActivityLogTable');
    const ancillarySalaryRegisterTable = document.getElementById('ancillarySalaryRegisterTable');

    const printInventoryAuditBtn = document.getElementById('printInventoryAuditBtn');
    const downloadInventoryAuditPdfBtn = document.getElementById('downloadInventoryAuditPdfBtn');
    const downloadInventoryAuditCsvBtn = document.getElementById('downloadInventoryAuditCsvBtn');

    const printSchoolAssetsBtn = document.getElementById('printSchoolAssetsBtn');
    const downloadSchoolAssetsPdfBtn = document.getElementById('downloadSchoolAssetsPdfBtn');
    const downloadSchoolAssetsCsvBtn = document.getElementById('downloadSchoolAssetsCsvBtn');

    const printCashBookBtn = document.getElementById('printCashBookBtn');
    const downloadCashBookPdfBtn = document.getElementById('downloadCashBookPdfBtn');
    const downloadCashBookCsvBtn = document.getElementById('downloadCashBookCsvBtn');

    const printDebtorsBtn = document.getElementById('printDebtorsBtn');
    const downloadDebtorsPdfBtn = document.getElementById('downloadDebtorsPdfBtn');
    const downloadDebtorsCsvBtn = document.getElementById('downloadDebtorsCsvBtn');

    const printLearnerBalanceSummaryBtn = document.getElementById('printLearnerBalanceSummaryBtn');
    const downloadLearnerBalanceSummaryPdfBtn = document.getElementById('downloadLearnerBalanceSummaryPdfBtn');
    const downloadLearnerBalanceSummaryCsvBtn = document.getElementById('downloadLearnerBalanceSummaryCsvBtn');

    const printTrialBalanceBtn = document.getElementById('printTrialBalanceBtn');
    const downloadTrialBalancePdfBtn = document.getElementById('downloadTrialBalancePdfBtn');
    const downloadTrialBalanceCsvBtn = document.getElementById('downloadTrialBalanceCsvBtn');

    const printBankRecBtn = document.getElementById('printBankRecBtn');
    const downloadBankRecPdfBtn = document.getElementById('downloadBankRecPdfBtn');
    const downloadBankRecCsvBtn = document.getElementById('downloadBankRecCsvBtn');

    const printProfitLossBtn = document.getElementById('printProfitLossBtn');
    const downloadProfitLossPdfBtn = document.getElementById('downloadProfitLossPdfBtn');
    const downloadProfitLossCsvBtn = document.getElementById('downloadProfitLossCsvBtn');

    const printBalanceSheetBtn = document.getElementById('printBalanceSheetBtn');
    const downloadBalanceSheetPdfBtn = document.getElementById('downloadBalanceSheetPdfBtn');
    const downloadBalanceSheetCsvBtn = document.getElementById('downloadBalanceSheetCsvBtn');

    const printAccountantLogBtn = document.getElementById('printAccountantLogBtn');
    const downloadAccountantLogPdfBtn = document.getElementById('downloadAccountantLogPdfBtn');
    const downloadAccountantLogCsvBtn = document.getElementById('downloadAccountantLogCsvBtn');
    const printAncillarySalaryRegisterBtn = document.getElementById('printAncillarySalaryRegisterBtn');

    const paymentSearchInput = document.getElementById('paymentSearchInput');
    const paymentMethodFilter = document.getElementById('paymentMethodFilter');
    const paymentCurrencyFilter = document.getElementById('paymentCurrencyFilter');
    const paymentDateFilter = document.getElementById('paymentDateFilter');
    const invoiceLearnerSearch = document.getElementById('invoice_learner_search');
    const invoiceLearnerSelect = document.getElementById('invoice_learner_id');
    const invoiceFeeGpfInput = document.getElementById('invoice_fee_gpf');
    const invoiceFeeSsfInput = document.getElementById('invoice_fee_ssf');
    const invoiceFeeSdcInput = document.getElementById('invoice_fee_sdc');
    const invoiceFeeRegistrationInput = document.getElementById('invoice_fee_registration');
    const invoiceFeeZimsecInput = document.getElementById('invoice_fee_zimsec');
    const invoiceAmountDueInput = document.getElementById('invoice_amount_due');
    const paymentLearnerSearch = document.getElementById('payment_learner_search');
    const paymentLearnerSelect = document.getElementById('payment_learner_id');
    const paymentInvoiceSearch = document.getElementById('payment_invoice_search');
    const paymentInvoiceSelect = document.getElementById('payment_invoice_id');
    const paymentAmountInput = document.getElementById('payment_amount');
    const paymentAllocationPreview = document.getElementById('paymentAllocationPreview');
    const recurringInvoiceDefaults = {
      gpf: 20,
      ssf: 20,
      sdc: 80
    };

    function normalizeMoneyInput(rawValue) {
      const parsed = Number(String(rawValue || '').replace(',', '.'));
      if (!Number.isFinite(parsed) || parsed < 0) {
        return 0;
      }
      return parsed;
    }

    function updateInvoiceAmountFromComponents() {
      if (!invoiceAmountDueInput) {
        return;
      }
      const gpf = recurringInvoiceDefaults.gpf;
      const ssf = recurringInvoiceDefaults.ssf;
      const sdc = recurringInvoiceDefaults.sdc;
      if (invoiceFeeGpfInput) {
        invoiceFeeGpfInput.value = gpf.toFixed(2);
      }
      if (invoiceFeeSsfInput) {
        invoiceFeeSsfInput.value = ssf.toFixed(2);
      }
      if (invoiceFeeSdcInput) {
        invoiceFeeSdcInput.value = sdc.toFixed(2);
      }
      const registration = normalizeMoneyInput(invoiceFeeRegistrationInput?.value);
      const zimsec = normalizeMoneyInput(invoiceFeeZimsecInput?.value);
      const total = gpf + ssf + sdc + registration + zimsec;
      invoiceAmountDueInput.value = total.toFixed(2);
    }

    function splitPaymentAllocation(totalAmount) {
      const safeAmount = Number.isFinite(totalAmount) && totalAmount > 0 ? totalAmount : 0;
      const ratioTotal = 20 + 20 + 80;
      const gpf = Math.round((safeAmount * (20 / ratioTotal)) * 100) / 100;
      const ssf = Math.round((safeAmount * (20 / ratioTotal)) * 100) / 100;
      const sdc = Math.round((safeAmount - gpf - ssf) * 100) / 100;
      return { gpf, ssf, sdc };
    }

    function updatePaymentAllocationPreview() {
      if (!paymentAllocationPreview) {
        return;
      }
      const rawAmount = normalizeMoneyInput(paymentAmountInput?.value);
      const allocation = splitPaymentAllocation(rawAmount);
      paymentAllocationPreview.textContent =
        `Auto split preview: GPF ${allocation.gpf.toFixed(2)} (16.67%) | SSF ${allocation.ssf.toFixed(2)} (16.67%) | SDC ${allocation.sdc.toFixed(2)} (66.67%)`;
    }

    [invoiceFeeGpfInput, invoiceFeeSsfInput, invoiceFeeSdcInput, invoiceFeeRegistrationInput, invoiceFeeZimsecInput].forEach(el => {
      if (el) {
        el.addEventListener('input', updateInvoiceAmountFromComponents);
      }
    });
    updateInvoiceAmountFromComponents();

    if (paymentAmountInput) {
      paymentAmountInput.addEventListener('input', updatePaymentAllocationPreview);
      paymentAmountInput.addEventListener('change', updatePaymentAllocationPreview);
    }
    updatePaymentAllocationPreview();

    const reportMeta = {
      schoolName: <?= json_encode($schoolName, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolAddress: <?= json_encode($schoolAddress, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolContact: <?= json_encode($schoolContact, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolMotto: <?= json_encode($schoolMotto, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      palette: {
        ink: <?= json_encode($paletteInk, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        muted: <?= json_encode($paletteMuted, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandNavy: <?= json_encode($paletteBrandNavy, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandNavyDeep: <?= json_encode($paletteBrandNavyDeep, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandIce: <?= json_encode($paletteBrandIce, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        line: <?= json_encode($palettePatchSky, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
      },
      preparedBy: 'Accountant Desk',
      logoDataUri: <?= json_encode($schoolLogoDataUri, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      logoPath: <?= json_encode($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
    };
    const schoolFilePrefix = String(reportMeta.schoolName || 'school')
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '_')
      .replace(/^_+|_+$/g, '') || 'school';

    function getVisibleTableDataset(tableEl) {
      if (!tableEl) {
        return { headers: [], rows: [] };
      }
      const headers = Array.from(tableEl.querySelectorAll('thead th')).map(th => th.textContent.trim());
      const rows = Array.from(tableEl.querySelectorAll('tbody tr'))
        .filter(row => row.style.display !== 'none')
        .map(row => Array.from(row.querySelectorAll('td')).map(td => td.textContent.trim()));
      return { headers, rows };
    }

    function wireSelectSearch(searchEl, selectEl, labels) {
      if (!searchEl || !selectEl) {
        return;
      }

      function applyFilter() {
        const term = searchEl.value.trim().toLowerCase();
        let hasAny = false;
        const visibleOptions = [];
        let changedSelection = false;

        Array.from(selectEl.options).forEach((option, idx) => {
          if (idx === 0) {
            option.style.display = '';
            return;
          }

          const matches = term === '' || option.textContent.toLowerCase().includes(term);
          option.style.display = matches ? '' : 'none';
          if (!matches && option.selected) {
            selectEl.value = String(selectEl.options[0]?.value || '');
            changedSelection = true;
          }
          if (matches) {
            hasAny = true;
            visibleOptions.push(option);
          }
        });

        if (selectEl.options[0]) {
          selectEl.options[0].text = hasAny ? labels.defaultLabel : labels.emptyLabel;
        }

        // When user types and a match exists, auto-populate the dropdown with the best match.
        if (term !== '' && visibleOptions.length > 0) {
          const currentVisible = visibleOptions.some(option => option.value === selectEl.value);
          if (!currentVisible) {
            const startsWithMatch = visibleOptions.find(option => option.textContent.toLowerCase().startsWith(term));
            const nextOption = startsWithMatch || visibleOptions[0];
            if (nextOption && selectEl.value !== nextOption.value) {
              selectEl.value = nextOption.value;
              changedSelection = true;
            }
          }
        }

        if (changedSelection) {
          selectEl.dispatchEvent(new Event('change', { bubbles: true }));
        }
      }

      searchEl.addEventListener('input', applyFilter);
      applyFilter();
    }

    function openReportPreview(modeLabel, tableEl) {
      const dataset = getVisibleTableDataset(tableEl);
      if (!dataset.rows.length) {
        window.alert('No visible data to export.');
        return;
      }

      const reportWindow = window.open('', '_blank');
      if (!reportWindow) {
        window.alert('Popup blocked. Please allow popups and try again.');
        return;
      }

      const generatedAt = new Date().toLocaleString();
      const headerHtml = dataset.headers.map(h => `<th>${h}</th>`).join('');
      const bodyHtml = dataset.rows.map(row => `<tr>${row.map(col => `<td>${col}</td>`).join('')}</tr>`).join('');
      const palette = {
        ink: String(reportMeta?.palette?.ink || '#173122'),
        muted: String(reportMeta?.palette?.muted || '#4F6656'),
        brandNavyDeep: String(reportMeta?.palette?.brandNavyDeep || '#1D6A33'),
        brandIce: String(reportMeta?.palette?.brandIce || '#EEF7EF'),
        line: String(reportMeta?.palette?.line || '#D6EEFF')
      };

      reportWindow.document.write(`
        <html>
          <head>
            <title>${reportMeta.schoolName} - ${modeLabel}</title>
            <style>
              @page { size: A4 portrait; margin: 10mm; }
              body { font-family: Arial, sans-serif; margin: 0; padding: 0; color: ${palette.ink}; }
              .page-frame {
                position: fixed;
                inset: 2mm;
                border: 0.8px solid ${palette.line};
                border-radius: 8px;
                pointer-events: none;
                z-index: 0;
              }
              .print-page { padding: 18px; position: relative; z-index: 1; }
              .head { display:flex; gap:12px; align-items:center; margin-bottom:12px; }
              .logo { width:74px; height:74px; object-fit:contain; border:1px solid ${palette.line}; border-radius:10px; padding:4px; }
              h1 { margin:0; font-size: 20px; color:${palette.brandNavyDeep}; }
              .meta { margin: 3px 0; font-size: 13px; }
              .motto { margin-top: 4px; color:${palette.muted}; font-style: italic; }
              .gen { margin: 10px 0 14px; font-size: 12px; }
              table { width: 100%; border-collapse: collapse; font-size: 12px; }
              th, td { border: 1px solid ${palette.line}; padding: 8px; text-align: left; }
              th { background: ${palette.brandIce}; color: ${palette.brandNavyDeep}; }
            </style>
          </head>
          <body>
            <div class="page-frame"></div>
            <div class="print-page">
              <div class="head">
                <img class="logo" src="${reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath}" alt="School logo">
                <div>
                  <h1>${reportMeta.schoolName}</h1>
                  <div class="meta">${reportMeta.schoolAddress}</div>
                  <div class="meta">${reportMeta.schoolContact}</div>
                  <div class="motto">${reportMeta.schoolMotto}</div>
                </div>
              </div>
              <div class="gen">Report: ${modeLabel} | Prepared By: ${reportMeta.preparedBy} | Generated: ${generatedAt}</div>
              <table>
                <thead><tr>${headerHtml}</tr></thead>
                <tbody>${bodyHtml}</tbody>
              </table>
            </div>
          </body>
        </html>
      `);
      reportWindow.document.close();
      reportWindow.focus();
      reportWindow.print();
    }

    function downloadCsvForTable(tableEl, fileName) {
      const dataset = getVisibleTableDataset(tableEl);
      if (!dataset.rows.length) {
        window.alert('No visible data to export.');
        return;
      }

      const esc = (text) => `"${String(text ?? '').replace(/\s+/g, ' ').trim().replace(/"/g, '""')}"`;
      const lines = [];
      lines.push('sep=,');
      lines.push(dataset.headers.map(esc).join(','));
      dataset.rows.forEach(row => lines.push(row.map(esc).join(',')));

      const csv = '\uFEFF' + lines.join('\n');
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
      const link = document.createElement('a');
      link.href = URL.createObjectURL(blob);
      link.download = fileName;
      link.style.display = 'none';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(link.href);
    }

    function applyPaymentTransactionFilter() {
      if (!paymentTransactionsTable) {
        return;
      }

      const searchValue = String(paymentSearchInput?.value || '').trim().toLowerCase();
      const methodValue = String(paymentMethodFilter?.value || '').trim().toLowerCase();
      const currencyValue = String(paymentCurrencyFilter?.value || '').trim().toLowerCase();
      const dateValue = String(paymentDateFilter?.value || '').trim();

      const bodyRows = Array.from(paymentTransactionsTable.querySelectorAll('tbody tr'));
      bodyRows.forEach(row => {
        const cells = Array.from(row.querySelectorAll('td'));
        if (!cells.length) {
          return;
        }

        const rowText = cells.map(td => td.textContent || '').join(' ').toLowerCase();
        const rowDate = (cells[0]?.textContent || '').trim();
        const rowCurrencyCell = (cells[4]?.textContent || '').toLowerCase();
        const rowMethod = (cells[8]?.textContent || '').toLowerCase();

        const matchSearch = searchValue === '' || rowText.includes(searchValue);
        const matchMethod = methodValue === '' || rowMethod.includes(methodValue);
        const matchCurrency = currencyValue === '' || rowCurrencyCell.includes(currencyValue);
        const matchDate = dateValue === '' || rowDate === dateValue;

        row.style.display = (matchSearch && matchMethod && matchCurrency && matchDate) ? '' : 'none';
      });
    }

    [paymentSearchInput, paymentMethodFilter, paymentCurrencyFilter, paymentDateFilter].forEach(el => {
      if (el) {
        el.addEventListener('input', applyPaymentTransactionFilter);
        el.addEventListener('change', applyPaymentTransactionFilter);
      }
    });

    wireSelectSearch(invoiceLearnerSearch, invoiceLearnerSelect, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

    wireSelectSearch(paymentLearnerSearch, paymentLearnerSelect, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

    wireSelectSearch(paymentInvoiceSearch, paymentInvoiceSelect, {
      defaultLabel: 'General payment (no specific invoice)',
      emptyLabel: 'No matching invoices'
    });

    applyPaymentTransactionFilter();

    if (printInventoryAuditBtn && inventoryAuditTable) {
      printInventoryAuditBtn.addEventListener('click', function () {
        openReportPreview('Inventory Audit Register', inventoryAuditTable);
      });
    }

    if (downloadInventoryAuditPdfBtn && inventoryAuditTable) {
      downloadInventoryAuditPdfBtn.addEventListener('click', function () {
        openReportPreview('Inventory Audit Register PDF Report', inventoryAuditTable);
      });
    }

    if (downloadInventoryAuditCsvBtn && inventoryAuditTable) {
      downloadInventoryAuditCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(inventoryAuditTable, `${schoolFilePrefix}_inventory_audit_register.csv`);
      });
    }

    if (printSchoolAssetsBtn && schoolAssetsTable) {
      printSchoolAssetsBtn.addEventListener('click', function () {
        openReportPreview('School Assets Register', schoolAssetsTable);
      });
    }

    if (printAncillarySalaryRegisterBtn && ancillarySalaryRegisterTable) {
      printAncillarySalaryRegisterBtn.addEventListener('click', function () {
        openReportPreview('Ancillary Salary Register', ancillarySalaryRegisterTable);
      });
    }

    if (printCashBookBtn && cashBookTable) {
      printCashBookBtn.addEventListener('click', function () {
        openReportPreview('Cash Book', cashBookTable);
      });
    }
    if (downloadCashBookPdfBtn && cashBookTable) {
      downloadCashBookPdfBtn.addEventListener('click', function () {
        openReportPreview('Cash Book', cashBookTable);
      });
    }
    if (downloadCashBookCsvBtn && cashBookTable) {
      downloadCashBookCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(cashBookTable, 'cash_book.csv');
      });
    }

    if (printDebtorsBtn && debtorsTable) {
      printDebtorsBtn.addEventListener('click', function () {
        openReportPreview('Debtors List', debtorsTable);
      });
    }
    if (downloadDebtorsPdfBtn && debtorsTable) {
      downloadDebtorsPdfBtn.addEventListener('click', function () {
        openReportPreview('Debtors List', debtorsTable);
      });
    }
    if (downloadDebtorsCsvBtn && debtorsTable) {
      downloadDebtorsCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(debtorsTable, 'debtors_list.csv');
      });
    }

    if (printLearnerBalanceSummaryBtn && learnerBalanceSummaryTable) {
      printLearnerBalanceSummaryBtn.addEventListener('click', function () {
        openReportPreview('Learner Balance Summary', learnerBalanceSummaryTable);
      });
    }
    if (downloadLearnerBalanceSummaryPdfBtn && learnerBalanceSummaryTable) {
      downloadLearnerBalanceSummaryPdfBtn.addEventListener('click', function () {
        openReportPreview('Learner Balance Summary PDF Report', learnerBalanceSummaryTable);
      });
    }
    if (downloadLearnerBalanceSummaryCsvBtn && learnerBalanceSummaryTable) {
      downloadLearnerBalanceSummaryCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(learnerBalanceSummaryTable, `${schoolFilePrefix}_learner_balance_summary.csv`);
      });
    }

    if (printTrialBalanceBtn && trialBalanceTable) {
      printTrialBalanceBtn.addEventListener('click', function () {
        openReportPreview('Trial Balance', trialBalanceTable);
      });
    }
    if (downloadTrialBalancePdfBtn && trialBalanceTable) {
      downloadTrialBalancePdfBtn.addEventListener('click', function () {
        openReportPreview('Trial Balance', trialBalanceTable);
      });
    }
    if (downloadTrialBalanceCsvBtn && trialBalanceTable) {
      downloadTrialBalanceCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(trialBalanceTable, 'trial_balance.csv');
      });
    }

    if (printBankRecBtn && bankReconciliationTable) {
      printBankRecBtn.addEventListener('click', function () {
        openReportPreview('Bank Reconciliation Statement', bankReconciliationTable);
      });
    }
    if (downloadBankRecPdfBtn && bankReconciliationTable) {
      downloadBankRecPdfBtn.addEventListener('click', function () {
        openReportPreview('Bank Reconciliation Statement', bankReconciliationTable);
      });
    }
    if (downloadBankRecCsvBtn && bankReconciliationTable) {
      downloadBankRecCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(bankReconciliationTable, 'bank_reconciliation.csv');
      });
    }

    if (printProfitLossBtn && profitLossTable) {
      printProfitLossBtn.addEventListener('click', function () {
        openReportPreview('Trading Profit and Loss', profitLossTable);
      });
    }
    if (downloadProfitLossPdfBtn && profitLossTable) {
      downloadProfitLossPdfBtn.addEventListener('click', function () {
        openReportPreview('Trading Profit and Loss', profitLossTable);
      });
    }
    if (downloadProfitLossCsvBtn && profitLossTable) {
      downloadProfitLossCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(profitLossTable, 'trading_profit_loss.csv');
      });
    }

    if (printBalanceSheetBtn && balanceSheetTable) {
      printBalanceSheetBtn.addEventListener('click', function () {
        openReportPreview('Balance Sheet', balanceSheetTable);
      });
    }
    if (downloadBalanceSheetPdfBtn && balanceSheetTable) {
      downloadBalanceSheetPdfBtn.addEventListener('click', function () {
        openReportPreview('Balance Sheet', balanceSheetTable);
      });
    }
    if (downloadBalanceSheetCsvBtn && balanceSheetTable) {
      downloadBalanceSheetCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(balanceSheetTable, 'balance_sheet.csv');
      });
    }

    if (printAccountantLogBtn && accountantActivityLogTable) {
      printAccountantLogBtn.addEventListener('click', function () {
        openReportPreview('Accountant Activity Log', accountantActivityLogTable);
      });
    }
    if (downloadAccountantLogPdfBtn && accountantActivityLogTable) {
      downloadAccountantLogPdfBtn.addEventListener('click', function () {
        openReportPreview('Accountant Activity Log', accountantActivityLogTable);
      });
    }
    if (downloadAccountantLogCsvBtn && accountantActivityLogTable) {
      downloadAccountantLogCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(accountantActivityLogTable, `${schoolFilePrefix}_accountant_activity_log.csv`);
      });
    }

    if (downloadSchoolAssetsPdfBtn && schoolAssetsTable) {
      downloadSchoolAssetsPdfBtn.addEventListener('click', function () {
        openReportPreview('School Assets Register PDF Report', schoolAssetsTable);
      });
    }

    if (downloadSchoolAssetsCsvBtn && schoolAssetsTable) {
      downloadSchoolAssetsCsvBtn.addEventListener('click', function () {
        downloadCsvForTable(schoolAssetsTable, `${schoolFilePrefix}_school_assets_register.csv`);
      });
    }
  </script>
  <?php output_select_search_script(); ?>
  <footer style="text-align:center;padding:14px 0 10px;font-size:0.8rem;color:#8a9ab0;opacity:0.7;">Developed by Ngwenya Jonas &copy; 2026</footer>
</body>
</html>
