import type {
  Poi,
  PoiCategory,
  PoiDataset,
  PoiFilter,
  PoiImageAsset,
  PoiOpeningHours,
  PoiResolved,
  PoiSummary,
  PoiTag,
  RecommendationSource,
} from './types'

export function formatOpeningHours(openingHours: PoiOpeningHours): string {
  if (openingHours.status === 'unknown')
    return '开放时间待确认'

  return openingHours.displayText?.trim() || '开放时间待确认'
}

export function formatRecommendationLabel(_source: RecommendationSource, index: number): string {
  return `推荐指数 ${index}/5`
}

export function filterPois(pois: readonly Poi[], filter: PoiFilter = {}): Poi[] {
  const requiredTags = Array.from(new Set(filter.tagCodes ?? []))

  return pois.filter((poi) => {
    if (filter.categoryCode && poi.categoryCode !== filter.categoryCode)
      return false

    return requiredTags.every(tagCode => poi.tagCodes.includes(tagCode))
  })
}

export function findPoiById(pois: readonly Poi[], poiId: string): Poi | null {
  const normalizedId = poiId.trim()
  if (!normalizedId)
    return null

  return pois.find(poi => poi.id === normalizedId) ?? null
}

export function sortCategories(categories: readonly PoiCategory[]): PoiCategory[] {
  return categories
    .filter(category => category.status === 'enabled')
    .slice()
    .sort((left, right) => left.sortOrder - right.sortOrder || left.name.localeCompare(right.name, 'zh-CN'))
}

export function sortTags(tags: readonly PoiTag[]): PoiTag[] {
  return tags
    .filter(tag => tag.status === 'enabled')
    .slice()
    .sort((left, right) => left.sortOrder - right.sortOrder || left.name.localeCompare(right.name, 'zh-CN'))
}

export function resolvePoi(
  poi: Poi,
  categories: readonly PoiCategory[],
  tags: readonly PoiTag[],
  images: readonly PoiImageAsset[],
): PoiResolved | null {
  const category = categories.find(item => item.code === poi.categoryCode && item.status === 'enabled')
  const coverImage = images.find(item => item.id === poi.coverImageId)
  if (!category || !coverImage)
    return null

  const tagMap = new Map(tags.map(tag => [tag.code, tag]))
  const imageMap = new Map(images.map(image => [image.id, image]))
  const resolvedTags = poi.tagCodes
    .map(tagCode => tagMap.get(tagCode))
    .filter((tag): tag is PoiTag => Boolean(tag && tag.status === 'enabled'))
  const resolvedImages = poi.imageIds
    .map(imageId => imageMap.get(imageId))
    .filter((image): image is PoiImageAsset => Boolean(image))

  return {
    ...poi,
    category,
    tags: resolvedTags,
    coverImage,
    images: [coverImage, ...resolvedImages],
    openingHoursText: formatOpeningHours(poi.openingHours),
  }
}

export function toPoiSummary(poi: PoiResolved): PoiSummary {
  return {
    id: poi.id,
    name: poi.name,
    categoryCode: poi.categoryCode,
    categoryName: poi.category.name,
    tagCodes: [...poi.tagCodes],
    tags: poi.tags.map(tag => ({ ...tag, synonyms: tag.synonyms ? [...tag.synonyms] : undefined })),
    longitude: poi.longitude,
    latitude: poi.latitude,
    coordinateSystem: poi.coordinateSystem,
    coverImage: { ...poi.coverImage },
    summary: poi.summary,
    description: poi.description,
    address: poi.address,
    recommendationIndex: poi.recommendationIndex,
    recommendationSource: poi.recommendationSource,
    openingHoursText: poi.openingHoursText,
  }
}

export function resolveDatasetPois(dataset: PoiDataset, pois: readonly Poi[]): PoiResolved[] {
  return pois
    .map(poi => resolvePoi(poi, dataset.categories, dataset.tags, dataset.images))
    .filter((poi): poi is PoiResolved => Boolean(poi))
}
