/**
 * MapFactory - 预配置 maplibregl.Map 实例工厂
 *
 * 提供快速创建带有默认底图图层、控件和事件处理的地图实例的工具方法。
 * 内部使用 MapManager 单例管理地图生命周期，避免重复创建实例。
 *
 * @module map/MapFactory
 */

import { Map, MapOptions, NavigationControlOptions, StyleSpecification } from 'maplibre-gl'
import {
  MapManager,
  MapConfig,
  DEFAULT_CENTER,
  DEFAULT_ZOOM,
  DEFAULT_NAVIGATION_CONTROL_OPTIONS,
} from './MapManager'

// ============================================================
// 类型定义
// ============================================================

/**
 * 地图工厂配置选项
 *
 * 扩展自 MapConfig，增加工厂特有的便捷配置项
 */
export interface MapFactoryOptions extends Omit<MapConfig, 'container'> {
  /**
   * 地图容器元素或其 id（必填）
   */
  container: string | HTMLElement

  /**
   * 是否自动添加 NavigationControl 导航控件
   * @defaultValue true
   */
  enableNavigationControl?: boolean

  /**
   * NavigationControl 导航控件配置
   * @defaultValue { showCompass: true, showZoom: true, visualizePitch: false }
   */
  navigationControlOptions?: NavigationControlOptions

  /**
   * 是否启用默认的中日韩本地字体渲染
   * @defaultValue true
   */
  enableLocalIdeograph?: boolean

  /**
   * 用户自定义的 map 'load' 事件处理器
   */
  onLoad?: (map: Map) => void
}

/**
 * 底图图层配置
 */
export interface BasemapLayerConfig {
  /**
   * 图层 id
   */
  id: string

  /**
   * 图层名称（用于显示）
   */
  name: string

  /**
   * MapLibre 样式 URL 或 style 对象
   */
  style: string | StyleSpecification
}

// ============================================================
// 预置底图配置
// ============================================================

/**
 * 内置底图图层列表
 *
 * 可根据项目需要扩展更多底图样式
 */
export const PRESET_BASEMAPS: Record<string, BasemapLayerConfig> = {
  /**
   * MapLibre 官方 Demo 瓦片底图（开发/测试用）
   */
  demotiles: {
    id: 'basemap-demotiles',
    name: 'Demo Tiles',
    style: 'https://demotiles.maplibre.org/style.json',
  },

  /**
   * OpenStreetMap 栅格瓦片底图
   */
  osm: {
    id: 'basemap-osm',
    name: 'OpenStreetMap',
    style: {
      version: 8,
      sources: {
        'osm-raster': {
          type: 'raster',
          tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
          tileSize: 256,
          attribution:
            '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
          maxzoom: 19,
        },
      },
      layers: [
        {
          id: 'osm-raster-layer',
          type: 'raster',
          source: 'osm-raster',
          minzoom: 0,
          maxzoom: 19,
        },
      ],
    },
  },
}

// ============================================================
// MapFactory
// ============================================================

/**
 * 地图工厂
 *
 * 提供一组静态方法，用于快速创建带有常用预配置的 maplibregl.Map 实例。
 * 所有方法内部通过 MapManager 单例管理地图生命周期。
 *
 * @example
 * ```ts
 * // 使用预置 OSM 底图快速创建地图
 * const map = MapFactory.createWithBasemap('osm', {
 *   container: 'map-container',
 * })
 *
 * // 使用自定义样式创建地图
 * const map = MapFactory.create({
 *   container: 'map-container',
 *   style: 'https://my-style-server/style.json',
 *   zoom: 12,
 * })
 *
 * // 创建带加载回调的地图
 * const map = MapFactory.create({
 *   container: 'map-container',
 *   style: 'https://demotiles.maplibre.org/style.json',
 *   onLoad: (map) => {
 *     console.log('地图就绪', map.getCenter())
 *   },
 * })
 * ```
 */
export class MapFactory {
  /**
   * 获取 MapManager 单例
   *
   * @returns MapManager 实例
   */
  private static getManager(): MapManager {
    return MapManager.getInstance()
  }

