<?php
require 'connDb.php'; // Ensure this correctly sets $pdo, $dbTable, and $dbName

// IMPORTANT: Double-check that 'id' is indeed your primary key column name in your database.
$primaryKeyColumn = 'id';

// --- Fetch all rows for initial table display ---
$rows = getAllTips($pdo);

// --- Fetch column names and schema details for form generation and validation ---
$columnNames = [];
$columnSchema = []; // This will store detailed schema info (is_nullable, data_type, max_length)

try {
    if (!isset($dbTable) || !isset($dbName)) {
        throw new Exception("Error: \$dbTable or \$dbName variable not set in connDb.php.");
    }
    // Get column names
    $stmt = $pdo->query("DESCRIBE " . $dbTable);
    $columnNames = $stmt->fetchAll(PDO::FETCH_COLUMN);

    // Get detailed column schema for validation
    $stmt = $pdo->prepare("SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = :dbName AND TABLE_NAME = :tableName");
    $stmt->execute([':dbName' => $dbName, ':tableName' => $dbTable]);
    $schemaResult = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($schemaResult as $col) {
        $columnSchema[$col['COLUMN_NAME']] = [
            'is_nullable' => ($col['IS_NULLABLE'] === 'YES'),
            'data_type' => $col['DATA_TYPE'],
            'max_length' => $col['CHARACTER_MAXIMUM_LENGTH']
        ];
    }

} catch (Exception $e) {
    error_log("Error fetching database schema: " . $e->getMessage());
    // Fallback if schema fetch fails: assume all columns are nullable text
    if (empty($columnNames) && !empty($rows)) {
        $columnNames = array_keys($rows[0]);
    }
    foreach ($columnNames as $colName) {
        $columnSchema[$colName] = ['is_nullable' => true, 'data_type' => 'text', 'max_length' => null];
    }
}

// Filter out columns that should NOT be in the add/edit form (e.g., auto-increment ID on add, timestamps)
$formEditableColumns = array_filter($columnNames, function($col) use ($primaryKeyColumn) {
    return $col !== 'created_at' && $col !== 'updated_at' && $col !== $primaryKeyColumn; // Exclude PK for add form
});
foreach ($columnNames as $col) {
    if ($col === 'created_at') {
        $columnSchema[$col]['is_readonly_add'] = true; // Ensure created_at is readonly
        $columnSchema[$col]['default_value_add'] = date('Y-m-d H:i:s'); // Default to current date-time
    }
    if ($col === 'updated_at') {
        $columnSchema[$col]['is_readonly_add'] = false; // Allow updated_at to be editable
        $columnSchema[$col]['default_value_add'] = date('Y-m-d H:i:s'); // Default to current date-time
    }
    if ($col === 'tipMod') {
        $columnSchema[$col]['is_readonly_add'] = true; // Make tipMod readonly
        $columnSchema[$col]['default_value_add'] = date('Y-m-d H:i:s'); // Set to current date-time
    }
}

// Pass default values for add form to JS
$jsDefaultValuesAdd = json_encode(array_reduce($columnNames, function($carry, $col) use ($columnSchema) {
  if (isset($columnSchema[$col]['default_value_add'])) {
    $carry[$col] = $columnSchema[$col]['default_value_add'];
  }
  return $carry;
}, []));
// Pass PHP variables to JavaScript
$jsTableName = json_encode($dbTable);
$jsPrimaryKeyColumn = json_encode($primaryKeyColumn);
$jsFormEditableColumns = json_encode(array_values($formEditableColumns)); // Columns for the ADD form
$jsAllColumnNames = json_encode(array_values($columnNames)); // All columns for the EDIT form display
$jsColumnSchema = json_encode($columnSchema); // Detailed schema for validation
$jsDefaultValuesAdd = json_encode(array_reduce($columnNames, function($carry, $col) use ($columnSchema) {
  if (isset($columnSchema[$col]['default_value_add'])) {
    $carry[$col] = $columnSchema[$col]['default_value_add'];
  }
  return $carry;
}, []));
// Helper function (assuming it's not already in connDb.php)
if (!function_exists('formatCell')) {
    function formatCell($value) {
        if ($value === null) {
            return '<span class="text-muted fst-italic">NULL</span>';
        }
        if (preg_match('/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d{2})?$/', $value)) {
            return '<span class="text-secondary">' . htmlspecialchars($value) . '</span>';
        }
        if (strlen($value) > 100) {
            return htmlspecialchars(substr($value, 0, 100)) . '...';
        }
        return htmlspecialchars($value);
    }
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Data Table Viewer</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet">
  <link href="https://cdn.datatables.net/responsive/2.5.0/css/responsive.bootstrap5.min.css" rel="stylesheet">

  <style>
    td, th {
      word-wrap: break-word;
      white-space: normal;
      max-width: 300px;
    }
    tfoot input {
      width: 100%;
      font-size: 0.875rem;
    }
    tfoot {
      display: table-header-group;
    }
    .toast-container {
      z-index: 1080;
    }
    /* Styles for the loading overlay */
    #loadingOverlay {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(255, 255, 255, 0.8); /* Semi-transparent white */
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999; /* Ensure it's on top of everything */
    }
    .spinner-lg {
      width: 4rem;
      height: 4rem;
      border-width: .4em;
    }
  </style>
