﻿@page

"/workorders/selectedlist"
@using Blazored.Toast.Services
@using MaasOffline.Models.DTOs
@using MaasOffline.Models.Entities
@using Microsoft.AspNetCore.Components.Web
@inject NavigationManager navigationManager
@inject IOfflineStorageService StorageService
@inject IToastService ToastService
@inject IJSRuntime JSRuntime
@inject ILogger<SelectedList > _logger
@inject IWorkOrderApiService WorkOrderService
@inject IIndexedDbService IndexedDbService

<PageTitle > Work Orders List</PageTitle >

<div class="selectedlist-container" >
<div class="content-wrapper" >
<WorkOrderHeader / >

<div class="main-card" >
<!-- Header Section with gradient like Dashboard -->
<div class="card-header" >
<div class="header-content" >
<h3 class="card-title" >
<i class="bi bi-clipboard-check" > </i >
Work Orders List
</h3 >
@if (isInitialized) {
    <div class="button-group"> <button type="button" class="btn @(isForMeOn ? "btn-primary" : "btn-outline-primary") btn-wider" @onclick="ForMeClick" disabled="@isForMeOn">My WOs</button> <button type="button" class="btn @(!isForMeOn ? "btn-primary" : "btn-outline-primary") btn-wider" @onclick="TurnOffForMe" disabled="@(!isForMeOn)">All WOs</button> </div>
}

</div >
</div >

@if (_isLoading) {
    <div class="loading-spinner text-center"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">Loading...</span> </div> <p>Loading work orders...</p> </div>
}