  /**
   * 创建预配置的地图实例
   *
   * 自动合并默认配置（南京中心点、默认缩放级别、本地字体等），
   * 并添加 NavigationControl 导航控件。
   *
   * @param options - 地图工厂配置选项
   * @returns 创建的 maplibregl.Map 实例
   */
  static create(options: MapFactoryOptions): Map {
    const manager = MapFactory.getManager()

    // 提取 factory 特有参数
    const {
      container,
      enableNavigationControl = true,
      navigationControlOptions,
      enableLocalIdeograph = true,
      onLoad,
      ...mapOptions
    } = options

    // 构建 MapConfig
    const config: Omit<MapConfig, 'container'> = {
      // 默认配置
      center: DEFAULT_CENTER,
      zoom: DEFAULT_ZOOM,

      // 如果启用本地字体，设置中文字体回退
      localIdeographFontFamily: enableLocalIdeograph ? 'sans-serif' : false,

      // 导航控件配置
      navigationControl: enableNavigationControl
        ? (navigationControlOptions ?? DEFAULT_NAVIGATION_CONTROL_OPTIONS)
        : false,

      // 合并用户传入的其他配置
      ...mapOptions,
    }

    // 如果用户提供了 onLoad 回调，先注册事件监听
    if (onLoad) {
      manager.on('map:loaded', (map) => {
        onLoad(map)
        // onLoad 只触发一次，用完即移除
        manager.off('map:loaded', onLoad as () => void)
      })
    }

    // 创建地图
    const map = manager.createMap(container, config)

    return map
  }

  /**
   * 使用预置底图创建地图
   *
   * 从 {@link PRESET_BASEMAPS} 中选择一个预定义底图样式。
   *
   * @param basemapKey - 底图键名，可选值：'demotiles' | 'osm'
   * @param options - 地图工厂配置选项（可选，会覆盖底图默认样式中的 style）
   * @returns 创建的 maplibregl.Map 实例
   * @throws 如果传入的 basemapKey 不存在于预置底图列表中
   */
  static createWithBasemap(
    basemapKey: keyof typeof PRESET_BASEMAPS,
    options: MapFactoryOptions
  ): Map {
    const basemap = PRESET_BASEMAPS[basemapKey]

    if (!basemap) {
      throw new Error(
        `[MapFactory] 未知的底图键名: "${basemapKey}"，可用值: ${Object.keys(PRESET_BASEMAPS).join(', ')}`
      )
    }

    // 使用预置底图的 style，但允许用户覆盖
    return MapFactory.create({
      style: basemap.style,
      ...options,
    })
  }

  /**
   * 注册自定义底图到预置列表
   *
   * @param key - 底图唯一键名
   * @param config - 底图图层配置
   */
  static registerBasemap(key: string, config: BasemapLayerConfig): void {
    PRESET_BASEMAPS[key] = config
  }

  /**
   * 移除预置底图
   *
   * @param key - 底图键名
   */
  static unregisterBasemap(key: string): void {
    delete PRESET_BASEMAPS[key]
  }

  /**
   * 获取所有已注册的底图列表
   *
   * @returns 底图配置记录
   */
  static getRegisteredBasemaps(): Record<string, BasemapLayerConfig> {
    return { ...PRESET_BASEMAPS }
  }

  /**
   * 获取当前地图实例（便捷方法）
   *
   * @returns 当前 maplibregl.Map 实例，未创建时返回 null
   */
  static getCurrentMap(): Map | null {
    return MapFactory.getManager().getMap()
  }

  /**
   * 销毁当前地图实例（便捷方法）
   */
  static destroy(): void {
    MapFactory.getManager().destroyMap()
  }

  /**
   * 订阅地图事件（便捷方法）
   *
   * @param type - 事件类型
   * @param handler - 事件处理函数
   */
  static on(
    type: 'map:loaded' | 'map:destroyed' | 'map:creating',
    handler: (...args: any[]) => void
  ): void {
    MapFactory.getManager().on(type as any, handler)
  }

  /**
   * 取消订阅地图事件（便捷方法）
   *
   * @param type - 事件类型
   * @param handler - 要移除的事件处理函数
   */
  static off(
    type: 'map:loaded' | 'map:destroyed' | 'map:creating',
    handler?: (...args: any[]) => void
  ): void {
    MapFactory.getManager().off(type as any, handler as any)
  }
}