</head>
<body class="bg-light">
<div class="container-fluid py-4">
  <h2 class="mb-4"><i class="fas fa-database me-2"></i>Tips Table Viewer</h2>

  <div class="d-flex justify-content-end mb-3">
    <button class="btn btn-primary" id="addNewRecordBtn"><i class="fa-solid fa-plus-circle me-1"></i>Add New Record</button>
  </div>

  <?php if (empty($rows) && empty($columnNames)): ?>
    <div class="alert alert-info text-center">
      No records found and no column information available. Please ensure the table exists or add some data.
    </div>
  <?php elseif (empty($rows) && !empty($columnNames)): ?>
    <div class="alert alert-info text-center">
      No records found. Click "Add New Record" to get started!
    </div>
    <div class="table-responsive">
      <table id="dataTable1" class="table table-striped table-bordered w-100 align-middle">
        <thead class="table-primary text-center">
          <tr>
            <?php foreach ($columnNames as $col): ?>
              <th><?= htmlspecialchars($col) ?></th>
            <?php endforeach; ?>
            <th>Actions</th>
          </tr>
        </thead>
        <tfoot>
          <tr>
            <?php foreach ($columnNames as $col): ?>
              <th><input type="text" placeholder="Search <?= htmlspecialchars($col) ?>" class="form-control form-control-sm" /></th>
            <?php endforeach; ?>
            <th></th>
          </tr>
        </tfoot>
        <tbody>
        </tbody>
      </table>
    </div>
  <?php else: ?>
    <div class="table-responsive">
      <table id="dataTable1" class="table table-striped table-bordered w-100 align-middle">
        <thead class="table-primary text-center">
          <tr>
            <?php foreach ($columnNames as $col): ?>
              <th><?= htmlspecialchars($col) ?></th>
            <?php endforeach; ?>
            <th>Actions</th>
          </tr>
        </thead>
        <tfoot>
          <tr>
            <?php foreach ($columnNames as $col): ?>
              <th><input type="text" placeholder="Search <?= htmlspecialchars($col) ?>" class="form-control form-control-sm" /></th>
            <?php endforeach; ?>
            <th></th>
          </tr>
        </tfoot>
        <tbody>
          <?php foreach ($rows as $row): ?>
            <?php
            // DEBUGGING PHP: Output the PHP array structure to HTML comments
            // echo '';
            ?>
            <tr>
              <?php foreach ($columnNames as $col): ?>
                <td><?= formatCell($row[$col] ?? '') ?></td>
              <?php endforeach; ?>
              <td class="text-center">
                <button class="btn btn-sm btn-info viewEditBtn me-1" data-bs-toggle="tooltip" title="View/Edit"
                        data-row-json='<?= htmlspecialchars(json_encode($row), ENT_QUOTES, 'UTF-8') ?>'>
                  <i class="fas fa-edit"></i>
                </button>
                <button class="btn btn-sm btn-danger deleteRowBtn" data-id='<?= htmlspecialchars($row[$primaryKeyColumn] ?? '') ?>' data-bs-toggle="tooltip" title="Delete">
                  <i class="fas fa-trash-can"></i>
                </button>
              </td>
            </tr>
          <?php endforeach; ?>
        </tbody>
      </table>
    </div>
  <?php endif; ?>
</div>

<div class="modal fade" id="rowModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <form id="modalForm" class="modal-content">
      <div class="modal-header bg-primary text-white">
        <h5 class="modal-title" id="rowModalLabel">Edit Row</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body row g-3" id="modalBodyContent"></div>
      <div class="modal-footer">
        <button type="submit" id="saveChangesBtn" class="btn btn-success" disabled>
          <span class="spinner-border spinner-border-sm d-none me-2" role="status" aria-hidden="true"></span>
          Save Changes
        </button>
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
      </div>
    </form>
  </div>