else {
    <div class="sync-content">
    <!-- Filter Toggle and Visibility Options -->
    <div class="filter-options d-flex justify-content-between align-items-center"> <div class="d-flex gap-2"> <button class="btn btn-sm btn-outline-primary" @onclick="ToggleFilter" aria-controls="filters-panel" aria-expanded="@isFilterVisible"> <i class="bi bi-funnel"></i> @(isFilterVisible ? "Hide Filters" : "Filters") </button>
    <!-- Clear Filters button (also closes the panel) -->
    <button class="btn btn-sm btn-outline-secondary" @onclick="ClearAndHideFilters" disabled="@_isLoading"> <i class="bi bi-x-circle"></i> Clear Filters </button> </div>
    <!-- Combined toggle control -->
    <div class="display-toggle"> <select class="form-select form-select-sm" @onchange="OnDisplaySelectChanged"> <option value="true" selected="@showWorkOrderId">WO #</option> <option value="false" selected="@(!showWorkOrderId)">Invoice #</option> </select> </div> </div>
    <!-- Collapsible Filter Section -->
    <div class="filter-section"> <div id="filters-panel" class="filter-body" aria-hidden="@(!isFilterVisible)" style="@(!isFilterVisible ? "display:none" : null)"> <div class="filter-grid row align-items-end"> <div class="filter-item col-md-4 mb-2"> <select class="form-select" value="@searchCriteria.CategoryId" @onchange="OnCategoryChanged" disabled="@_isLoading"> <option value="-1">All Categories</option> @foreach (var category in categories)

{
    <option value="@category.Id">@category.CategoryName</option>
}

</select >
</div >
<div class="filter-item col-md-4 mb-2" >
<select class="form-select" value="@searchCriteria.PhaseSection" disabled="@_isLoading" @onchange="OnSectionChanged" >
<option value="" selected > All Sections</option >
@foreach (var phase in filteredPhaseSections) {
    <option value="@phase">@phase</option>
}

</select >
</div >
<!-- Site input group -->
<div class="filter-item col-md-4 mb-2 position-relative" >
<div class="input-group" >
<input type="text"
class="form-control"
placeholder="Site Number"
@bind="siteSearchText"
@bind:event="oninput"
@onkeydown="OnSiteKeyDown"
disabled="@_isLoading" / >

<button type="button"
class="btn btn-primary"
title="Apply site filter"
@onclick="ApplySiteFilter"
disabled="@_isLoading" >
<i class="bi bi-funnel" > </i > &nbsp;Apply
</button >

<button type="button"
class="btn btn-outline-secondary"
title="Clear site"
@onclick="ClearSiteFilter"
disabled="@_isLoading" >
<i class="bi bi-x-circle" > </i > &nbsp;Clear
</button >
</div >
</div >
</div >
</div >
</div >
<!-- Work Orders Table -->
<div class="updates-section" >
<div class="updates-header" >
<h4 class="section-title" > Work Orders (Count: @filteredWorkOrders.Count)</h4 >
</div >

<div class="table-container" >
<table class="table table-hover table-bordered table-striped" >
<thead class="sticky-top" >
<tr >
@if (showWorkOrderId) {
    <th @onclick="() => SortTable(nameof(WorkOrderDto.Id))"> WO # @(RenderSortIndicator(nameof(WorkOrderDto.Id))) </th>
}

else {
    <th @onclick="() => SortTable(nameof(WorkOrderDto.Title))"> Inv # @(RenderSortIndicator(nameof(WorkOrderDto.Title))) </th>
}

<th @onclick="() => SortTable(nameof(WorkOrderDto.PhaseSection))" >
Sec @(RenderSortIndicator(nameof(WorkOrderDto.PhaseSection)))
</th >
<th @onclick="() => SortTable(nameof(WorkOrderDto.SiteNumber))" >
Site @(RenderSortIndicator(nameof(WorkOrderDto.SiteNumber)))
</th >
<th @onclick="() => SortTable(nameof(WorkOrderDto.CategoryName))" >
Cat @(RenderSortIndicator(nameof(WorkOrderDto.CategoryName)))
</th >
<th @onclick="() => SortTable(nameof(WorkOrderDto.StatusName))" >
Status @(RenderSortIndicator(nameof(WorkOrderDto.StatusName)))
</th >
<th class="attachments-column" >
<i class="bi bi-paperclip" title="Attachments" > </i >
</th >
</tr >
</thead >
<tbody >
@foreach (var workOrder in filteredWorkOrders) {
    <tr> @if (showWorkOrderId)

{
    <td @onclick="() => EditWorkOrder(workOrder)" class="@(GetRowClasses(workOrder.Id))" style="cursor: pointer;"> @workOrder.Id </td>
}

else {
    <td @onclick="() => EditWorkOrder(workOrder)" class="@(GetRowClasses(workOrder.Id))" style="cursor: pointer;"> @(Int32.TryParse(workOrder.Title, out x) ? workOrder.Title : "") </td>
}

<td @onclick="() => EditWorkOrder(workOrder)"
class="@(GetRowClasses(workOrder.Id))"
style="cursor: pointer;" >
@workOrder.PhaseSection
</td >
<td @onclick="() => EditWorkOrder(workOrder)"
class="@(GetRowClasses(workOrder.Id))"
style="cursor: pointer;" >
<div class="d-flex align-items-center" >
@if (selectedRowId == workOrder.Id && rowLoading) {
    <div class="spinner-border spinner-border-sm me-2" role="status"> <span class="visually-hidden">Loading...</span> </div>
}

@workOrder.SiteNumber </div> </td> <td @onclick="() => EditWorkOrder(workOrder)" class="@(GetRowClasses(workOrder.Id))" style="cursor: pointer;"> @workOrder.CategoryName </td> <td @onclick="() => EditWorkOrder(workOrder)" class="@(GetRowClasses(workOrder.Id))" style="cursor: pointer;"> <span class="status-pill @GetStatusColor(workOrder.StatusName)"> <span class="d-none d-sm-inline">@workOrder.StatusName</span> <span class="d-inline d-sm-none">@GetStatusInitial(workOrder.StatusName)</span> </span> </td> <td class="attachments-column text-center"> @if (workOrderAttachments.ContainsKey(workOrder.Id) && workOrderAttachments[workOrder.Id] > 0) {
    <button class="btn btn-sm btn-link p-0 attachment-indicator" @onclick="() => ViewAttachments(workOrder.Id)" title="View @workOrderAttachments[workOrder.Id] attachment(s)"> <i class="bi bi-paperclip text-primary"></i> <span class="attachment-count">@workOrderAttachments[workOrder.Id]</span> </button>
}

</td >
</tr >
}
</tbody >
</table >
</div >
</div >
</div >
}

</div >
</div >
</div >

<style >
/* Container with gradient background like Dashboard */
.selectedlist-container {
    min-height: 100vh;
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    padding: 1rem;
}

.content-wrapper {
    max-width: 1200px;
    margin: 0 auto;
}

/* Allow full width on tablets and smaller */
@@media (max-width: 1400px) {
    .content-wrapper {
        max-width: 95%;
    }
}

