using Data.SeaHavenIndustries; using SeaHaven.DataServices.Models; namespace SeaHaven.DataServices.Interfaces { public interface IVendorDataService { Task GetByIdAsync(int id); Task GetByIdWithDetailsAsync(int id); // Batched lookup: one query for the distinct requested ids, preserving input order // and skipping any ids that are not present (no rows returned for missing ids). Task> GetByIdsOrderedAsync(IReadOnlyCollection ids, CancellationToken cancellationToken); Task> GetAllAsync(); Task> GetActiveVendorsAsync(CancellationToken cancellationToken); // SH-249: canonical trade vocabulary (server-owned reference data) for // vendor facets. Active trades ordered by SortOrder then Name; independent // of technician Vendor.TradeSpecialties free text. Task> GetActiveTradesAsync(CancellationToken cancellationToken); // SH-278: active (non-archived) Area catalogue rows for vendor facets and for // resolving areas[n] filter ids. Archived Areas are excluded. Task> GetActiveAreasAsync(CancellationToken cancellationToken); // SH-198 facet fix: company-owned facet profiles sourced from VendorCompanies, // with status semantics aligned to BuildDirectoryUnionQuery. Null returns all // companies; active includes companies with zero non-deleted technicians or at // least one active non-deleted technician; inactive includes companies with at // least one inactive non-deleted technician. Task> GetCompaniesForFacetsAsync(bool? isActive, CancellationToken cancellationToken); Task<(IEnumerable Items, int TotalCount)> GetPagedAsync( int page, int pageSize, string? search = null, bool? isActive = true, IReadOnlyCollection? companies = null, IReadOnlyCollection? trades = null, IReadOnlyCollection? locations = null, IReadOnlyCollection? jobBuckets = null); // Compatibility path for existing per-technician consumers (GetVendorList) // and behavior tests. GetVendorDirectoryList uses the company-grouped path // below. Task<(IReadOnlyList Items, int TotalCount)> GetDirectoryPagedAsync( int page, int pageSize, string? search = null, bool? isActive = true, IReadOnlyCollection? companies = null, IReadOnlyCollection? trades = null, IReadOnlyCollection? locations = null, IReadOnlyCollection? jobBuckets = null, CancellationToken cancellationToken = default); // SH-281 company directory: linked vendors group by real CompanyId; unlinked // legacy vendors group by trimmed case-insensitive CompanyName (missing names // isolated by vendor identity); company-only groups remain. Facet filters // select a group when any status-eligible row matches; job buckets apply to // the summed per-technician TotalJobs. Bounded group keys are selected and // paginated in SQL, then the full status-eligible roster is fetched only for // those keys (search/trade/location are not reapplied). TotalCount counts // company groups. Task<(IReadOnlyList Items, int TotalCount)> GetCompanyDirectoryPagedAsync( int page, int pageSize, string? search = null, bool? isActive = true, IReadOnlyCollection? companies = null, IReadOnlyCollection? trades = null, IReadOnlyCollection? locations = null, IReadOnlyCollection? jobBuckets = null, VendorAreaFilter? areaFilter = null, CancellationToken cancellationToken = default); Task AddAsync(Vendor vendor); Task UpdateAsync(Vendor vendor); Task DeleteAsync(int id); Task ExistsAsync(int id); Task GetActiveTokenForVendorAsync(int vendorId, CancellationToken cancellationToken); Task GetTokenWithVendorAsync(string token, CancellationToken cancellationToken); Task AddTokenAsync(VendorAccessToken token, CancellationToken cancellationToken); Task> GetRevocableTokensAsync(int vendorId, CancellationToken cancellationToken); Task SaveChangesAsync(CancellationToken cancellationToken); Task CountAsync(); Task GetCompanyByIdAsync(int id); Task GetCompanyByNormalizedNameAsync(string normalizedName); Task AddCompanyAsync(VendorCompany company); Task UpdateCompanyAsync(VendorCompany company); Task> GetLinkedWorkOrdersAsync(int vendorId); Task IsVendorAssignedToWorkOrderAsync(int vendorId, int workOrderId); Task UpdateWithAuditLogsAsync(Vendor vendor, IReadOnlyCollection auditLogs); } }