import '../../l10n/app_localizations.dart';
import '../../models/content_models.dart';
import '../formatting/localized_formatters.dart';
import 'event_labels.dart';
import 'package:intl/intl.dart';
const canonicalRealEstateCategoryKeys = <String>[
'apartment',
'house',
'land',
'temporary-living',
'wg-room',
'garage-parking',
'commercial',
];
bool isCanonicalRealEstateCategory(String key) =>
canonicalRealEstateCategoryKeys.contains(key);
/// Returns the only public transaction choices supported by the real-estate
/// route. Legacy storage aliases are read compatibly, but never become extra
/// UI segments.
List<String> canonicalRealEstateTransactionValues(Iterable<String> values) {
final result = <String>[];
for (final rawValue in values) {
final value = switch (rawValue.trim()) {
'sale' => 'sale',
'rent' || 'lease' || 'temporary' => 'rent',
_ => '',
};
if (value.isNotEmpty && !result.contains(value)) {
result.add(value);
}
}
return result;
}
String localizedCategoryProfileLabel(
AppLocalizations l10n,
String route,
String profileKey,
) {
if (route == 'real-estate') {
return switch (profileKey) {
'apartment' => l10n.categoryApartment,
'house' => l10n.categoryHouse,
'temporary-living' => l10n.categoryTemporaryLiving,
'wg-room' || 'room' => l10n.categoryWgRoom,
'land' => l10n.categoryLand,
'garage-parking' => l10n.categoryGarageParking,
'commercial' => l10n.categoryCommercial,
'office-practice' => l10n.categoryOfficePractice,
'retail-hospitality' => l10n.categoryRetailHospitality,
'warehouse' => l10n.categoryWarehouse,
_ => l10n.categoryFallback,
};
}
if (route == 'classifieds') {
return switch (profileKey) {
'electronics' => l10n.categoryElectronics,
'furniture-home' => l10n.categoryFurnitureHome,
'clothing' => l10n.categoryClothing,
'bikes-sports' => l10n.categoryBikesSports,
'tickets' => l10n.categoryTickets,
'books-media' => l10n.categoryBooksMedia,
'services' => l10n.categoryServices,
_ => l10n.categoryFallback,
};
}
if (route == 'jobs') {
return switch (profileKey) {
'it-tech' => l10n.categoryItTech,
'healthcare' => l10n.categoryHealthcare,
'education' => l10n.categoryEducation,
'office-admin' => l10n.categoryOfficeAdmin,
'retail-hospitality' => l10n.categoryRetailJobs,
'craft-trade' => l10n.categoryCraftTrade,
'public-social' => l10n.categoryPublicSocial,
'culture-creative' => l10n.categoryCultureCreative,
'transport-logistics' => l10n.categoryTransportLogistics,
'apprenticeship-internship' => l10n.categoryApprenticeshipInternship,
_ => l10n.categoryFallback,
};
}
if (route == 'places') {
return switch (profileKey) {
'gastronomy' => l10n.placeCategoryGastronomy,
'leisure' => l10n.placeCategoryLeisure,
'culture' => l10n.placeCategoryCulture,
'playgrounds' => l10n.placeCategoryPlaygrounds,
'shopping' => l10n.placeCategoryShopping,
'services' => l10n.placeCategoryServices,
'health' => l10n.placeCategoryHealth,
'other' => l10n.placeCategoryOther,
_ => l10n.categoryFallback,
};
}
return l10n.categoryFallback;
}
String listingValueLabel(
AppLocalizations l10n,
String value, {
String? fieldKey,
}) {
if (value == 'more_than_6' &&
(fieldKey == 'bathrooms' || fieldKey == 'bedrooms')) {
return l10n.listingValueMoreThanSix;
}
if (value == 'custom' && fieldKey == 'property_rooms') {
return l10n.listingValueCustom;
}
if (fieldKey == 'ticket_mode') {
return eventValueLabel(l10n, value);
}
if (value == 'both') {
return switch (fieldKey) {
'commission_payer' => l10n.listingValueBothParties,
'delivery_mode' => l10n.listingValueBoth,
_ => l10n.listingValueOther,
};
}
return switch (value) {
'offer' => l10n.listingValueOffer,
'search' => l10n.listingValueSearch,
'employment' => l10n.listingValueEmployment,
'rent' => l10n.listingValueRent,
'sale' => l10n.listingValueSale,
// Legacy transaction values are normalized to the current public rent
// choice by the WordPress route contract; keep a safe client fallback.
'lease' => l10n.listingValueRent,
'temporary' =>
fieldKey == 'employment_type'
? l10n.listingValueTemporary
: l10n.listingValueRent,
'private' => l10n.listingValuePrivate,
'business' => l10n.listingValueBusiness,
'organization' => l10n.listingValueOrganization,
'broker' => l10n.listingValueBroker,
'employer' => l10n.listingValueEmployer,
'fixed' => l10n.listingValueFixed,
'negotiable' => l10n.listingValueNegotiable,
'free' => l10n.listingValueFree,
'on_request' => l10n.listingValueOnRequest,
'range' => l10n.listingValueRange,
'once' => l10n.listingValueOnce,
'hour' => l10n.listingValueHour,
'month' => l10n.listingValueMonth,
'year' => l10n.listingValueYear,
'percentage' => l10n.listingValuePercentage,
'monthly_rent' => l10n.listingValueMonthlyRent,
'included' => l10n.listingValueIncluded,
'excluded' => l10n.listingValueExcluded,
'buyer' => l10n.listingValueBuyer,
'seller' => l10n.listingValueSeller,
'tenant' => l10n.listingValueTenant,
'landlord' => l10n.listingValueLandlord,
'new' => l10n.listingValueNew,
'used' => l10n.listingValueUsed,
'defective' => l10n.listingValueDefective,
'unknown' => l10n.listingValueUnknown,
'pickup' => l10n.listingValuePickup,
'shipping' => l10n.listingValueShipping,
'digital' => l10n.listingValueDigital,
'none' => l10n.listingValueNone,
'full_time' => l10n.listingValueFullTime,
'part_time' => l10n.listingValuePartTime,
'minijob' => l10n.listingValueMinijob,
'working_student' => l10n.listingValueWorkingStudent,
'freelance' => l10n.listingValueFreelance,
'apprenticeship' => l10n.listingValueApprenticeship,
'internship' => l10n.listingValueInternship,
'trainee' => l10n.listingValueTrainee,
'seasonal' => l10n.listingValueSeasonal,
'volunteer' => l10n.listingValueVolunteer,
'onsite' => l10n.listingValueOnsite,
'hybrid' => l10n.listingValueHybrid,
'remote' => l10n.listingValueRemote,
'cash' => l10n.listingValueCash,
'bank_transfer' => l10n.listingValueBankTransfer,
'secure_payment' => l10n.listingValueSecurePayment,
'other' => l10n.listingValueOther,
'first_occupancy' => l10n.listingValueFirstOccupancy,
'renovated' => l10n.listingValueRenovated,
'well_kept' => l10n.listingValueWellKept,
'needs_renovation' => l10n.listingValueNeedsRenovation,
'demand' => l10n.listingValueDemand,
'consumption' => l10n.listingValueConsumption,
'yes' => l10n.listingValueYes,
'no' => l10n.listingValueNo,
// Unknown values are still backend data. Keep them visible in a readable
// form instead of replacing a new WordPress value with the misleading
// generic "Other" label.
_ => backendValueLabel(value),
};
}
/// Formats a value that came from WordPress without inventing a category or
/// replacing an unknown backend value with a client-side fallback.
String backendValueLabel(String value) {
final normalized = value.trim();
if (normalized.isEmpty) return '';
final words = normalized.replaceAll(RegExp(r'[_-]+'), ' ').split(' ');
return words
.where((word) => word.isNotEmpty)
.map(
(word) => word.length == 1
? word.toUpperCase()
: '${word.substring(0, 1).toUpperCase()}${word.substring(1)}',
)
.join(' ');
}
String jobSalaryLabel(ListingData? listing, String locale) {
if (listing == null) return '';
final min = listing.salaryMin;
final max = listing.salaryMax;
if (min == null && max == null) return '';
final minLabel = formatCurrencyAmount(min, listing.priceCurrency, locale);
final maxLabel = formatCurrencyAmount(max, listing.priceCurrency, locale);
if (minLabel.isEmpty) return maxLabel;
if (maxLabel.isEmpty || minLabel == maxLabel) return minLabel;
return '$minLabel–$maxLabel';
}
String jobSalaryIntervalLabel(AppLocalizations l10n, ListingData listing) {
return switch (listing.priceInterval.trim().toLowerCase()) {
'hour' => l10n.jobsSalaryHour,
'month' => l10n.jobsSalaryMonth,
'year' => l10n.jobsSalaryYear,
'once' => l10n.jobsSalaryOnce,
// Keep an unknown or legacy interval understandable without exposing an
// API key. The amount is still rendered; only its unit is conservative.
_ => l10n.jobsSalaryGross,
};
}
double? parseJobSalaryFilterAmount(String raw, {String? locale}) {
final value = raw.trim();
if (value.isEmpty) return null;
if (locale != null && locale.trim().isNotEmpty) {
try {
return NumberFormat.decimalPattern(locale).parse(value).toDouble();
} on FormatException {
// Fall through to the permissive compatibility parser below.
}
}
final normalized = value.contains(',')
? value.replaceAll('.', '').replaceFirst(',', '.')
: RegExp(r'^\d{1,3}(?:\.\d{3})+$').hasMatch(value)
? value.replaceAll('.', '')
: value;
return double.tryParse(normalized);
}
double? convertJobSalaryAmount(
double? value, {
required String fromInterval,
required String toInterval,
}) {
if (value == null || !value.isFinite) return null;
final from = fromInterval.trim().toLowerCase();
final to = toInterval.trim().toLowerCase();
if (from == to) return value;
if (from == 'month' && to == 'year') return value * 12;
if (from == 'year' && to == 'month') return value / 12;
// Hourly compensation cannot be safely converted without contracted
// working hours. Keep it in its native interval instead of inventing one.
return null;
}
String listingFieldLabel(AppLocalizations l10n, String fieldKey) {
return switch (fieldKey) {
'rating_average' => l10n.detailRating,
'featured' => l10n.detailFeatured,
'status' => l10n.detailListingStatus,
'offer_type' => l10n.detailOfferType,
'provider_type' => l10n.detailProvider,
'price_type' => l10n.detailPriceType,
'price_amount' ||
'price_currency' ||
'price_interval' ||
'price_label' => l10n.detailPrice,
'available_from' => l10n.detailAvailability,
'company_name' => l10n.detailOrganisation,
'transaction_type' => l10n.detailTransactionType,
'property_kind' => l10n.detailPropertyKind,
'property_rooms' => l10n.detailRooms,
'area' => l10n.detailArea,
'bathrooms' => l10n.detailBathrooms,
'condition' => l10n.detailCondition,
'delivery_mode' => l10n.detailDelivery,
'employment_type' => l10n.detailEmploymentType,
'work_mode' => l10n.detailWorkMode,
'salary_min' || 'salary_max' => l10n.detailSalary,
'application_url' => l10n.detailApplication,
'contact_preference' => l10n.detailContactPreference,
'expire_date' => l10n.detailExpires,
'brand' => l10n.detailBrand,
'model' => l10n.detailModel,
'color' => l10n.detailColor,
'size' => l10n.detailSize,
'material' => l10n.detailMaterial,
'item_age' => l10n.detailItemAge,
'original_price' => l10n.detailOriginalPrice,
'payment_mode' => l10n.detailPaymentMode,
'reference_code' => l10n.detailReferenceCode,
'department' => l10n.detailDepartment,
'work_hours' => l10n.detailWorkHours,
'start_date' => l10n.detailStartDate,
'application_deadline' => l10n.detailApplicationDeadline,
'requirements' => l10n.detailRequirements,
'responsibilities' => l10n.detailResponsibilities,
'benefits' => l10n.detailBenefits,
'languages' => l10n.detailLanguages,
'education' => l10n.detailEducation,
'experience_years' => l10n.detailExperienceYears,
'application_email' => l10n.detailApplicationEmail,
'application_method' => l10n.detailApplicationMethod,
'bedrooms' => l10n.detailBedrooms,
'floor' => l10n.detailFloor,
'total_floors' => l10n.detailTotalFloors,
'year_built' => l10n.detailYearBuilt,
'last_renovated' => l10n.detailLastRenovated,
'cold_rent' => l10n.detailColdRent,
'warm_rent' => l10n.detailWarmRent,
'additional_costs' => l10n.detailAdditionalCosts,
'heating_costs_included' => l10n.detailHeatingCostsIncluded,
'deposit' => l10n.detailDeposit,
'house_fee' => l10n.detailHouseFee,
'commission_type' => l10n.detailCommissionType,
'commission_amount' => l10n.detailCommissionAmount,
'commission_applicable' => l10n.detailCommissionApplicable,
'commission_calculation' => l10n.detailCommissionCalculation,
'commission_total' => l10n.detailCommissionTotal,
'commission_months' => l10n.detailCommissionMonths,
'commission_buyer_share' => l10n.detailCommissionBuyerShare,
'commission_seller_share' => l10n.detailCommissionSellerShare,
'commission_vat' => l10n.detailCommissionVat,
'commission_payer' => l10n.detailCommissionPayer,
'energy_certificate_type' => l10n.detailEnergyCertificate,
'energy_value' => l10n.detailEnergyValue,
'energy_class' => l10n.detailEnergyClass,
'heating_type' => l10n.detailHeatingType,
'energy_source' => l10n.detailEnergySource,
'parking_spaces' => l10n.detailParkingSpaces,
'parking_price' => l10n.detailParkingPrice,
'amenity_kitchen' => l10n.detailKitchen,
'amenity_balcony' => l10n.detailBalcony,
'amenity_terrace' => l10n.detailTerrace,
'amenity_garden' => l10n.detailGarden,
'amenity_basement' => l10n.detailBasement,
'amenity_attic' => l10n.detailAttic,
'amenity_elevator' => l10n.detailElevator,
'amenity_guest_toilet' => l10n.detailGuestToilet,
'amenity_air_conditioning' => l10n.detailAirConditioning,
'amenity_floor_heating' => l10n.detailFloorHeating,
'amenity_fireplace' => l10n.detailFireplace,
'amenity_furnished' => l10n.detailFurnished,
'amenity_barrier_free' => l10n.detailBarrierFree,
'amenity_pets_allowed' => l10n.detailPetsAllowed,
'amenity_garage' => l10n.detailGarage,
'amenity_carport' => l10n.detailCarport,
'amenity_e_charging' => l10n.detailECharging,
// The schema may gain a field before this client ships a dedicated label.
// Keep the UI localized instead of exposing an internal API key.
_ => l10n.contentTypeOther,
};
}