/* Main card with rounded corners and shadow */
.main-card {
    background: white;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.08);
    overflow: hidden; /* ensure children clip to rounded corners */
    margin: 0.5rem 0;
}

/* Header with gradient background matching Dashboard */
.card-header {
    background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%);
    padding: 0.75rem 1rem;
    border-bottom: 1px solid #e2e8f0;
}

.header-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}

.card-title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    color: #4a5568;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

    .card-title i {
        font-size: 1.5rem;
        color: #667eea;
    }

.button-group {
    display: flex;
    gap: 0.5rem;
}

/* Content area */
.sync-content {
    padding: 0.5rem 0.75rem;
}

/* Filter options bar */
.filter-options {
    margin-bottom: 0.25rem;
}

/* Display toggle dropdown */
.display-toggle select {
    width: 120px;
}

/* Filter section */
.filter-section {
    background: #f8f9ff;
    border-radius: 6px;
    padding: 0.25rem;
    margin-bottom: 0.25rem;
}

.filter-body {
    padding: 0.1rem;
}

/* Updates section for table - full width inside card */
.updates-section {
    background: white;
    padding: 0 0.75rem 0.75rem;
    height: calc(100vh - 200px);
}

.updates-header {
    padding: 0.1rem 0;
    margin-bottom: 0.1rem;
    border-bottom: none;
}

.section-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: #4a5568;
}

/* Table container */
.table-container {
    overflow-x: auto;
    overflow-y: auto;
    max-height: calc(100vh - 250px);
    border-radius: 6px;
}

/* Table styling */
.table {
    margin-bottom: 0;
}

    .table thead {
        background: #f8f9ff;
    }

        .table thead th {
            border-color: #e2e8f0;
            color: #4a5568;
            font-weight: 600;
            cursor: pointer;
            user-select: none;
        }

/* Loading spinner */
.loading-spinner {
    padding: 3rem;
}

/* Status pills */
.status-pill {
    padding: 0.25rem 0.75rem;
    border-radius: 12px;
    font-size: 0.875rem;
    font-weight: 500;
}

    .status-pill.success {
        background: #d1fae5;
        color: #065f46;
    }

    .status-pill.warning {
        background: #fed7aa;
        color: #92400e;
    }

    .status-pill.secondary {
        background: #e5e7eb;
        color: #374151;
    }

/* Attachment indicator */
.attachments-column {
    width: 60px;
    text-align: center;
    cursor: default !important;
}

.attachment-indicator {
    position: relative;
}

.attachment-count {
    position: absolute;
    top: -5px;
    right: -5px;
    background: #ef4444;
    color: white;
    border-radius: 50%;
    width: 18px;
    height: 18px;
    font-size: 0.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
}

/* Row hover and selection */
.table-hover tbody tr:hover {
    background-color: #f3f4f6 !important;
    cursor: pointer;
}

.selected-row {
    background-color: #e0e7ff !important;
}

.row-loading {
    opacity: 0.6;
}

/* --- EDGE-TO-EDGE GRID INSIDE THE ROUNDED CARD --- */
/* Pull only the table area to the card edges; keep other content padded */
.selectedlist-container .table-container {
    margin-left: -0.75rem; /* negate .updates-section horizontal padding */
    margin-right: -0.75rem;
    border-radius: 0; /* let .main-card handle rounding */
    box-shadow: none;
}

.selectedlist-container table {
    width: 100%;
    border-radius: 0;
    box-shadow: none;
}

/* Mobile (iPhone): ensure truly edge-to-edge */
@@media (max-width: 480px) {
    .selectedlist-container .sync-content {
        padding: 0.5rem;
    }
    /* keep nice padding for controls */
    .updates-section {
        padding: 0 0.25rem 0.25rem 0.25rem;
        height: calc(100vh - 180px);
    }

    .table-container {
        max-height: calc(100vh - 220px);
    }

    .selectedlist-container .table-container {
        margin-left: -0.25rem; /* negate the mobile padding above */
        margin-right: -0.25rem;
        border-radius: 0;
    }

    table {
        font-size: 0.85rem;
    }

        table th, table td {
            padding: 0.25rem;
        }

    .status-pill {
        padding: 0.1rem 0.4rem;
        font-size: 0.75rem;
    }

    .attachments-column {
        width: 40px;
        padding: 0.3rem;
    }
}

