<link href="<?= ROOT_URL ?>/src/css/diary.css" rel="stylesheet">
<script src="<?= ROOT_URL ?>/src/js/moment.js"></script>
<script src="<?= ROOT_URL ?>/src/js/diary.js"></script>

<style>
.assignment-toolbar {
    gap: .5rem;
}
.assignment-calendar-wrap {
    min-height: 520px;
}
.assignment-list {
    max-height: 520px;
    overflow: auto;
}
.assignment-notes {
    color: #6b7580;
    display: block;
    max-width: 420px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.assignment-list-table {
    min-width: 1280px;
    table-layout: fixed;
}
.assignment-list-table th,
.assignment-list-table td {
    vertical-align: middle;
}
.assignment-list-table th {
    white-space: nowrap;
}
.assignment-list-client {
    max-width: 260px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.assignment-list-subtext {
    color: #6b7580;
    display: block;
    font-size: .8rem;
    line-height: 1.25;
}
.assignment-date-stack {
    white-space: nowrap;
}
.assignment-date-stack small {
    color: #596674;
}
.assignment-due-chips,
.assignment-actions {
    align-items: center;
    display: flex;
    flex-wrap: nowrap;
    gap: .35rem;
    max-width: 420px;
}
.assignment-due-chip {
    border: 1px solid #dfe5eb;
    border-radius: 6px;
    font-size: .78rem;
    line-height: 1;
    padding: .28rem .4rem;
    white-space: nowrap;
}
.assignment-actions .btn {
    align-items: center;
    display: inline-flex;
    gap: .3rem;
    height: 30px;
    justify-content: center;
    margin: 0 !important;
    padding: 0 .55rem;
    white-space: nowrap;
}
.assignment-calendar-wrap .fc-center h2,
.assignment-calendar-wrap .fc-toolbar h2 {
    white-space: nowrap;
    line-height: 1.2;
}
.assignment-calendar-wrap .fc-day-header,
.assignment-calendar-wrap .fc-widget-header {
    background: var(--primary-color, #294766) !important;
    color: #fff !important;
    font-weight: 700;
    white-space: nowrap;
}
.assignment-calendar-wrap .fc-day-header a,
.assignment-calendar-wrap .fc-widget-header a,
.assignment-calendar-wrap .fc-col-header-cell a {
    color: #fff !important;
}
.assignment-calendar-wrap .fc-axis,
.assignment-calendar-wrap .fc-timegrid-axis,
.assignment-calendar-wrap .fc-timegrid-slot-label,
.assignment-calendar-wrap .fc-timegrid-axis-cushion,
.assignment-calendar-wrap .fc-timegrid-slot-label-cushion {
    background: #f2f4f6 !important;
    color: #4f5963 !important;
}
.assignment-calendar-wrap .fc-bg td,
.assignment-calendar-wrap .fc-slats td,
.assignment-calendar-wrap .fc-content-skeleton td,
.assignment-calendar-wrap .fc-axis {
    border-color: #d0d4d8 !important;
}
.assignment-calendar-wrap .fc-time-grid .fc-day,
.assignment-calendar-wrap .fc-time-grid .fc-bg td,
.assignment-calendar-wrap .fc-time-grid .fc-content-skeleton td,
.assignment-calendar-wrap .fc-day-grid .fc-day {
    border-left: 1px solid #d0d4d8 !important;
    border-right: 1px solid #d0d4d8 !important;
}
.assignment-calendar-wrap .fc-time-grid .fc-slats tr {
    border-top: 1px solid #e1e4e7;
}
.assignment-calendar-wrap .fc-time-grid .fc-slats tr:nth-child(even) td {
    border-top-style: dotted !important;
    border-top-color: #edf0f2 !important;
}
.assignment-calendar-wrap .fc-time-grid .fc-slats td {
    height: 44px;
}
.assignment-calendar-wrap .fc-time-grid-container {
    border: 1px solid #d0d4d8;
}
.assignment-calendar-wrap .fc-day-header {
    border: 1px solid #d0d4d8 !important;
    background: var(--primary-color, #294766) !important;
    color: #fff !important;
}
.assignment-calendar-wrap .fc-view > table,
.assignment-calendar-wrap .fc-view .fc-head,
.assignment-calendar-wrap .fc-view .fc-body {
    border-collapse: collapse !important;
}
.assignment-calendar-wrap .fc-time-grid .fc-bg table,
.assignment-calendar-wrap .fc-time-grid .fc-content-skeleton table,
.assignment-calendar-wrap .fc-day-grid .fc-bg table,
.assignment-calendar-wrap .fc-day-grid .fc-content-skeleton table {
    border-collapse: collapse !important;
}
.assignment-calendar-wrap .fc-time-grid .fc-bg td,
.assignment-calendar-wrap .fc-time-grid .fc-content-skeleton td {
    box-shadow: inset 1px 0 0 #d0d4d8, inset -1px 0 0 #d0d4d8;
}
.assignment-calendar-wrap .fc-month-view .fc-bg td,
.assignment-calendar-wrap .fc-month-view .fc-content-skeleton td,
.assignment-calendar-wrap .fc-month-view .fc-day-top {
    border: 1px solid #d0d4d8 !important;
    box-shadow: inset 0 0 0 1px #e4e7ea;
}
.assignment-calendar-wrap .fc-month-view .fc-row {
    border-top: 1px solid #d0d4d8 !important;
}
.assignment-calendar-wrap .fc-month-view .fc-day-number {
    padding: 6px;
}
.assignment-calendar-wrap .fc-time-grid-event {
    margin-left: 3px;
    margin-right: 3px;
}
.assignment-calendar-wrap .fc-event {
    border-width: 2px;
    box-shadow: 0 1px 3px rgba(0,0,0,.22);
}
.assignment-calendar-wrap .surveyor-colour-0 { background-color: #294766 !important; border-color: #294766 !important; }
.assignment-calendar-wrap .surveyor-colour-1 { background-color: #2f6f64 !important; border-color: #2f6f64 !important; }
.assignment-calendar-wrap .surveyor-colour-2 { background-color: #7a4f2b !important; border-color: #7a4f2b !important; }
.assignment-calendar-wrap .surveyor-colour-3 { background-color: #6d4c7d !important; border-color: #6d4c7d !important; }
.assignment-calendar-wrap .surveyor-colour-4 { background-color: #7a3947 !important; border-color: #7a3947 !important; }
.assignment-calendar-wrap .surveyor-colour-5 { background-color: #4f6330 !important; border-color: #4f6330 !important; }
.assignment-calendar-wrap .fc-day,
.assignment-calendar-wrap .fc-day-top,
.assignment-calendar-wrap .fc-day-header {
    background-clip: padding-box;
}
.assignment-calendar-wrap .fc-today {
    background: rgba(42, 73, 101, .16) !important;
}
.assignment-calendar-wrap .fc-highlight {
    background: rgba(42, 73, 101, .22);
}
.assignment-calendar-wrap .fc-theme-standard td,
.assignment-calendar-wrap .fc-theme-standard th,
.assignment-calendar-wrap .fc-scrollgrid,
.assignment-calendar-wrap .fc-scrollgrid td,
.assignment-calendar-wrap .fc-scrollgrid th {
    border-color: #d0d4d8 !important;
}
.assignment-calendar-wrap .fc-timegrid-col,
.assignment-calendar-wrap .fc-col-header-cell {
    border-left: 1px solid #d0d4d8 !important;
    border-right: 1px solid #d0d4d8 !important;
    box-shadow: inset 1px 0 0 #d0d4d8, inset -1px 0 0 #d0d4d8;
}
.assignment-calendar-wrap .fc-col-header-cell {
    background: var(--primary-color, #294766) !important;
    color: #fff !important;
}
.assignment-calendar-wrap .fc-timegrid-slot {
    border-top: 1px solid #e1e4e7 !important;
    height: 44px !important;
}
.assignment-calendar-wrap .fc-timegrid-slot-minor {
    border-top: 1px dotted #edf0f2 !important;
}
.assignment-calendar-wrap .fc-daygrid-day {
    border: 1px solid #d0d4d8 !important;
    box-shadow: inset 0 0 0 1px #e4e7ea;
}
.assignment-calendar-wrap .fc-daygrid-day-frame {
    border: 1px solid #e4e7ea;
    min-height: 96px;
}
.assignment-calendar-wrap .fc-daygrid-day-number {
    padding: 6px;
}
@media (max-width: 767px) {
    .assignment-calendar-wrap {
        min-height: 430px;
    }
}
</style>

<div class="card mb-4">
    <div class="card-header d-flex flex-wrap align-items-center justify-content-between assignment-toolbar">
        <h5 class="mb-0">Surveyor Diary</h5>
        <div class="d-flex flex-wrap assignment-toolbar">
            <button class="btn btn-sm btn-success shadow-0" type="button" onclick="openAssignSurveyorModal()">
                <i class="fad fa-plus"></i> Assign Surveyor
            </button>
            <button class="btn btn-sm btn-secondary shadow-0" type="button" onclick="toggleDiaryMode()">
                <i class="fad fa-table"></i> List / Calendar
            </button>
        </div>
    </div>
    <div class="card-body">
        <div class="row align-items-end gy-2 mb-3">
            <div class="col-12 col-md-4">
                <label for="surveyorFilter" class="form-label">Surveyor</label>
                <select id="surveyorFilter" class="form-select" onchange="applyDiaryFilters()">
                    <option value="">All surveyors</option>
                </select>
            </div>
            <div class="col-12 col-md-4">
                <label for="statusFilter" class="form-label">Status</label>
                <select id="statusFilter" class="form-select" onchange="applyDiaryFilters()">
                    <option value="">All statuses</option>
                    <option value="Not Started">Not Started</option>
                    <option value="In Progress">In Progress</option>
                    <option value="Completed">Completed</option>
                </select>
            </div>
            <div class="col-12 col-md-4 text-md-end">
                <button class="btn btn-outline-secondary btn-sm" type="button" onclick="clearDiaryFilters()">
                    <i class="fad fa-broom"></i> Clear
                </button>
            </div>
        </div>

        <div id="assignedJobsSection">
            <div id="assignmentCalendarWrap" class="assignment-calendar-wrap" style="display:none">
                <div class="d-flex justify-content-end flex-wrap assignment-toolbar mb-2">
                    <button id="diaryRangeDay" class="btn btn-sm btn-outline-secondary" type="button" onclick="setDiaryRange('day')">Day</button>
                    <button id="diaryRangeWeek" class="btn btn-sm btn-secondary" type="button" onclick="setDiaryRange('week')">Week</button>
                    <button id="diaryRangeMonth" class="btn btn-sm btn-outline-secondary" type="button" onclick="setDiaryRange('month')">Month</button>
                </div>
                <div id="assignmentCalendar"></div>
            </div>

            <div id="assignmentListWrap" class="assignment-list table-responsive mt-3">
                <table class="table table-hover table-sm align-middle assignment-list-table">
                    <colgroup>
                        <col style="width: 64px">
                        <col style="width: 260px">
                        <col style="width: 180px">
                        <col style="width: 150px">
                        <col style="width: 260px">
                        <col style="width: 120px">
                        <col style="width: 420px">
                    </colgroup>
                    <thead class="table-dark bg-dark" style="position: sticky; top: 0; z-index: 1;">
                        <tr>
                            <th>Job</th>
                            <th>Client / Site</th>
                            <th>Surveyor</th>
                            <th>Date / Time</th>
                            <th>Expected</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody id="assignedJobsTable"></tbody>
                </table>
            </div>
        </div>

        <div id="assignFormSection" style="display:none">
            <div class="row gy-3">
                <div class="col-12 col-lg-4">
                    <label for="clientSelect" class="form-label">Client</label>
                    <select id="clientSelect" class="form-select" onchange="loadLocationOptions('clientSelect', 'locationSelect')">
                        <option value="">Select Client</option>
                    </select>
                </div>
                <div class="col-12 col-lg-4">
                    <label for="locationSelect" class="form-label">Site</label>
                    <select id="locationSelect" class="form-select">
                        <option value="">Whole client / no site</option>
                    </select>
                </div>
                <div class="col-12 col-lg-4">
                    <label for="surveyorSelect" class="form-label">Surveyor</label>
                    <select id="surveyorSelect" class="form-select">
                        <option value="">Select Surveyor</option>
                    </select>
                </div>
                <div class="col-12 col-md-4">
                    <label for="appointmentDate" class="form-label">Date</label>
                    <input type="date" id="appointmentDate" class="form-control">
                </div>
                <div class="col-6 col-md-4">
                    <label for="startTime" class="form-label">Start</label>
                    <input type="time" id="startTime" class="form-control">
                </div>
                <div class="col-6 col-md-4">
                    <label for="endTime" class="form-label">End</label>
                    <input type="time" id="endTime" class="form-control">
                </div>
                <div class="col-12">
                    <label for="assignmentNotes" class="form-label">Notes</label>
                    <textarea id="assignmentNotes" class="form-control" rows="3"></textarea>
                </div>
                <div class="col-12 text-end">
                    <button class="btn btn-outline-secondary" type="button" onclick="toggleView('assigned')">Cancel</button>
                    <button class="btn btn-primary" type="button" onclick="assignSurveyor()">Assign Surveyor</button>
                </div>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="assignmentDetailModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-lg modal-dialog-scrollable">
        <div class="modal-content">
            <div class="modal-header">
                <a href="javascript:void(0)" class="sa">Job Details</a>
            </div>
            <div class="modal-body">
                <form id="assignmentDetailForm">
                    <input type="hidden" id="detailAssignmentId">
                    <input type="hidden" id="detailClientId">
                    <div class="row gy-3">
                        <div class="col-12 col-lg-6">
                            <label for="detailClient" class="form-label">Client</label>
                            <input type="text" id="detailClient" class="form-control" disabled>
                        </div>
                        <div class="col-12 col-lg-6">
                            <label for="detailSurveyor" class="form-label">Surveyor</label>
                            <select id="detailSurveyor" class="form-select"></select>
                        </div>
                        <div class="col-12 col-lg-6">
                            <label for="detailLocation" class="form-label">Site</label>
                            <select id="detailLocation" class="form-select"></select>
                        </div>
                        <div class="col-12 col-lg-6">
                            <label for="detailStatus" class="form-label">Status</label>
                            <select id="detailStatus" class="form-select">
                                <option value="0">Not Started</option>
                                <option value="1">In Progress</option>
                                <option value="2">Completed</option>
                            </select>
                        </div>
                        <div class="col-12 col-md-4">
                            <label for="detailDate" class="form-label">Date</label>
                            <input type="date" id="detailDate" class="form-control" onchange="updateDetailUiWarning()" oninput="updateDetailUiWarning()">
                        </div>
                        <div class="col-6 col-md-4">
                            <label for="detailStart" class="form-label">Start</label>
                            <input type="time" id="detailStart" class="form-control" onchange="updateDetailUiWarning()" oninput="updateDetailUiWarning()">
                        </div>
                        <div class="col-6 col-md-4">
                            <label for="detailEnd" class="form-label">End</label>
                            <input type="time" id="detailEnd" class="form-control" onchange="updateDetailUiWarning()" oninput="updateDetailUiWarning()">
                        </div>
                        <div class="col-12">
                            <div id="detailUiEstimate" class="alert alert-light border mb-0" style="display:none"></div>
                        </div>
                        <div class="col-12">
                            <div id="detailUiWarning" class="alert alert-warning mb-0" style="display:none"></div>
                        </div>
                        <div class="col-12">
                            <label for="detailNotes" class="form-label">Notes</label>
                            <textarea id="detailNotes" class="form-control" rows="4"></textarea>
                        </div>
                        <div class="col-12" id="detailMapLink"></div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-secondary" data-mdb-dismiss="modal">Close</button>
                <button type="button" class="btn btn-info" onclick="saveAssignmentDetails()">Save Changes</button>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="assignmentMapModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-xl modal-dialog-scrollable">
        <div class="modal-content">
            <div class="modal-header">
                <a href="javascript:void(0)" class="sa">Job Map</a>
            </div>
            <div class="modal-body">
                <input type="hidden" id="mapDestination">
                <div class="row gy-2 mb-3">
                    <div class="col-12 col-lg-8">
                        <label for="mapOrigin" class="form-label">From</label>
                        <input type="text" id="mapOrigin" class="form-control" placeholder="Optional start point or previous job">
                    </div>
                    <div class="col-12 col-lg-4 d-flex align-items-end gap-2">
                        <button type="button" class="btn btn-outline-info" onclick="useGpsForJobMap()">GPS</button>
                        <button type="button" class="btn btn-info" onclick="renderJobMapRoute()">Route</button>
                        <button type="button" class="btn btn-outline-secondary" onclick="renderJobMapLocation()">Location</button>
                        <a id="mapExternalLink" class="btn btn-secondary" target="_blank" href="#">Open</a>
                    </div>
                </div>
                <div class="ratio ratio-16x9">
                    <iframe id="assignmentMapFrame" src="" style="border:0;" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
                </div>
                <div id="mapRouteSummary" class="alert alert-light border mt-3 mb-0" style="display:none"></div>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="adminMessageModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <a href="javascript:void(0)" class="sa">Send Message to Surveyor</a>
            </div>
            <div class="modal-body">
                <form id="adminMessageForm">
                    <input type="hidden" id="adminAssignmentId" name="assignment_id">
                    <input type="hidden" id="recipient_id" name="recipient_id">
                    <div class="mb-3">
                        <label for="adminMessageContent" class="form-label">Message</label>
                        <textarea id="adminMessageContent" name="message" class="form-control" rows="4" required></textarea>
                    </div>
                    <div class="mb-3">
                        <label for="adminMessageStatus" class="form-label">Priority</label>
                        <select id="adminMessageStatus" name="status" class="form-select">
                            <option value="normal">Normal</option>
                            <option value="urgent">Urgent</option>
                        </select>
                    </div>
                    <button type="submit" class="btn btn-primary">Send Message</button>
                </form>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="removeAssignmentModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <a href="javascript:void(0)" class="sa">Confirm Assignment Removal</a>
            </div>
            <div class="modal-body">
                <p id="confirmMessage">Are you sure you want to remove this assignment?</p>
                <div class="form-check mb-3">
                    <input class="form-check-input" type="checkbox" id="pauseSurveyorAssignmentsToggle" onclick="toggleOtherCheckbox('pause')">
                    <label id="pauseMessage" class="form-check-label" for="pauseSurveyorAssignmentsToggle"></label>
                </div>
                <div class="form-check">
                    <input class="form-check-input" type="checkbox" id="removeSurveyorAssignmentsToggle" onclick="toggleOtherCheckbox('remove')">
                    <label class="form-check-label" for="removeSurveyorAssignmentsToggle">
                        Also remove all surveyor-client assignments from the managed surveyor permissions system?
                    </label>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-mdb-dismiss="modal">Cancel</button>
                <button type="button" id="confirmRemoveButton" class="btn btn-danger">Remove</button>
            </div>
        </div>
    </div>
</div>

<script>
let allJobs = [];
let allSurveyors = [];
let calendar = null;
let diaryRange = 'week';
let calendarVisible = false;
let assignmentDiaryStarted = false;
let assignmentJobsLoading = false;
let assignmentJobsPendingReload = false;

function startAssignmentDiary() {
    if (assignmentDiaryStarted) return;
    const listWrap = document.getElementById('assignmentListWrap');
    const calendarEl = document.getElementById('assignmentCalendar');
    if (!listWrap || !calendarEl) {
        setTimeout(startAssignmentDiary, 100);
        return;
    }
    assignmentDiaryStarted = true;
    initialiseCalendar();
    toggleDiaryMode(false);
    loadDiarySurveyorData();
    loadAssignedJobs();
    setInterval(loadAssignedJobs, 30000);
}

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', startAssignmentDiary);
} else {
    setTimeout(startAssignmentDiary, 0);
}

function initialiseCalendar() {
    const calendarEl = document.getElementById('assignmentCalendar');
    if (!calendarEl) return;
    if (typeof FullCalendar === 'undefined') {
        calendarEl.innerHTML = '<div class="alert alert-warning">Calendar library could not be loaded.</div>';
        return;
    }
    calendar = new FullCalendar.Calendar(calendarEl, {
        height: 520,
        themeSystem: 'bootstrap',
        scrollTime: currentCalendarScrollTime(),
        header: {
            left: 'prev,next today',
            center: 'title',
            right: ''
        },
        defaultView: 'timeGridWeek',
        displayEventTime: true,
        slotEventOverlap: true,
        eventOverlap: true,
        eventClick: function(info) {
            openAssignmentDetails(info.event.extendedProps.jobId);
        },
        dateClick: function(info) {
            openAssignSurveyorModalFromDate(info.date, info.allDay);
        },
        viewRender: function() {
            if (assignmentDiaryStarted) {
                loadAssignedJobs();
            }
        }
    });
    calendar.render();
    scrollCalendarToCurrentTime(calendar);
    setDiaryRangeButtonState();
    setTimeout(function() {
        if (!calendar) return;
        calendar.changeView('timeGridWeek');
        calendar.updateSize();
        scrollCalendarToCurrentTime(calendar);
        setDiaryRangeButtonState();
    }, 250);
    setTimeout(function() {
        if (!calendar) return;
        calendar.updateSize();
    }, 600);
    if (typeof ResizeObserver !== 'undefined') {
        const wrap = document.getElementById('assignmentCalendarWrap');
        const observer = new ResizeObserver(function() {
            if (calendar && calendarVisible) calendar.updateSize();
        });
        observer.observe(wrap);
    }
}

function openAssignSurveyorModal(appointmentDate = '', startTime = '') {
    const params = new URLSearchParams({ tenant: TENANT_URL });
    if (appointmentDate) params.append('appointment_date', appointmentDate);
    if (startTime) params.append('start_time', startTime);
    const dest = ROOT_URL + '/includes/admin/admin_assignment_modal.php?' + params.toString();
    loadModalContent(dest, 'popupBox', 'modal-xl', 1060, 'true', 'Assign Surveyor');
}

function openAssignSurveyorModalFromDate(date, allDay) {
    const day = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
    const appointmentDate = Math.floor(day.getTime() / 1000);
    const startTime = allDay ? '' : Math.floor(date.getTime() / 1000);
    openAssignSurveyorModal(appointmentDate, startTime);
}

function setDiaryRange(range) {
    diaryRange = range;
    setDiaryRangeButtonState();
    if (!calendar) return;
    const view = range === 'day' ? 'timeGridDay' : (range === 'month' ? 'dayGridMonth' : 'timeGridWeek');
    calendar.changeView(view);
    scrollCalendarToCurrentTime(calendar);
    loadAssignedJobs();
}

function setDiaryRangeButtonState() {
    const buttons = {
        day: document.getElementById('diaryRangeDay'),
        week: document.getElementById('diaryRangeWeek'),
        month: document.getElementById('diaryRangeMonth')
    };
    Object.keys(buttons).forEach(key => {
        if (!buttons[key]) return;
        buttons[key].classList.remove('btn-light', 'btn-outline-light', 'btn-secondary', 'btn-outline-secondary');
        buttons[key].classList.add(key === diaryRange ? 'btn-secondary' : 'btn-outline-secondary');
    });
}

function toggleDiaryMode(forceVisible = null) {
    calendarVisible = forceVisible === null ? !calendarVisible : !!forceVisible;
    document.getElementById('assignmentCalendarWrap').style.display = calendarVisible ? '' : 'none';
    document.getElementById('assignmentListWrap').style.display = calendarVisible ? 'none' : '';
    if (calendarVisible && calendar) {
        calendar.render();
        calendar.updateSize();
        scrollCalendarToCurrentTime(calendar);
    }
}

function currentCalendarScrollTime() {
    const now = new Date();
    const minutes = Math.max(0, (now.getHours() * 60) + now.getMinutes() - 60);
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;
    return String(hours).padStart(2, '0') + ':' + String(mins).padStart(2, '0') + ':00';
}

function scrollCalendarToCurrentTime(targetCalendar) {
    if (!targetCalendar || diaryRange === 'month' || !calendarVisible) return;
    setTimeout(function() {
        if (typeof targetCalendar.scrollToTime === 'function') {
            targetCalendar.scrollToTime(currentCalendarScrollTime());
        }
    }, 80);
}

function loadAssignedJobs() {
    if (assignmentJobsLoading) {
        assignmentJobsPendingReload = true;
        return;
    }
    assignmentJobsLoading = true;
    assignmentJobsPendingReload = false;
    fetch(ROOT_URL + '/includes/admin/admin_get_assigned_jobs.php?' + assignmentDiaryQueryString())
        .then(response => response.json())
        .then(data => {
            allJobs = data.jobs || [];
            applyDiaryFilters();
        })
        .finally(() => {
            assignmentJobsLoading = false;
            if (assignmentJobsPendingReload) {
                loadAssignedJobs();
            }
        });
}

function assignmentDiaryQueryString() {
    const params = new URLSearchParams({ tenant: TENANT_URL });
    const range = assignmentDiaryVisibleRange();
    params.set('start', range.start);
    params.set('end', range.end);
    return params.toString();
}

function assignmentDiaryVisibleRange() {
    if (calendar && calendar.view) {
        const view = calendar.view;
        const start = view.intervalStart || view.activeStart || view.start;
        const end = view.intervalEnd || view.activeEnd || view.end;
        if (start && end) {
            return {
                start: dateLikeToTimestamp(start),
                end: Math.max(dateLikeToTimestamp(start), dateLikeToTimestamp(end) - 1)
            };
        }
    }
    const now = new Date();
    const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const end = new Date(start);
    if (diaryRange === 'day') {
        end.setDate(start.getDate() + 1);
    } else if (diaryRange === 'month') {
        start.setDate(1);
        end.setMonth(start.getMonth() + 1, 1);
    } else {
        const day = start.getDay() || 7;
        start.setDate(start.getDate() - day + 1);
        end.setDate(start.getDate() + 7);
    }
    return {
        start: Math.floor(start.getTime() / 1000),
        end: Math.floor(end.getTime() / 1000) - 1
    };
}

function dateLikeToTimestamp(value) {
    if (typeof value.unix === 'function') return value.unix();
    return Math.floor(new Date(value).getTime() / 1000);
}

function applyDiaryFilters() {
    const surveyorId = document.getElementById('surveyorFilter').value;
    const status = document.getElementById('statusFilter').value;
    let jobs = allJobs.slice();
    if (surveyorId) jobs = jobs.filter(job => String(job.surveyor_id) === String(surveyorId));
    if (status) jobs = jobs.filter(job => job.status === status);
    renderCalendar(jobs);
    renderJobList(jobs);
}

function clearDiaryFilters() {
    document.getElementById('surveyorFilter').value = '';
    document.getElementById('statusFilter').value = '';
    applyDiaryFilters();
}

function renderCalendar(jobs) {
    if (!calendar) return;
    const addEvents = function() {
        calendar.removeAllEvents();
        jobs.forEach(job => {
            const start = Number(job.start_time || job.appointment_date);
            const end = Number(job.end_time || 0);
            calendar.addEvent({
                title: `${job.surveyor}: ${job.clientname}`,
                start: new Date(start * 1000),
                end: end ? new Date(end * 1000) : null,
                allDay: !job.start_time,
                className: statusClass(job.status) + ' ' + surveyorColourClass(job.surveyor_id),
                extendedProps: { jobId: job.id }
            });
        });
    };
    if (typeof calendar.batchRendering === 'function') {
        calendar.batchRendering(addEvents);
    } else {
        addEvents();
    }
}

function jobListRow(job, previous) {
    const travelLink = previous && previous.map_query && job.map_query
        ? `<a class="btn btn-outline-info btn-sm mb-1" target="_blank" href="https://www.google.com/maps/dir/?api=1&origin=${encodeURIComponent(previous.map_query)}&destination=${encodeURIComponent(job.map_query)}"><i class="fad fa-route"></i></a>`
        : '';
    return `
        <tr>
            <td>${job.id}</td>
            <td class="assignment-list-client">
                <a href="index.php?t=includes/master&p=client.php&clientnumber=${job.clientnumber}&view=asset">${escapeHtml(job.clientname || '')}</a>
                ${job.locname ? `<span class="assignment-list-subtext">${escapeHtml(job.locname)}</span>` : ''}
                ${job.notes ? `<span class="assignment-notes">${escapeHtml(job.notes)}</span>` : ''}
            </td>
            <td>${escapeHtml(job.surveyor || '')}</td>
            <td class="assignment-date-stack">${formatJobDate(job)}</td>
            <td>${itemsDue(job)}</td>
            <td><span class="badge ${statusBadge(job.status)}">${job.status}</span></td>
            <td>
                <div class="assignment-actions">
                    <button class="btn btn-secondary btn-sm" title="Edit job" onclick="openAssignmentDetails(${job.id})"><i class="fad fa-edit"></i> Edit</button>
                    <a class="btn btn-secondary btn-sm" title="Surveyor permissions" href="index.php?t=includes/master&p=surveyor.php&id=${job.surveyor_id}&view=assign"><i class="fad fa-arrow-right-to-arc"></i> Assign</a>
                    <button class="btn btn-info btn-sm" title="Message surveyor" onclick="openAdminMessageModal(${job.id}, '${job.surveyor_id}')"><i class="fad fa-envelope"></i> Message</button>
                    ${job.map_query ? `<button class="btn btn-outline-secondary btn-sm" title="Show job map" onclick="openJobMapModal(${job.id})"><i class="fad fa-map-location-dot"></i> Map</button>` : ''}
                    ${previous && previous.map_query && job.map_query ? `<button class="btn btn-outline-info btn-sm" title="Show route from previous job" onclick="openJobMapModal(${job.id}, '${encodeURIComponent(previous.map_query)}')"><i class="fad fa-route"></i> Route</button>` : ''}
                    <button class="btn btn-danger btn-sm" title="Remove assignment" onclick="openRemoveModalForJob(${job.id})"><i class="fad fa-trash"></i> Remove</button>
                </div>
            </td>
        </tr>
    `;
}

function renderJobList(jobs) {
    const table = document.getElementById('assignedJobsTable');
    const sorted = jobs.slice().sort((a, b) => Number(a.start_time || a.appointment_date) - Number(b.start_time || b.appointment_date));
    const previousBySurveyorDate = {};
    const rows = sorted.map(job => {
        const dateKey = `${job.surveyor_id}-${dateInputValue(job.start_time || job.appointment_date)}`;
        const previous = previousBySurveyorDate[dateKey];
        previousBySurveyorDate[dateKey] = job;
        return jobListRow(job, previous);
    });
    table.innerHTML = rows.join('');
}

function surveyorColourClass(surveyorId) {
    const id = Number(surveyorId || 0);
    return 'surveyor-colour-' + Math.abs(id % 6);
}

function loadDiarySurveyorData() {
    fetch(ROOT_URL + '/includes/admin/admin_get_surveyors.php?tenant=' + TENANT_URL)
        .then(response => response.json())
        .then(data => {
            allSurveyors = data.surveyors || [];
            populateSurveyorSelects();
        });
}

function populateSurveyorSelects() {
    const surveyorSelect = document.getElementById('surveyorSelect');
    const surveyorFilter = document.getElementById('surveyorFilter');
    const detailSurveyor = document.getElementById('detailSurveyor');
    surveyorSelect.innerHTML = '<option value="">Select Surveyor</option>';
    surveyorFilter.innerHTML = '<option value="">All surveyors</option>';
    detailSurveyor.innerHTML = '';
    allSurveyors.forEach(surveyor => {
        const label = `${surveyor.forename} ${surveyor.surname}`;
        surveyorSelect.innerHTML += `<option value="${surveyor.id}">${escapeHtml(label)}</option>`;
        surveyorFilter.innerHTML += `<option value="${surveyor.id}">${escapeHtml(label)}</option>`;
        detailSurveyor.innerHTML += `<option value="${surveyor.id}">${escapeHtml(label)}</option>`;
    });
}

function loadLocationOptions(clientSelectId, locationSelectId, selectedLocation = '') {
    const clientId = document.getElementById(clientSelectId).value || document.getElementById('detailClientId').value;
    const locationSelect = document.getElementById(locationSelectId);
    locationSelect.innerHTML = '<option value="">Whole client / no site</option>';
    if (!clientId) return Promise.resolve();
    return fetch(ROOT_URL + '/includes/admin/admin_get_locations.php?tenant=' + TENANT_URL + '&client_id=' + encodeURIComponent(clientId))
        .then(response => response.json())
        .then(data => {
            (data.locations || []).forEach(location => {
                const selected = String(location.locnumber) === String(selectedLocation) ? 'selected' : '';
                const label = `${location.locname}${location.postcode ? ' - ' + location.postcode : ''}`;
                locationSelect.innerHTML += `<option value="${location.locnumber}" ${selected}>${escapeHtml(label)}</option>`;
            });
        });
}

function assignSurveyor() {
    const clientId = document.getElementById('clientSelect').value;
    const surveyorId = document.getElementById('surveyorSelect').value;
    const dateValue = document.getElementById('appointmentDate').value;
    const startValue = document.getElementById('startTime').value;
    const endValue = document.getElementById('endTime').value;
    const appointmentDate = dateToTimestamp(dateValue);
    if (!clientId || !surveyorId || !appointmentDate) {
        showResponse('warning', 'Please select a client, surveyor and date.');
        return;
    }
    const body = new URLSearchParams({
        tenant: TENANT_URL,
        client_id: clientId,
        surveyor_id: surveyorId,
        appointment_date: appointmentDate,
        location_id: document.getElementById('locationSelect').value,
        start_time: timeToTimestamp(dateValue, startValue),
        end_time: timeToTimestamp(dateValue, endValue),
        notes: document.getElementById('assignmentNotes').value
    });
    const clientName = selectedText('clientSelect').split(' - ')[0];
    fetch(ROOT_URL + '/includes/admin/admin_assign_surveyor.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body.toString()
    })
    .then(response => response.text().then(text => {
        if (!response.ok) throw new Error(text || response.statusText);
        return text;
    }))
    .then(data => {
        if (data.includes('success')) {
            showResponse('success', data.replace('success:', '').trim() || 'Surveyor assigned successfully.');
            sendAssignmentNotification(surveyorId, clientName);
            loadAssignedJobs();
            toggleView('assigned');
        } else if (data.includes('already exists') || data.includes('overlaps')) {
            showResponse('warning', data.replace('error:', '').trim());
        } else {
            showResponse('danger', data.replace('error:', '').trim() || data || 'Error assigning surveyor.');
        }
    })
    .catch(error => showResponse('danger', error.message || 'Error assigning surveyor.'));
}

function openAssignmentDetails(jobId) {
    const job = allJobs.find(row => Number(row.id) === Number(jobId));
    if (!job) return;
    document.getElementById('detailAssignmentId').value = job.id;
    document.getElementById('detailClientId').value = job.clientnumber;
    document.getElementById('detailClient').value = job.clientname || '';
    document.getElementById('detailSurveyor').value = job.surveyor_id;
    document.getElementById('detailStatus').value = statusValue(job.status);
    document.getElementById('detailDate').value = dateInputValue(job.appointment_date);
    document.getElementById('detailStart').value = timeInputValue(job.start_time);
    document.getElementById('detailEnd').value = timeInputValue(job.end_time);
    document.getElementById('detailNotes').value = job.notes || '';
    document.getElementById('detailUiEstimate').dataset.uiUnits = Number(job.ui_units_due || 0);
    document.getElementById('detailUiEstimate').dataset.uiMissing = Number(job.ui_missing_due || 0);
    renderDetailUiEstimate();
    const map = document.getElementById('detailMapLink');
    map.innerHTML = job.map_query ? `<button type="button" class="btn btn-outline-secondary btn-sm" onclick="openJobMapModal(${job.id})"><i class="fad fa-map-location-dot"></i> Open Map</button>` : '';
    loadLocationOptions('detailClientId', 'detailLocation', job.location_id).then(() => {
        new mdb.Modal(document.getElementById('assignmentDetailModal')).show();
    });
}

function renderDetailUiEstimate() {
    const estimate = document.getElementById('detailUiEstimate');
    if (!estimate) return;
    const units = Number(estimate.dataset.uiUnits || 0);
    const missing = Number(estimate.dataset.uiMissing || 0);
    const minutes = units * 15;
    const parts = [`Estimated inspection time: <strong>${formatUiUnits(units)} UI</strong> (${formatMinutes(minutes)}).`];
    if (missing > 0) parts.push(`${missing} due/overdue item${missing === 1 ? '' : 's'} do not have a UI value.`);
    estimate.innerHTML = parts.join(' ');
    estimate.style.display = '';
    updateDetailUiWarning();
}

function updateDetailUiWarning() {
    const warning = document.getElementById('detailUiWarning');
    const estimate = document.getElementById('detailUiEstimate');
    if (!warning || !estimate) return;
    const units = Number(estimate.dataset.uiUnits || 0);
    const expectedMinutes = units * 15;
    const dateValue = document.getElementById('detailDate').value;
    const start = timeToTimestamp(dateValue, document.getElementById('detailStart').value);
    const end = timeToTimestamp(dateValue, document.getElementById('detailEnd').value);
    warning.style.display = 'none';
    warning.innerHTML = '';
    if (!expectedMinutes || !start || !end) return;
    const scheduledMinutes = Math.max(0, (Number(end) - Number(start)) / 60);
    if (scheduledMinutes < expectedMinutes) {
        warning.innerHTML = `Scheduled time is ${formatMinutes(scheduledMinutes)}, but the UI estimate is ${formatMinutes(expectedMinutes)}. Short by ${formatMinutes(expectedMinutes - scheduledMinutes)}.`;
        warning.style.display = '';
    }
}

function formatUiUnits(units) {
    return Number(units || 0).toFixed(2).replace(/\.?0+$/, '');
}

function formatMinutes(minutes) {
    minutes = Math.round(Number(minutes || 0));
    if (minutes < 60) return minutes + ' mins';
    const hours = Math.floor(minutes / 60);
    const rem = minutes % 60;
    return hours + 'h' + (rem ? ' ' + rem + 'm' : '');
}

function showAssignmentMapModal() {
    const modalElement = document.getElementById('assignmentMapModal');
    if (!modalElement) return;
    const modal = new mdb.Modal(modalElement);
    modal.show();
    modalElement.style.zIndex = 1085;
    setTimeout(function() {
        const backdrops = document.querySelectorAll('.modal-backdrop');
        const backdrop = backdrops[backdrops.length - 1];
        if (backdrop) backdrop.style.zIndex = 1080;
    }, 0);
}

function openJobMapModal(jobId, encodedOrigin = '') {
    const job = allJobs.find(row => Number(row.id) === Number(jobId));
    if (!job || !job.map_query) return;
    document.getElementById('mapDestination').value = job.map_query;
    document.getElementById('mapOrigin').value = encodedOrigin ? decodeURIComponent(encodedOrigin) : '';
    if (encodedOrigin) {
        renderJobMapRoute();
    } else {
        renderJobMapLocation();
    }
    showAssignmentMapModal();
}

function renderJobMapLocation() {
    const destination = document.getElementById('mapDestination').value;
    const url = 'https://maps.google.com/maps?q=' + encodeURIComponent(destination) + '&z=14&output=embed';
    const frame = document.getElementById('assignmentMapFrame');
    frame.removeAttribute('srcdoc');
    frame.src = url;
    document.getElementById('mapExternalLink').href = 'https://www.google.com/maps/search/?api=1&query=' + encodeURIComponent(destination);
    setRouteSummary('mapRouteSummary', '');
}

function renderJobMapRoute() {
    const origin = document.getElementById('mapOrigin').value.trim();
    const destination = document.getElementById('mapDestination').value;
    if (!origin) {
        renderJobMapLocation();
        return;
    }
    const externalUrl = 'https://www.google.com/maps/dir/?api=1&origin=' + encodeURIComponent(origin) + '&destination=' + encodeURIComponent(destination);
    document.getElementById('mapExternalLink').href = externalUrl;
    calculateRouteMetrics(origin, destination, 'mapRouteSummary', 'assignmentMapFrame');
}

function useGpsForJobMap() {
    if (!navigator.geolocation) {
        setRouteSummary('mapRouteSummary', 'GPS is not available in this browser.');
        return;
    }
    setRouteSummary('mapRouteSummary', 'Finding your location...');
    navigator.geolocation.getCurrentPosition(function(position) {
        document.getElementById('mapOrigin').value = position.coords.latitude.toFixed(6) + ',' + position.coords.longitude.toFixed(6);
        renderJobMapRoute();
    }, function(error) {
        setRouteSummary('mapRouteSummary', 'GPS location could not be used: ' + error.message);
    }, { enableHighAccuracy: true, timeout: 10000, maximumAge: 60000 });
}

function setRouteSummary(targetId, message) {
    const target = document.getElementById(targetId);
    if (!target) return;
    target.style.display = message ? '' : 'none';
    target.textContent = message || '';
}

function parseLatLng(value) {
    const match = String(value || '').trim().match(/^(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/);
    if (!match) return null;
    return { lat: parseFloat(match[1]), lon: parseFloat(match[2]) };
}

function extractUkPostcode(value) {
    const matches = String(value || '').toUpperCase().match(/[A-Z]{1,2}\d[A-Z\d]?\s*\d[A-Z]{2}/g) || [];
    for (const candidate of matches) {
        const postcode = normaliseUkPostcode(candidate);
        if (postcode) return postcode;
    }
    const compactMatches = String(value || '').toUpperCase().replace(/[^A-Z0-9]/g, ' ').split(/\s+/);
    for (const candidate of compactMatches) {
        const postcode = normaliseUkPostcode(candidate);
        if (postcode) return postcode;
    }
    return '';
}

function normaliseUkPostcode(postcode) {
    const clean = String(postcode || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
    if (!/^[A-Z]{1,2}\d[A-Z\d]?\d[A-Z]{2}$/.test(clean)) return '';
    return clean.slice(0, -3) + ' ' + clean.slice(-3);
}

function fetchJsonWithTimeout(url, timeoutMs = 8000) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), timeoutMs);
    return fetch(url, { signal: controller.signal })
        .then(response => {
            clearTimeout(timeout);
            if (!response.ok) {
                const error = new Error('Request failed with status ' + response.status);
                error.status = response.status;
                throw error;
            }
            return response.json();
        })
        .catch(error => {
            clearTimeout(timeout);
            throw error;
        });
}

function geocodePostcode(postcode) {
    return fetchJsonWithTimeout('https://api.postcodes.io/postcodes/' + encodeURIComponent(postcode), 5000)
        .then(data => {
            if (data && data.result) return { lat: data.result.latitude, lon: data.result.longitude };
            return Promise.reject();
        });
}

function geocodeMapQuery(value) {
    const query = String(value || '').trim();
    const coords = parseLatLng(value);
    if (coords) return Promise.resolve(coords);

    const postcode = extractUkPostcode(query);
    if (postcode) {
        return geocodePostcode(postcode).catch(() => geocodeAddressFallbacks(query, postcode));
    }
    return geocodeAddressFallbacks(query, '').catch(() => Promise.reject(new Error('Unable to geocode ' + query)));
}

function geocodeAddressFallbacks(query, postcode) {
    const parts = String(query || '').split(',').map(part => part.trim()).filter(Boolean);
    const attempts = [query];
    if (parts.length > 3) attempts.push(parts.slice(-3).join(', '));
    if (parts.length > 2) attempts.push(parts.slice(-2).join(', '));
    if (postcode) attempts.push(postcode);
    const uniqueAttempts = attempts.filter((attempt, index) => attempt && attempts.indexOf(attempt) === index);

    return uniqueAttempts.reduce((chain, attempt) => {
        return chain.catch(() => geocodeMapQueryWithNominatim(attempt));
    }, Promise.reject());
}

function geocodeMapQueryWithNominatim(value) {
    return fetchJsonWithTimeout('https://nominatim.openstreetmap.org/search?format=json&limit=1&q=' + encodeURIComponent(value), 8000)
        .then(data => {
            if (data && data[0]) return { lat: parseFloat(data[0].lat), lon: parseFloat(data[0].lon) };
            return Promise.reject();
        });
}

function calculateRouteMetrics(origin, destination, targetId, frameId) {
    setRouteSummary(targetId, 'Calculating distance and travel time...');
    Promise.all([geocodeMapQuery(origin), geocodeMapQuery(destination)])
        .then(points => {
            const from = points[0];
            const to = points[1];
            const url = 'https://router.project-osrm.org/route/v1/driving/' + from.lon + ',' + from.lat + ';' + to.lon + ',' + to.lat + '?overview=full&geometries=geojson';
            return fetchJsonWithTimeout(url, 10000)
                .then(data => {
                    if (!data.routes || !data.routes[0]) return Promise.reject();
                    const route = data.routes[0];
                    renderRoutePreviewMap(frameId, from, to, route.geometry && route.geometry.coordinates ? route.geometry.coordinates : []);
                    setRouteSummary(targetId, 'Approx driving distance: ' + formatDistance(route.distance) + '. Approx travel time: ' + formatDuration(route.duration) + '. Use Open for the full live Google route if needed.');
                });
        })
        .catch(() => {
            setRouteSummary(targetId, 'Route estimate is unavailable. Use Open for live Google Maps distance and traffic.');
        });
}

function renderRoutePreviewMap(frameId, from, to, coordinates) {
    const frame = document.getElementById(frameId);
    if (!frame) return;
    const route = (coordinates || []).map(point => [point[1], point[0]]);
    if (!route.length) route.push([from.lat, from.lon], [to.lat, to.lon]);
    const html = `<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<style>html,body,#map{height:100%;margin:0}.leaflet-container{font:12px Arial,sans-serif}</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"><\/script>
<script>
const route = ${JSON.stringify(route)};
const from = ${JSON.stringify([from.lat, from.lon])};
const to = ${JSON.stringify([to.lat, to.lon])};
const map = L.map('map', { scrollWheelZoom: false });
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '&copy; OpenStreetMap' }).addTo(map);
const line = L.polyline(route, { color: '#24445f', weight: 5, opacity: 0.9 }).addTo(map);
L.circleMarker(from, { radius: 7, color: '#24445f', fillColor: '#ffffff', fillOpacity: 1, weight: 3 }).addTo(map).bindTooltip('From');
L.marker(to).addTo(map).bindTooltip('Job location');
map.fitBounds(line.getBounds().pad(0.18));
<\/script>
</body>
</html>`;
    frame.removeAttribute('src');
    frame.srcdoc = html;
}

function formatDistance(metres) {
    const miles = metres / 1609.344;
    return miles >= 10 ? miles.toFixed(0) + ' miles' : miles.toFixed(1) + ' miles';
}

function formatDuration(seconds) {
    const mins = Math.round(seconds / 60);
    if (mins < 60) return mins + ' mins';
    const hours = Math.floor(mins / 60);
    const rem = mins % 60;
    return hours + 'h' + (rem ? ' ' + rem + 'm' : '');
}

function saveAssignmentDetails() {
    const dateValue = document.getElementById('detailDate').value;
    const body = new URLSearchParams({
        tenant: TENANT_URL,
        assignment_id: document.getElementById('detailAssignmentId').value,
        client_id: document.getElementById('detailClientId').value,
        surveyor_id: document.getElementById('detailSurveyor').value,
        location_id: document.getElementById('detailLocation').value,
        appointment_date: dateToTimestamp(dateValue),
        start_time: timeToTimestamp(dateValue, document.getElementById('detailStart').value),
        end_time: timeToTimestamp(dateValue, document.getElementById('detailEnd').value),
        notes: document.getElementById('detailNotes').value,
        status: document.getElementById('detailStatus').value
    });
    fetch(ROOT_URL + '/includes/admin/admin_update_assignment.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body.toString()
    })
    .then(response => response.text())
    .then(data => {
        if (data.trim() === 'success') {
            showResponse('success', 'Assignment updated.');
            killModal('assignmentDetailModal');
            loadAssignedJobs();
        } else {
            showResponse('warning', data.replace('error:', '').trim() || 'Assignment could not be updated.');
        }
    });
}

function openAdminMessageModal(assignmentId, recipientId) {
    document.getElementById('adminAssignmentId').value = assignmentId;
    document.getElementById('recipient_id').value = recipientId;
    new mdb.Modal(document.getElementById('adminMessageModal')).show();
}

document.getElementById('adminMessageForm').addEventListener('submit', function(e) {
    e.preventDefault();
    const formData = new FormData(this);
    fetch(ROOT_URL + '/includes/admin/send_message_admin.php?tenant=' + TENANT_URL, {
        method: 'POST',
        body: formData
    })
    .then(response => response.text())
    .then(data => {
        if (data === 'success') {
            showResponse('success', 'Message sent successfully.');
            document.getElementById('adminMessageContent').value = '';
            killModal('adminMessageModal');
        } else {
            showResponse('danger', 'Failed to send message.');
        }
    });
});

function sendAssignmentNotification(surveyorId, clientName) {
    const message = `You have been assigned to ${clientName}.`;
    fetch(ROOT_URL + '/includes/admin/admin_send_assignment_notification.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: `surveyor_id=${surveyorId}&message=${encodeURIComponent(message)}&tenant=${TENANT_URL}`
    });
}

function toggleView(view) {
    document.getElementById('assignedJobsSection').style.display = view === 'assignForm' ? 'none' : 'block';
    document.getElementById('assignFormSection').style.display = view === 'assignForm' ? 'block' : 'none';
    if (view !== 'assignForm' && calendar) {
        calendar.render();
        calendar.updateSize();
    }
}

function openRemoveModal(assignmentId, surveyorId, clientId, clientName) {
    document.getElementById('confirmMessage').textContent = `Are you sure you want to remove the assignment for ${clientName}?`;
    document.getElementById('pauseMessage').textContent = `Pause access permissions for ${clientName}?`;
    const removeModal = new mdb.Modal(document.getElementById('removeAssignmentModal'));
    removeModal.show();
    document.getElementById('confirmRemoveButton').onclick = function() {
        confirmRemoveAssignment(assignmentId, surveyorId, clientId, clientName);
        removeModal.hide();
    };
}

function openRemoveModalForJob(jobId) {
    const job = allJobs.find(row => Number(row.id) === Number(jobId));
    if (!job) return;
    openRemoveModal(job.id, job.surveyor_id, job.clientnumber, job.clientname || '');
}

function confirmRemoveAssignment(assignmentId, surveyorId, clientId, clientName) {
    const pauseSurveyorClient = document.getElementById('pauseSurveyorAssignmentsToggle').checked;
    const removeSurveyorClient = document.getElementById('removeSurveyorAssignmentsToggle').checked;
    let body = `assignment_id=${assignmentId}&surveyor_id=${surveyorId}&client_id=${clientId}&client_name=${encodeURIComponent(clientName)}&tenant=${TENANT_URL}`;
    if (pauseSurveyorClient) body += '&pause_surveyor_client=true';
    if (removeSurveyorClient) body += '&remove_surveyor_client=true';
    fetch(ROOT_URL + '/includes/admin/admin_remove_assignment.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: body
    })
    .then(response => response.text())
    .then(data => {
        if (data === 'success') {
            showResponse('success', `Assignment for ${clientName} has been removed.`);
            loadAssignedJobs();
        } else {
            showResponse('danger', 'Error processing the request.');
        }
    });
}

function toggleOtherCheckbox(action) {
    if (action === 'pause') document.getElementById('removeSurveyorAssignmentsToggle').checked = false;
    if (action === 'remove') document.getElementById('pauseSurveyorAssignmentsToggle').checked = false;
}

function statusBadge(status) {
    if (status === 'Completed') return 'bg-success';
    if (status === 'In Progress') return 'bg-warning';
    return 'bg-danger';
}

function statusClass(status) {
    if (status === 'Completed') return 'success-color-dark';
    if (status === 'In Progress') return 'warning-color-dark';
    return 'danger-color-dark';
}

function statusValue(status) {
    if (status === 'Completed') return '2';
    if (status === 'In Progress') return '1';
    return '0';
}

function itemsDue(job) {
    return `<div class="assignment-due-chips">
        <span class="assignment-due-chip text-danger">Overdue ${Number(job.overdue || 0)}</span>
        <span class="assignment-due-chip text-warning">Today ${Number(job.due_today || 0)}</span>
        <span class="assignment-due-chip text-primary">Week ${Number(job.due_this_week || 0)}</span>
        <span class="assignment-due-chip text-info">Month ${Number(job.due_this_month || 0)}</span>
    </div>`;
}

function formatJobDate(job) {
    const date = dateInputValue(job.appointment_date).split('-').reverse().join('-');
    const start = timeInputValue(job.start_time);
    const end = timeInputValue(job.end_time);
    return `${date}${start ? `<br><small>${start}${end ? ' - ' + end : ''}</small>` : ''}`;
}

function dateToTimestamp(value) {
    if (!value) return '';
    const date = new Date(value + 'T00:00:00');
    return Math.floor(date.getTime() / 1000);
}

function timeToTimestamp(dateValue, timeValue) {
    if (!dateValue || !timeValue) return '';
    const date = new Date(dateValue + 'T' + timeValue + ':00');
    return Math.floor(date.getTime() / 1000);
}

function dateInputValue(timestamp) {
    if (!timestamp) return '';
    const date = new Date(Number(timestamp) * 1000);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

function timeInputValue(timestamp) {
    if (!timestamp) return '';
    const date = new Date(Number(timestamp) * 1000);
    return date.toTimeString().slice(0, 5);
}

function selectedText(id) {
    const select = document.getElementById(id);
    return select.options[select.selectedIndex] ? select.options[select.selectedIndex].text : '';
}

function escapeHtml(value) {
    return String(value || '').replace(/[&<>"']/g, function(chr) {
        return ({'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;'}[chr]);
    });
}

</script>
