import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';

type SimpleDetachedRouteHandle = DetachedRouteHandle | null;
/**
 * 路由复用策略
 */
export class SimpleReuseStrategy implements RouteReuseStrategy {

  private static routeCache = new Map<string, DetachedRouteHandle>();
  private static waitDelete: string | null;

  /**
     * 用于删除路由快照
     *
     * @param {string} url - 需要删除路由的 URL。
     * @return {void}
     */
  public static deleteRouteSnapshot(url: string): void {
    if (url[0] === '/') {
      url = url.substring(1);
    }
    url = url.replace(/\//g, '_');
    if (SimpleReuseStrategy.routeCache.has(url)) {
      SimpleReuseStrategy.routeCache.delete(url);
    }
    SimpleReuseStrategy.waitDelete = url;
  }

  /**
   * 用于清空路由快照
   */
  public static clearRouteSnapshot(): void {
    SimpleReuseStrategy.routeCache.clear();
    SimpleReuseStrategy.waitDelete = null;
  }


  /**
   * 基于路由数据确定路由是否应该分离。
   * 表示对所有路由允许复用 如果有路由不想利用可以在这加一些业务逻辑判断，这里判断路由是否有 reuse 数据判断是否复用。
   *
   * @param {ActivatedRouteSnapshot} route - 要检查分离的路由快照。
   * @return {boolean} 如果应该分离路由则返回true，否则返回 false。
   */
  public shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return route.data.reuse;
  }


  /**
  * 当路由离开时会触发, 按 path 作为 key 存储路由快照组件当前实例对象
  * 如果路由配置为‘’，则出现Cannot reattach ActivatedRouteSnapshot created from a different route问题
  *
  * @param {ActivatedRouteSnapshot} route - 用于获取完整路由 URL 的路由快照。
  * @param {DetachedRouteHandle} handle - 要存储的路由处理程逻辑。
  * @return {void}
  */
  public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    const url = this.getFullRouteUrl(route);
    if (SimpleReuseStrategy.waitDelete && SimpleReuseStrategy.waitDelete === url) {
      // 如果待删除是当前路由，且未存储过则不存储快照
      SimpleReuseStrategy.waitDelete = null;
      return;
    }
    SimpleReuseStrategy.routeCache.set(url, handle);
  }


  /**
   * 根据 URL 确定是否应该附加路由。
   * 若 URL 在缓存中有的都认为允许还原路由
   *
   * @param {ActivatedRouteSnapshot} route - 要检查的路由快照。
   * @return {boolean} 是否应该附加路由。
   */
  public shouldAttach(route: ActivatedRouteSnapshot): boolean {
    const url = this.getFullRouteUrl(route);
    return SimpleReuseStrategy.routeCache.has(url);
  }


  /**
     * 从缓存中获取快照，若无则返回 null
     *
     * @param {ActivatedRouteSnapshot} route - 要检查的路由快照
     * @return {SimpleDetachedRouteHandle} SimpleDetachedRouteHandle
     */
  public retrieve(route: ActivatedRouteSnapshot): SimpleDetachedRouteHandle {
    const url = this.getFullRouteUrl(route);
    let handle = SimpleReuseStrategy.routeCache.has(url)
      ? SimpleReuseStrategy.routeCache.get(url)
      : null;
    handle = handle ? handle : null;
    return handle;
  }

  /**
   * 进入路由时触发，根据将来和当前路由配置和参数的比较确定当前路由是否应该重用。
   *
   * @param {ActivatedRouteSnapshot} future - 将来的路由快照。
   * @param {ActivatedRouteSnapshot} curr - 当前路由快照。
   * @return {boolean} 如果应该重用路由，则返回 true，否则返回 false。
   */
  public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    return (
      future.routeConfig === curr.routeConfig &&
      JSON.stringify(future.params) === JSON.stringify(curr.params)
    );
  }

  /**
   * 基于提供的 ActivatedRouteSnapshot 获取完整的路由 URL。
   *
   * @param {ActivatedRouteSnapshot} route - 用于生成完整路由 URL 的 ActivatedRouteSnapshot
   * @return {string} 过滤、连接和替换字符后的完整路由URL。
   */
  private getFullRouteUrl(route: ActivatedRouteSnapshot): string {
    return this.getFullRouteUrlPaths(route).filter(Boolean).join('/').replace(/\//g, '_');
  }

  /**
   * 基于提供的 ActivatedRouteSnapshot 获取完整的路由 URL 的 paths。
   *
   * @param {ActivatedRouteSnapshot} route - 用于生成完整路由 URL 的 ActivatedRouteSnapshot
   * @return {string []}
   */
  private getFullRouteUrlPaths(route: ActivatedRouteSnapshot): string[] {
    const paths = route.url.map(urlSegment => urlSegment.path);
    return route.parent ? [...this.getFullRouteUrlPaths(route.parent), ...paths] : paths;
  }
}