</div>

<div class="modal fade" id="addModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <form id="addModalForm" class="modal-content needs-validation" novalidate>
      <div class="modal-header bg-success text-white">
        <h5 class="modal-title">Add New Record</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body row g-3" id="addModalBodyContent"></div>
      <div class="modal-footer">
        <button type="submit" id="saveAddBtn" class="btn btn-success">
          <span class="spinner-border spinner-border-sm d-none me-2" role="status" aria-hidden="true"></span>
          Add Record
        </button>
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
      </div>
    </form>
  </div>
</div>

<div class="modal fade" id="deleteConfirmModal" tabindex="-1" aria-labelledby="deleteConfirmModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header bg-danger text-white">
        <h5 class="modal-title" id="deleteConfirmModalLabel">Confirm Deletion</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">
        Are you sure you want to delete record ID: <span id="deleteRecordId" class="fw-bold"></span>?
        This action cannot be undone.
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-danger" id="confirmDeleteBtn">
          <span class="spinner-border spinner-border-sm d-none me-2" role="status" aria-hidden="true"></span>
          Delete
        </button>
      </div>
    </div>
  </div>
</div>


<div class="toast-container position-fixed bottom-0 end-0 p-3">
  <div id="successToast" class="toast align-items-center text-bg-success border-0" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="d-flex">
      <div class="toast-body">
        <i class="fa-solid fa-check-circle me-2"></i>
        <span id="successToastMessage"></span>
      </div>
      <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
  </div>

  <div id="errorToast" class="toast align-items-center text-bg-danger border-0" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="d-flex">
      <div class="toast-body">
        <i class="fa-solid fa-triangle-exclamation me-2"></i>
        <span id="errorToastMessage"></span>
      </div>
      <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
    </div>
  </div>
</div>

<div id="loadingOverlay">
    <div class="spinner-border text-primary spinner-lg" role="status">
        <span class="visually-hidden">Loading...</span>
    </div>
</div>


<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.5.0/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.5.0/js/responsive.bootstrap5.min.js"></script>

<script>
const TABLE_NAME = <?= $jsTableName ?>;
const PRIMARY_KEY_COLUMN = <?= $jsPrimaryKeyColumn ?>;
const EDITABLE_COLUMNS = <?= $jsFormEditableColumns ?>;
const ALL_COLUMN_NAMES = <?= $jsAllColumnNames ?>;
const COLUMN_SCHEMA = <?= $jsColumnSchema ?>;
const DEFAULT_ADD_VALUES = <?= $jsDefaultValuesAdd ?>;

let originalFormState = '';
let dataTableInstance;

const successToastEl = document.getElementById('successToast');
const successToastMsg = document.getElementById('successToastMessage');
const successToast = successToastEl ? new bootstrap.Toast(successToastEl, { delay: 3000 }) : null;

const errorToastEl = document.getElementById('errorToast');
const errorToastMsg = document.getElementById('errorToastMessage');
const errorToast = errorToastEl ? new bootstrap.Toast(errorToastEl, { delay: 5000 }) : null;

const loadingOverlay = $('#loadingOverlay'); // Get the loading overlay element

function showFeedback(type, message) {
    if (type === 'success' && successToast) {
        successToastMsg.textContent = message;
        successToast.show();
    } else if (type === 'error' && errorToast) {
        errorToastMsg.textContent = message;
        errorToast.show();
    } else {
        alert(message);
    }
}

function reloadTableData() {
    location.reload();
}