/* Tablet optimizations */
@@media screen and (min-width: 768px) and (max-width: 1024px) {
    .content-wrapper {
        max-width: 95%;
        padding: 0 1rem;
    }
}

</style >

@code {
    // Data private List<WorkOrderDto> workOrders = new();
    private List<WorkOrderDto> filteredWorkOrders = new();
    private WorkOrderList searchCriteria = new();
    private List<CategoryDto> categories = new();
    private WorkOrderFilters filters = new();
    // Selected WorkOrder List private List<WorkOrderDto> selectedWorkOrders = new();
    private List<string> phaseSections = new();
    private List<string> siteNumbers = new();
    private List<string> filteredPhaseSections = new();
    private List<string> filteredSiteNumbers = new();
    // UI state private bool _isLoading = false;
    private bool isFilterVisible = false;
    // hidden by default private bool isFilterApplying = false;
    private int? selectedRowId = null;
    private bool rowLoading = false;
    private string siteSearchText = string.Empty;
    private bool isSiteDropdownVisible = false;
    private bool isNewWorkOrder = false;
    // Column visibility toggle - true shows Work Order ID, false shows Invoice Number private bool showWorkOrderId = true;
    // Default to showing Work Order ID // Sorting state private string currentSortField = nameof(WorkOrderDto.Id);
    private bool isAscending = true;
    int x = 0;
    // Sync Options private SyncOptions syncOptions

{
    get;
    set;
}

= new();

// Users List
private List<SystemUser > assignedToUsers {
    get;
    set;
}

= new();

// isForMeOn
private bool isForMeOn {
    get;
    set;
}

= false;
private bool isInitialized {
    get;
    set;
}

= false;

// All Assigned WorkOrders
public List<WorkOrderDto > allAssignedWorkOrders {
    get;
    set;
}

= new();

// Attachment counts per work order
private Dictionary<int, int > workOrderAttachments = new();

// Render sort indicator
private RenderFragment RenderSortIndicator(string field) = > builder = > {
    if (field == currentSortField)

{
    builder .OpenElement(0, "span");
    builder .AddAttribute(1, "class", "sort-indicator");
    builder .AddContent(2, isAscending ? " ▲" : " ▼");
    builder .CloseElement();
}

}

;

private List<string > FilteredSiteSuggestions = > siteNumbers
.Where(s => string.IsNullOrWhiteSpace(siteSearchText) || s.Contains(siteSearchText, StringComparison.OrdinalIgnoreCase))
.OrderBy(s => s)
.ToList();

protected override async Task OnInitializedAsync() {
    _isLoading = true;
    try

{
    // Load user column preferences await LoadColumnPreferences();
    syncOptions = await StorageService.GetSyncOptionsAsync();
    _logger .LogInformation("Loading work orders");
    workOrders = await StorageService.GetWorkOrderUpdatesAsync();
    var lookupData = await StorageService.GetLookupDataAsync();
    // Populate category names from lookup data if (lookupData?.Categories != null && lookupData.Categories.Any())

{
    _logger .LogInformation($"Found {lookupData.Categories.Count()} categories in lookup data");
    var categoryDict = lookupData.Categories.ToDictionary(c => c.Id, c => c.CategoryName);
    int populatedCount = 0;
    int skippedCount = 0;
    foreach (var workOrder in workOrders)

{
    if (categoryDict.TryGetValue(workOrder.CategoryId, out var categoryName))

{
    workOrder .CategoryName = categoryName;
    populatedCount ++;
}

else {
    _logger .LogWarning($"Category ID {workOrder.CategoryId} not found in lookup data for WorkOrder {workOrder.Id}");
    workOrder .CategoryName = "Unknown Category";
    skippedCount ++;
}

}

_logger.LogInformation($"Category population complete: {populatedCount} populated, {skippedCount} skipped");
}

else {
    _logger .LogWarning("No lookup data or categories found");
    foreach (var workOrder in workOrders)

{
    workOrder .CategoryName = "No Categories Available";
}

}

// Load attachment counts
await LoadAttachmentCounts();

// Initial list: optionally scoped to current user
isForMeOn = await StorageService.GetUserPreferences();
if (isForMeOn) {
    filteredWorkOrders = workOrders .Where(w => w.EmployeeId == syncOptions.EmployeeId) .OrderBy(w => w.PhaseSection) .ThenBy(w => w.SiteNumber) .ToList();
    allAssignedWorkOrders .Clear();
    allAssignedWorkOrders .AddRange(filteredWorkOrders);
}

else {
    filteredWorkOrders = workOrders.OrderBy(w => w.PhaseSection).ThenBy(w => w.SiteNumber).ToList();
}

// Load saved filters (use the field, not a local shadow)
var filtersFromStorage = await StorageService.GetFilters();
if (filtersFromStorage != null) {
    filters = filtersFromStorage;
    if (filters.CategoryId > 0 || !string.IsNullOrWhiteSpace(filters.PhaseSection) || !string.IsNullOrWhiteSpace(filters.SiteNumber))

{
    searchCriteria .CategoryId = filters.CategoryId;
    searchCriteria .PhaseSection = filters.PhaseSection;
    searchCriteria .SiteNumber = filters.SiteNumber;
    currentSortField = string.IsNullOrWhiteSpace(filters.CurrentSortField) ? currentSortField : filters.CurrentSortField;
    isAscending = filters.IsAscending;
    SortTable(currentSortField);
    // will persist state await FilterWorkOrders();
}

isFilterVisible = filters.IsFilterVisible;
}

await LoadDropdownData();
filteredPhaseSections = phaseSections;
filteredSiteNumbers = siteNumbers;
siteSearchText = searchCriteria.SiteNumber;

isInitialized = true;
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to load work orders");
    ShowToast("Failed to load work orders", false);
}

finally {
    _isLoading = false;
}

}

private async Task LoadAttachmentCounts() {
    try

{
    workOrderAttachments .Clear();
    // Local attachments from IndexedDB: WOImages var localImages = await IndexedDbService.GetAllAsync("WOImages");
    if (localImages != null)

{
    var localCounts = localImages .Where(img => img.WorkOrderId > 0) .GroupBy(img => img.WorkOrderId) .ToDictionary(g => g.Key, g => g.Count());
    foreach (var kvp in localCounts) workOrderAttachments[kvp.Key] = kvp.Value;
}

// Server attachments mirrored in IndexedDB: WOImagesFromDb
var serverImages = await IndexedDbService.GetAllAsync("WOImagesFromDb");
if (serverImages != null) {
    var serverCounts = serverImages .Where(img => img.WorkOrderId > 0) .GroupBy(img => img.WorkOrderId) .ToDictionary(g => g.Key, g => g.Count());
    foreach (var kvp in serverCounts)

{
    if (workOrderAttachments.ContainsKey(kvp.Key)) workOrderAttachments[kvp.Key] += kvp.Value;
    else workOrderAttachments[kvp.Key] = kvp.Value;
}

}

_logger.LogInformation($"Loaded attachment counts for {workOrderAttachments.Count} work orders");
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to load attachment counts");
}

}

private void ViewAttachments(int workOrderId) {
    navigationManager .NavigateTo($"/view-attachment/{workOrderId}");
}

private async Task LoadDropdownData() {
    try

{
    var lookupData = await StorageService.GetLookupDataAsync();
    if (lookupData != null)

{
    categories = lookupData.Categories.ToList();
    if (lookupData.Memberships != null)

{
    phaseSections = lookupData.Memberships .Where(m => !string.IsNullOrWhiteSpace(m.Section)) .Select(m => m.Section) .Distinct() .OrderBy(s => s) .ToList();
}

else {
    phaseSections = workOrders .Where(w => !string.IsNullOrEmpty(w.PhaseSection)) .Select(w => w.PhaseSection) .Distinct() .OrderBy(p => p) .ToList();
}

}

siteNumbers = workOrders
.Where(w => !string.IsNullOrEmpty(w.SiteNumber))
.Select(w => w.SiteNumber)
.Distinct()
.OrderBy(s => s)
.ToList();
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to load filter options");
    ShowToast("Failed to load filter options", false);
}

}

private async Task OnCategoryChanged(ChangeEventArgs e) {
    searchCriteria .CategoryId = Convert.ToInt32(e.Value);
    UpdateFilteredDropdowns(searchCriteria.CategoryId);
    await FilterWorkOrders();
}

private async Task OnSectionChanged(ChangeEventArgs e) {
    searchCriteria .PhaseSection = Convert.ToString(e.Value) ?? "";
    await FilterWorkOrders();
}

private void UpdateFilteredDropdowns(int categoryId) {
    try

{
    var categoryWorkOrders = categoryId == -1 ? workOrders : workOrders.Where(w => w.CategoryId == categoryId);
    filteredPhaseSections = phaseSections;
    filteredSiteNumbers = categoryWorkOrders .Where(w => !string.IsNullOrEmpty(w.SiteNumber)) .Select(w => w.SiteNumber) .Distinct() .OrderBy(s => s) .ToList();
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to update dropdowns");
    ShowToast("Failed to update dropdowns", false);
}

}

private Task OnSiteSearchInput(ChangeEventArgs e) {
    siteSearchText = e?.Value?.ToString() ?? string.Empty;
    return Task.CompletedTask;
}

private async Task ApplySiteFilter() {
    searchCriteria .SiteNumber = (siteSearchText ?? string.Empty).Trim();
    await FilterWorkOrders();
}

private async Task ClearSiteFilter() {
    siteSearchText = string.Empty;
    searchCriteria .SiteNumber = string.Empty;
    await FilterWorkOrders();
}

private async Task OnSiteKeyDown(KeyboardEventArgs e) {
    if (string.Equals(e?.Key, "Enter", StringComparison.OrdinalIgnoreCase)) await ApplySiteFilter();
}

private async Task FilterWorkOrders() {
    _isLoading = true;
    isFilterApplying = true;
    try

{
    // Apply filters var query = BuildFilterQuery();
    // Apply current sort ApplySorting(ref query);
    filteredWorkOrders = query.ToList();
    // Persist filters filters.CategoryId = searchCriteria.CategoryId;
    filters .PhaseSection = searchCriteria.PhaseSection;
    filters .SiteNumber = searchCriteria.SiteNumber;
    filters .IsFilterVisible = (searchCriteria.CategoryId != -1
                                       || !string.IsNullOrWhiteSpace(searchCriteria.PhaseSection)
                                       || !string.IsNullOrWhiteSpace(searchCriteria.SiteNumber));
    await StorageService.SaveFilters(filters);
    ShowToast("Filters applied successfully");
}

catch (Exception ex) {
    _logger .LogError(ex, "Error applying filters");
    ShowToast("Error applying filters", false);
}

finally {
    _isLoading = false;
    isFilterApplying = false;
}

}

private void SortTable(string field) {
    if (currentSortField == field)

{
    isAscending = !isAscending;
}

else {
    currentSortField = field;
    isAscending = true;
}

filters.CurrentSortField = currentSortField;
filters.IsAscending = isAscending; // persist the actual direction
StorageService.SaveFilters(filters);

// Re-sort the filtered list
var query = filteredWorkOrders.AsQueryable();
ApplySorting(ref query);
filteredWorkOrders = query.ToList();
}

private void ApplySorting(ref IQueryable<WorkOrderDto> query) {
    switch (currentSortField)

{
    case nameof(WorkOrderDto.Id): query = isAscending ? query.OrderBy(w => w.Id) : query.OrderByDescending(w => w.Id);
    break;
    case nameof(WorkOrderDto.Title): query = isAscending ? query.OrderBy(w => w.Title) : query.OrderByDescending(w => w.Title);
    break;
    case nameof(WorkOrderDto.PhaseSection): query = isAscending ? query.OrderBy(w => w.PhaseSection) : query.OrderByDescending(w => w.PhaseSection);
    break;
    case nameof(WorkOrderDto.SiteNumber): query = isAscending ? query.OrderBy(w => w.SiteNumber) : query.OrderByDescending(w => w.SiteNumber);
    break;
    case nameof(WorkOrderDto.CategoryName): query = isAscending ? query.OrderBy(w => w.CategoryName) : query.OrderByDescending(w => w.CategoryName);
    break;
    case nameof(WorkOrderDto.StatusName): query = isAscending ? query.OrderBy(w => w.StatusName) : query.OrderByDescending(w => w.StatusName);
    break;
    default: query = query.OrderBy(w => w.PhaseSection).ThenBy(w => w.SiteNumber);
    break;
}

}

private IQueryable<WorkOrderDto > BuildFilterQuery() {
    IQueryable <WorkOrderDto> query = isForMeOn ? allAssignedWorkOrders.AsQueryable() : workOrders.AsQueryable();
    if (searchCriteria.CategoryId > 0) query = query.Where(w => w.CategoryId == searchCriteria.CategoryId);
    if (!string.IsNullOrWhiteSpace(searchCriteria.PhaseSection)) query = query.Where(w => w.PhaseSection.Equals(searchCriteria.PhaseSection, StringComparison.OrdinalIgnoreCase));
    if (!string.IsNullOrWhiteSpace(searchCriteria.SiteNumber))

{
    var term = searchCriteria.SiteNumber.Trim();
    query = query.Where(w => !string.IsNullOrEmpty(w.SiteNumber) && w.SiteNumber.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0);
}

return query;
}

private void ShowToast(string message, bool isSuccess = true) {
    if (isSuccess) ToastService.ShowSuccess(message);
    else ToastService.ShowError(message);
}

private string GetStatusColor(string? status) = >
status?.ToLower() switch {
    "completed" => "success", "in progress" => "warning", "pending" => "secondary", _ => "secondary"
}

;

private void GoToAddWorkOrderPage() = >
navigationManager.NavigateTo(AppConstants.Routes.addWorkOrder);

private async Task EditWorkOrder(WorkOrderDto workOrder) {
    if (workOrder != null)

{
    selectedRowId = workOrder.Id;
    rowLoading = true;
    StateHasChanged();
    await Task.Delay(500);
    navigationManager .NavigateTo(AppConstants.Routes.addWorkOrder + $"/{workOrder.Id}");
}

}

private void ToggleFilter() = > isFilterVisible = !isFilterVisible;

private async Task SaveColumnPreferences() {
    try

{
    await JSRuntime.InvokeVoidAsync("localStorage.setItem", "showWorkOrderId", showWorkOrderId.ToString());
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to save column preferences");
}

}

private async Task LoadColumnPreferences() {
    try

{
    var savedShowWorkOrderId = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "showWorkOrderId");
    if (!string.IsNullOrEmpty(savedShowWorkOrderId)) showWorkOrderId = bool.Parse(savedShowWorkOrderId);
}

catch (Exception ex) {
    _logger .LogError(ex, "Failed to load column preferences");
}

}

