import type { MuseumExhibit, MuseumHall, MuseumPoi, SearchIndexItem } from '@/domain/museum' import { guideRepository, type GuideRepository } from '@/repositories/GuideRepository' import { staticMuseumContentProvider, type MuseumContentProvider } from '@/data/providers/staticMuseumContentProvider' export interface MuseumContentRepository { listFacilities(): Promise getFacilityById(id: string): Promise searchFacilities(keyword?: string): Promise listExhibits(): Promise getExhibitById(id: string): Promise listHalls(): Promise getHallById(id: string): Promise searchContent(keyword?: string): Promise } const normalize = (value: string) => value.trim().toLowerCase() const includesKeyword = (values: Array, keyword: string) => ( values.filter(Boolean).join(' ').toLowerCase().includes(keyword) ) export class DefaultMuseumContentRepository implements MuseumContentRepository { constructor( private readonly contentProvider: MuseumContentProvider = staticMuseumContentProvider, private readonly guide: GuideRepository = guideRepository ) {} listFacilities() { return this.guide.listPois() } getFacilityById(id: string) { return this.guide.getPoiById(id) } searchFacilities(keyword = '') { return this.guide.searchPois(keyword) } listExhibits() { return this.contentProvider.listExhibits() } async getExhibitById(id: string) { const exhibits = await this.contentProvider.listExhibits() return exhibits.find((exhibit) => exhibit.id === id) || null } listHalls() { return this.contentProvider.listHalls() } async getHallById(id: string) { const halls = await this.contentProvider.listHalls() return halls.find((hall) => hall.id === id) || null } async searchContent(keyword = '') { const normalizedKeyword = normalize(keyword) const facilities = await this.searchFacilities(keyword) const exhibits = await this.listExhibits() const halls = await this.listHalls() const exhibitItems = exhibits .filter((exhibit) => !normalizedKeyword || includesKeyword([ exhibit.name, exhibit.hallName, exhibit.floorLabel, ...(exhibit.tags || []) ], normalizedKeyword)) .map((exhibit) => ({ id: exhibit.id, name: exhibit.name, desc: `${exhibit.hallName || '展项'} · ${exhibit.floorLabel || ''}`.trim(), type: 'exhibit', exhibitId: exhibit.id, poiId: exhibit.poiId, floorId: exhibit.floorId })) const hallItems = halls .filter((hall) => !normalizedKeyword || includesKeyword([ hall.name, hall.floorLabel, hall.description ], normalizedKeyword)) .map((hall) => ({ id: hall.id, name: hall.name, desc: `${hall.floorLabel || ''} · ${hall.exhibitCount || 0}件展项`.trim(), type: 'hall', hallId: hall.id, poiId: hall.poiId, floorId: hall.floorId })) const facilityItems = facilities.map((poi) => ({ id: poi.id, name: poi.name, desc: `${poi.floorLabel} · ${poi.primaryCategory.label}`, type: 'facility', poiId: poi.id, floorId: poi.floorId })) return [ ...exhibitItems, ...hallItems, ...facilityItems ] } } export const museumContentRepository = new DefaultMuseumContentRepository()