$(document).ready(function () {
    const tableElement = $('#dataTable1');
    if (tableElement.length && tableElement.find('thead th').length > 1) {
        dataTableInstance = tableElement.DataTable({
            responsive: true,
            pageLength: 10,
            initComplete: function () {
                this.api().columns().every(function () {
                    const that = this;
                    $('input', this.footer()).on('keyup change clear', function () {
                        if (that.search() !== this.value) {
                            that.search(this.value).draw();
                        }
                    });
                });
                loadingOverlay.hide(); // Hide spinner when DataTables is initialized
            }
        });
    } else {
        console.warn('DataTables not initialized, table element or headers missing. Hiding loading overlay.');
        loadingOverlay.hide(); // Hide spinner even if table not initialized
    }

    $('[data-bs-toggle="tooltip"]').tooltip();

    const rowModal = new bootstrap.Modal(document.getElementById('rowModal'));
    const modalBodyContent = $('#modalBodyContent');
    const saveChangesBtn = $('#saveChangesBtn');
    const saveChangesSpinner = saveChangesBtn.find('.spinner-border');
    const rowModalLabel = $('#rowModalLabel');

    $(document).on('click', '.viewEditBtn', function () {
        const rowDataAttr = $(this).attr('data-row-json');
        let rowData = {};

        try {
            rowData = JSON.parse(rowDataAttr);
        } catch (e) {
            console.error("Error parsing row data from button attribute:", e, "Raw data:", rowDataAttr);
            showFeedback('error', 'Error loading row data for editing. Parsing failed.');
            return;
        }

        modalBodyContent.empty();

        if (Object.keys(rowData).length === 0) {
            console.warn("Parsed rowData object is empty.");
            showFeedback('error', 'No data found for this row after parsing.');
            return;
        }

        let primaryKeyValue = rowData[PRIMARY_KEY_COLUMN];

        if (primaryKeyValue === undefined || primaryKeyValue === null || primaryKeyValue === '') {
            console.error("Primary key value is undefined, null, or empty for this row. Check PHP data output or PRIMARY_KEY_COLUMN constant.");
            showFeedback('error', 'Row ID not found for editing. Data might be incomplete or primary key name is incorrect.');
            return;
        }

        rowModalLabel.text(`Edit Row (ID: ${primaryKeyValue})`);

        modalBodyContent.append(`<input type="hidden" name="${PRIMARY_KEY_COLUMN}" value="${primaryKeyValue}">`);
        modalBodyContent.append(`<input type="hidden" name="tableName" value="${TABLE_NAME}">`);


        for (const key of ALL_COLUMN_NAMES) { // Use ALL_COLUMN_NAMES for edit form as it shows all, even read-only
            const value = rowData[key] === null ? '' : rowData[key];
            let inputHtml = '';
            let readonly = '';
            let colClass = 'col-md-6';
            let colSchema = COLUMN_SCHEMA[key] || {}; // Get schema for current column

            if (key === PRIMARY_KEY_COLUMN || key === 'created_at' || key === 'updated_at') {
                readonly = 'readonly';
                inputHtml = `<input type="text" name="${key}" class="form-control" value="${value}" ${readonly}>`;
            }
            // Prioritize specific text type columns (TEXT, MEDIUMTEXT, LONGTEXT) or common descriptive names for textareas
            else if (colSchema.data_type && (colSchema.data_type === 'text' || colSchema.data_type === 'mediumtext' || colSchema.data_type === 'longtext') ||
                     key.toLowerCase().includes('descr') || key.toLowerCase().includes('description') || key.toLowerCase().includes('comments') || key.toLowerCase().includes('moreinfo')) {
                inputHtml = `<textarea name="${key}" class="form-control" rows="8">${value}</textarea>`; // Increased rows
                colClass = 'col-12';
            }
            else {
                // Apply type and maxlength from schema for edit form fields too
                let inputType = 'text';
                let maxLengthAttr = '';
                if (colSchema.data_type) {
                     switch (colSchema.data_type) {
                        case 'int': case 'tinyint': case 'smallint':
                        case 'mediumint': case 'bigint': case 'decimal':
                        case 'float': case 'double':
                            inputType = 'number';
                            break;
                        case 'date':
                            inputType = 'date';
                            break;
                        case 'datetime': case 'timestamp':
                            // Handle datetime-local if the value is in the correct format
                            // Otherwise, it might be better to just leave as 'text'
                            inputType = 'datetime-local';
                            break;
                        case 'time':
                            inputType = 'time';
                            break;
                        case 'char': case 'varchar':
                            if (colSchema.max_length) {
                                maxLengthAttr = `maxlength="${colSchema.max_length}"`;
                            }
                            break;
                        case 'json':
                            inputType = 'text'; // Display JSON as text
                            break;
                    }
                }
                // Override for common names
                if (key.toLowerCase().includes('email')) inputType = 'email';
                if (key.toLowerCase().includes('phone')) inputType = 'tel';

                inputHtml = `<input type="${inputType}" name="${key}" class="form-control" value="${value}" ${maxLengthAttr}>`;
            }

            modalBodyContent.append(`
                <div class="${colClass} mb-3">
                    <label class="form-label">${key}</label>
                    ${inputHtml}
                </div>
            `);
        }

        rowModal.show();

        setTimeout(() => {
            originalFormState = $('#modalForm').serialize();
            saveChangesBtn.prop('disabled', true);
        }, 100);
    });

    $('#modalForm').on('input change', 'input, textarea, select', function () {
        saveChangesBtn.prop('disabled', $('#modalForm').serialize() === originalFormState);
    });

    $('#modalForm').submit(function (e) {
        e.preventDefault(); // CRITICAL: ALWAYS PREVENT DEFAULT SUBMISSION

        saveChangesBtn.prop('disabled', true);
        saveChangesSpinner.removeClass('d-none');

        $.ajax({
            url: 'updateRow.php',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify($(this).serializeArray().reduce((obj, item) => {
                obj[item.name] = item.value;
                return obj;
            }, {})),
            success: function (response) {
                if (response.status === 'success' || response.status === 'info') {
                    showFeedback('success', response.message);
                    rowModal.hide();
                    reloadTableData();
                } else {
                    showFeedback('error', response.message);
                }
            },
            error: function (xhr, status, error) {
                showFeedback('error', `Update error: ${xhr.responseText || error}`);
            },
            complete: function () {
                saveChangesBtn.prop('disabled', false);
                saveChangesSpinner.addClass('d-none');
            }
        });
    });

    const addModal = new bootstrap.Modal(document.getElementById('addModal'));
    const addModalBodyContent = $('#addModalBodyContent');
    const saveAddBtn = $('#saveAddBtn');
    const saveAddSpinner = saveAddBtn.find('.spinner-border');

    $('#addNewRecordBtn').click(function() {
        addModalBodyContent.empty();
        $('#addModalForm').removeClass('was-validated'); // Reset validation state

        addModalBodyContent.append(`<input type="hidden" name="tableName" value="${TABLE_NAME}">`);

        for (const key of EDITABLE_COLUMNS) { // Use EDITABLE_COLUMNS for Add form (excludes PK and timestamps)
            const colSchema = COLUMN_SCHEMA[key] || {}; // Get schema for this column

            let inputType = 'text';
            let colClass = 'col-md-6';
            let requiredAttr = '';
            let patternAttr = ''; // For specific regex patterns if needed
            let maxLengthAttr = '';
            let valueAttr = ''; // For default values if needed

            // Apply 'required' for NOT NULL columns (excluding the primary key for ADD)
            if (!colSchema.is_nullable) {
                requiredAttr = 'required';
            }

            // Determine input type and maxlength from schema
            if (colSchema.data_type) {
                switch (colSchema.data_type) {
                    case 'int': case 'tinyint': case 'smallint':
                    case 'mediumint': case 'bigint': case 'decimal':
                    case 'float': case 'double':
                        inputType = 'number';
                        break;
                    case 'date':
                        inputType = 'date';
                        break;
                    case 'datetime': case 'timestamp':
                        inputType = 'datetime-local'; // HTML5 type for date and time
                        break;
                    case 'time':
                        inputType = 'time';
                        break;
                    case 'char': case 'varchar':
                        if (colSchema.max_length) {
                            maxLengthAttr = `maxlength="${colSchema.max_length}"`;
                        }
                        break;
                    case 'json':
                        inputType = 'text'; // Treat JSON as text for input
                        break;
                }
            }

            // Override input type based on common name conventions if schema doesn't specify
            if (key.toLowerCase().includes('email')) inputType = 'email';
            if (key.toLowerCase().includes('phone')) inputType = 'tel';
            
            let inputHtml;
            // Prioritize specific text type columns (TEXT, MEDIUMTEXT, LONGTEXT) or common descriptive names for textareas
            if (colSchema.data_type && (colSchema.data_type === 'text' || colSchema.data_type === 'mediumtext' || colSchema.data_type === 'longtext') ||
                key.toLowerCase().includes('descr') || key.toLowerCase().includes('description') || key.toLowerCase().includes('comments') || key.toLowerCase().includes('moreinfo')) {
                inputType = 'textarea'; // Force textarea for specific columns or large text types
                colClass = 'col-12';
                inputHtml = `<textarea id="add-${key}" name="${key}" class="form-control" rows="8" ${requiredAttr} ${maxLengthAttr}></textarea>`; // Increased rows
            } else {
                inputHtml = `<input type="${inputType}" id="add-${key}" name="${key}" class="form-control" ${requiredAttr} ${patternAttr} ${maxLengthAttr} ${valueAttr}>`;
            }

            addModalBodyContent.append(`
                <div class="${colClass} mb-3">
                    <label for="add-${key}" class="form-label">${key}</label>
                    ${inputHtml}
                    <div class="invalid-feedback">Please enter a valid ${key}.</div>
                    <div class="valid-feedback">Looks good!</div>
                </div>
            `);
        }
        // After inputs appended, set tipMod value and add button
        setTimeout(() => {
            const tipModInput = $('#addModalForm').find('input[name="tipMod"]');
            if (tipModInput.length) {
                const now = (DEFAULT_ADD_VALUES && DEFAULT_ADD_VALUES.tipMod) ? DEFAULT_ADD_VALUES.tipMod : formatLocalDateTime(new Date());
                tipModInput.val(now);
                tipModInput.prop('readonly', true);
                if (!tipModInput.next('.setTipModNowBtn').length) {
                    tipModInput.after('<button type="button" class="btn btn-sm btn-secondary ms-2 setTipModNowBtn">Set to Now</button>');
                }
            }
        }, 50);

        addModal.show();
    });

    $('#addModalForm').submit(function (e) {
        e.preventDefault(); // CRITICAL: ALWAYS PREVENT DEFAULT SUBMISSION

        const form = this;
        if (!form.checkValidity()) {
            e.stopPropagation(); // Prevent the event from bubbling up (not strictly needed if preventDefault is first)
            form.classList.add('was-validated'); // Add Bootstrap's visual feedback
            showFeedback('error', 'Please fill in all required fields and correct any errors.');
            return; // Do not proceed with AJAX if validation fails
        }
        // If validation passes, remove was-validated for next time (optional)
        form.classList.remove('was-validated'); // Remove if valid for next submission

        saveAddBtn.prop('disabled', true);
        saveAddSpinner.removeClass('d-none');

        $.ajax({
            url: 'addRow.php',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify($(this).serializeArray().reduce((obj, item) => {
                obj[item.name] = item.value;
                return obj;
            }, {})),
            success: function (response) {
                if (response.status === 'success') {
                    showFeedback('success', response.message);
                    addModal.hide();
                    reloadTableData();
                } else {
                    showFeedback('error', response.message);
                }
            },
            error: function (xhr, status, error) {
                showFeedback('error', `Add error: ${xhr.responseText || error}`);
            },
            complete: function () {
                saveAddBtn.prop('disabled', false);
                saveAddSpinner.addClass('d-none');
            }
        });
    });

    const deleteConfirmModal = new bootstrap.Modal(document.getElementById('deleteConfirmModal'));
    const deleteRecordIdSpan = $('#deleteRecordId');
    const confirmDeleteBtn = $('#confirmDeleteBtn');
    const confirmDeleteSpinner = confirmDeleteBtn.find('.spinner-border');
    let recordToDeleteId = null;

    $(document).on('click', '.deleteRowBtn', function () {
        recordToDeleteId = $(this).data('id');
        deleteRecordIdSpan.text(recordToDeleteId);
        deleteConfirmModal.show();
    });

    $('#confirmDeleteBtn').click(function () {
        if (!recordToDeleteId) return;

        confirmDeleteBtn.prop('disabled', true);
        confirmDeleteSpinner.removeClass('d-none');

        $.ajax({
            url: 'deleteRow.php',
            type: 'POST',
            contentType: 'application/json',
            data: JSON.stringify({ id: recordToDeleteId, tableName: TABLE_NAME }),
            success: function (response) {
                if (response.status === 'success') {
                    showFeedback('success', response.message);
                    deleteConfirmModal.hide();
                    reloadTableData();
                } else {
                    showFeedback('error', response.message);
                }
            },
            error: function (xhr, status, error) {
                showFeedback('error', `Delete error: ${xhr.responseText || error}`);
            },
            complete: function () {
                confirmDeleteBtn.prop('disabled', false);
                confirmDeleteSpinner.addClass('d-none');
                recordToDeleteId = null;
            }
        });
    });

    // Add double-click event on the ID column to open the edit modal
    $(document).on('dblclick', 'td:first-child', function () {
        const row = $(this).closest('tr');
        const rowDataAttr = row.find('.viewEditBtn').attr('data-row-json');
        if (rowDataAttr) {
            try {
                const rowData = JSON.parse(rowDataAttr);
                $('.viewEditBtn', row).trigger('click'); // Trigger the edit button click
            } catch (e) {
                console.error("Error parsing row data for double-click:", e);
                showFeedback('error', 'Error loading row data for editing.');
            }
        }
    });

    // Automatically set tipMod to the current date and time
    $(document).on('focus', 'input[name="tipMod"]', function () {
        const tipModInput = $(this);
        const currentDateTimeLocal = formatLocalDateTime(new Date());
        tipModInput.val(currentDateTimeLocal); // Always set to local current date and time
    });

    // Add a button to set tipMod to the current date and time
    $(document).on('click', '.setTipModNowBtn', function () {
        const tipModInput = $('input[name="tipMod"]');
        const currentDateTimeLocal = formatLocalDateTime(new Date());
        tipModInput.val(currentDateTimeLocal); // Set to local current date and time
    });

    // Update validation: compute currentDateTime using local formatter
    $(document).on('change', 'input[name="tipMod"]', function () {
        const tipModInput = $(this);
        const createdAtValue = $('input[name="created_at"]').val();
        const currentDateTime = formatLocalDateTime(new Date());

        // parseDateString is used elsewhere in file; keep using it but compare to local 'currentDateTime'
        const tipModDate = parseDateString(tipModInput.val());
        const createdAtDate = parseDateString(createdAtValue);
        const currentDate = parseDateString(currentDateTime);

        if (isNaN(tipModDate)) {
            showFeedback('error', 'Invalid date/time format for tipMod. Expected e.g. "YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD H:MM AM/PM".');
            tipModInput.val(currentDateTime);
            return;
        }
        if (!isNaN(createdAtDate) && tipModDate < createdAtDate) {
            showFeedback('error', `tipMod (${tipModInput.val()}) is before created_at (${createdAtValue}). Resetting to created_at.`);
            tipModInput.val(createdAtValue);
            return;
        }

        if (tipModDate > currentDate) {
            showFeedback('error', `tipMod (${tipModInput.val()}) cannot be after current date/time (${currentDateTime}). Resetting to now.`);
            tipModInput.val(currentDateTime);
            return;
        }
    });

    // Helper: robust date parser that handles:
    //  - ISO-like 'YYYY-MM-DD HH:MM:SS' (converted to 'YYYY-MM-DDTHH:MM:SS')
    //  - Plain Date.parse-compatible strings
    //  - Common AM/PM strings like '2025-10-06 2:30:45 PM' or '10/06/2025 2:30 PM'
    function parseDateString(dateString) {
        if (!dateString) return NaN;
        if (typeof dateString !== 'string') dateString = String(dateString);
        dateString = dateString.trim();
        // Try native parsing first
        let d = new Date(dateString);
        if (!isNaN(d)) return d;

        // Try convert 'YYYY-MM-DD HH:MM:SS' -> 'YYYY-MM-DDTHH:MM:SS'
        let m = dateString.match(/^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})(?:\.\d+)?$/);
        if (m) {
            d = new Date(m[1] + 'T' + m[2]);
            if (!isNaN(d)) return d;
        }

        // Try 'YYYY-MM-DD HH:MM' without seconds
        m = dateString.match(/^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2})$/);
        if (m) {
            d = new Date(m[1] + 'T' + m[2] + ':00');
            if (!isNaN(d)) return d;
        }

        // AM/PM formats: capture date + time + AM/PM
        // Examples:
        //  - '2025-10-06 2:30:45 PM'
        //  - '10/06/2025 2:30 PM'
        m = dateString.match(/^(.*?)\s+(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)$/i);
        if (m) {
            let datePart = m[1].trim();
            let hh = parseInt(m[2], 10);
            const mm = parseInt(m[3], 10);
            const ss = m[4] ? parseInt(m[4], 10) : 0;
            const ampm = m[5].toUpperCase();
            if (ampm === 'PM' && hh < 12) hh += 12;
            if (ampm === 'AM' && hh === 12) hh = 0;
            // normalize date part: prefer YYYY-MM-DD if present, otherwise try Date.parse with the assembled string
            if (/^\d{4}-\d{2}-\d{2}$/.test(datePart)) {
                const normalized = `${datePart}T${String(hh).padStart(2,'0')}:${String(mm).padStart(2,'0')}:${String(ss).padStart(2,'0')}`;
                d = new Date(normalized);
                if (!isNaN(d)) return d;
            } else {
                // try parsing datePart with Date and set time
                const base = new Date(datePart);
                if (!isNaN(base)) {
                    base.setHours(hh, mm, ss, 0);
                    return base;
                }
            }
        }

        // Fallback: try replacing space with 'T' and parse
        try {
            d = new Date(dateString.replace(' ', 'T'));
            if (!isNaN(d)) return d;
        } catch (e) { /* ignore */ }

        return NaN;
    }

    // Ensure Add modal's tipMod is prefilled and readonly and has a "Set to Now" button
    $('#addNewRecordBtn').click(function() {
        // ...existing code that builds inputs...
        // After inputs appended, set tipMod value and add button
        setTimeout(() => {
            const tipModInput = $('#addModalForm').find('input[name="tipMod"]');
            if (tipModInput.length) {
                const now = (DEFAULT_ADD_VALUES && DEFAULT_ADD_VALUES.tipMod) ? DEFAULT_ADD_VALUES.tipMod : formatLocalDateTime(new Date());
                tipModInput.val(now);
                tipModInput.prop('readonly', true);
                if (!tipModInput.next('.setTipModNowBtn').length) {
                    tipModInput.after('<button type="button" class="btn btn-sm btn-secondary ms-2 setTipModNowBtn">Set to Now</button>');
                }
            }
        }, 50);

        addModal.show();
    });

    // For edit modal, ensure tipMod shown, readonly, and add Set to Now button
    $(document).on('click', '.viewEditBtn', function () {
        // ...existing code that builds modalBodyContent...
        // after modalBodyContent appended:
        setTimeout(() => {
            const tipModInput = $('#modalForm').find('input[name="tipMod"]');
            if (tipModInput.length) {
                // if value empty, set to current
                const currentVal = tipModInput.val() || formatLocalDateTime(new Date());
                tipModInput.val(currentVal);
                tipModInput.prop('readonly', true);
                if (!tipModInput.next('.setTipModNowBtn').length) {
                    tipModInput.after('<button type="button" class="btn btn-sm btn-secondary ms-2 setTipModNowBtn">Set to Now</button>');
                }
            }

            originalFormState = $('#modalForm').serialize();
            saveChangesBtn.prop('disabled', true);
        }, 100);
    });

    // Set to Now button handler (works for both Add and Edit)
    $(document).on('click', '.setTipModNowBtn', function () {
        const btn = $(this);
        const input = btn.prevAll('input[name="tipMod"]').first();
        const now = formatLocalDateTime(new Date());
        if (input.length) input.val(now);
    });

    // Validation for tipMod: detailed messages using the robust parser
    $(document).on('change', 'input[name="tipMod"]', function () {
        const tipModInput = $(this);
        const createdAtValue = $('input[name="created_at"]').val();
        const currentDateTime = formatLocalDateTime(new Date());

        const tipModDate = parseDateString(tipModInput.val());
        const createdAtDate = parseDateString(createdAtValue);
        const currentDate = parseDateString(currentDateTime);

        if (isNaN(tipModDate)) {
            showFeedback('error', 'Invalid date/time format for tipMod. Expected e.g. "YYYY-MM-DD HH:MM:SS" or "YYYY-MM-DD H:MM AM/PM".');
            tipModInput.val(currentDateTime);
            return;
        }
        // If createdAt missing, treat as epoch (very old) so check won't block
        if (isNaN(createdAtDate)) {
            // no created_at available; skip "before created_at" check
        } else if (tipModDate < createdAtDate) {
            showFeedback('error', `tipMod (${tipModInput.val()}) is before created_at (${createdAtValue}). Resetting to created_at.`);
            tipModInput.val(createdAtValue);
            return;
        }

        if (tipModDate > currentDate) {
            showFeedback('error', `tipMod (${tipModInput.val()}) cannot be after current date/time (${currentDateTime}). Resetting to now.`);
            tipModInput.val(currentDateTime);
            return;
        }
    });

    // Add this helper at the top of $(document).ready so it's available everywhere
    function formatLocalDateTime(d) {
        if (!(d instanceof Date)) d = new Date(d);
        if (isNaN(d)) return '';
        const Y = d.getFullYear();
        const M = String(d.getMonth() + 1).padStart(2, '0');
        const D = String(d.getDate()).padStart(2, '0');
        const hh = String(d.getHours()).padStart(2, '0');
        const mm = String(d.getMinutes()).padStart(2, '0');
        const ss = String(d.getSeconds()).padStart(2, '0');
        return `${Y}-${M}-${D} ${hh}:${mm}:${ss}`;
    }
});
// ...existing code...
</script>
</body>
</html>