private async Task OnDisplayToggleChanged(bool value) {
    showWorkOrderId = value;
    await SaveColumnPreferences();
}

private async Task OnDisplaySelectChanged(ChangeEventArgs e) {
    if (bool.TryParse(e.Value?.ToString(), out var value))

{
    showWorkOrderId = value;
    await SaveColumnPreferences();
}

}

private string GetRowClasses(int rowId) {
    var classes = new List<string>();
    if (selectedRowId == rowId)

{
    classes .Add("selected-row");
    if (rowLoading) classes.Add("row-loading");
}

return string.Join(" ", classes);
}

private async Task ResetFilters() {
    searchCriteria .CategoryId = -1;
    searchCriteria .PhaseSection = "";
    searchCriteria .SiteNumber = "";
    siteSearchText = "";
    await FilterWorkOrders();
}

private async Task ClearAndHideFilters() {
    await ResetFilters();
    isFilterVisible = false;
}

private async Task ForMeClick() {
    isForMeOn = true;
    await StorageService.SaveUserPreferences(isForMeOn);
    var allWorkOrders = await StorageService.GetWorkOrderUpdatesAsync();
    filteredWorkOrders = allWorkOrders .Where(w => w.EmployeeId == syncOptions.EmployeeId) .OrderBy(w => w.PhaseSection) .ThenBy(w => w.SiteNumber) .ToList();
    allAssignedWorkOrders .Clear();
    allAssignedWorkOrders .AddRange(filteredWorkOrders);
    var lookupData = await StorageService.GetLookupDataAsync();
    if (lookupData?.Categories != null && lookupData.Categories.Any())

{
    var categoryDict = lookupData.Categories.ToDictionary(c => c.Id, c => c.CategoryName);
    foreach (var workOrder in filteredWorkOrders) workOrder.CategoryName = categoryDict.GetValueOrDefault(workOrder.CategoryId, "Unknown Category");
}

}

private async Task TurnOffForMe() {
    isForMeOn = false;
    await StorageService.SaveUserPreferences(isForMeOn);
    workOrders = await StorageService.GetWorkOrderUpdatesAsync();
    filteredWorkOrders = workOrders.OrderBy(w => w.PhaseSection).ThenBy(w => w.SiteNumber).ToList();
}

private string GetStatusInitial(string? status) {
    if (string.IsNullOrWhiteSpace(status)) return "";
    return status.Trim().Substring(0, 1).ToUpper();
}
}
