/**
 * URL router for the SipRouter dashboard.
 * Maps grouped URL paths to views in dees-simple-appdash.
 */

const SUBVIEW_MAP = {
  overview: ['stats'],
  telephony: ['calls', 'phone', 'routes', 'voicemail', 'ivr'],
  configuration: ['contacts', 'providers'],
  system: ['log'],
} as const;

const DEFAULT_SUBVIEW = {
  overview: 'stats',
  telephony: 'calls',
  configuration: 'contacts',
  system: 'log',
} as const satisfies { [key in TViewSlug]: TSubviewSlug };

const DEFAULT_ROUTE: IRouteState = {
  view: 'overview',
  subview: 'stats',
};

type TViewSlug = keyof typeof SUBVIEW_MAP;
type TSubviewSlug = (typeof SUBVIEW_MAP)[TViewSlug][number];

interface IRouteState {
  view: TViewSlug;
  subview: TSubviewSlug;
}

function isValidView(view: string): view is TViewSlug {
  return Object.prototype.hasOwnProperty.call(SUBVIEW_MAP, view);
}

function isValidSubview(view: TViewSlug, subview: string): subview is TSubviewSlug {
  return (SUBVIEW_MAP[view] as readonly string[]).includes(subview);
}

class AppRouter {
  private currentRoute: IRouteState = DEFAULT_ROUTE;
  private onNavigate: ((view: TViewSlug, subview: TSubviewSlug) => void) | null = null;
  private initialized = false;

  init(): void {
    if (this.initialized) return;

    this.applyRoute(this.parsePath(location.pathname) ?? DEFAULT_ROUTE, false, true);

    // Handle browser back/forward.
    window.addEventListener('popstate', () => {
      this.applyRoute(this.parsePath(location.pathname) ?? DEFAULT_ROUTE, false, true);
    });

    this.initialized = true;
  }

  setNavigateHandler(handler: (view: TViewSlug, subview: TSubviewSlug) => void): void {
    this.onNavigate = handler;
  }

  navigateToView(view: TViewSlug, subview?: TSubviewSlug, skipCallback = false): void {
    const targetSubview = subview && isValidSubview(view, subview) ? subview : DEFAULT_SUBVIEW[view];
    this.applyRoute({ view, subview: targetSubview }, skipCallback, false);
  }

  getCurrentRoute(): IRouteState {
    return this.currentRoute;
  }

  isCurrentRoute(view: TViewSlug, subview: TSubviewSlug): boolean {
    return this.currentRoute.view === view && this.currentRoute.subview === subview;
  }

  private parsePath(pathname: string): IRouteState | null {
    const segments = pathname.split('/').filter(Boolean);
    if (segments.length === 0) return DEFAULT_ROUTE;
    if (segments.length > 2) return null;

    const [viewSegment, subviewSegment] = segments;
    if (!isValidView(viewSegment)) return null;

    const targetSubview = subviewSegment ?? DEFAULT_SUBVIEW[viewSegment];
    if (!isValidSubview(viewSegment, targetSubview)) return null;

    return {
      view: viewSegment,
      subview: targetSubview,
    };
  }

  private applyRoute(route: IRouteState, skipCallback: boolean, replace: boolean): void {
    this.currentRoute = route;

    const url = `/${route.view}/${route.subview}`;
    if (location.pathname !== url) {
      if (replace) {
        history.replaceState(null, '', url);
      } else {
        history.pushState(null, '', url);
      }
    }

    if (!skipCallback) {
      this.onNavigate?.(route.view, route.subview);
    }
  }
}

export const appRouter = new AppRouter();
export type { IRouteState, TSubviewSlug, TViewSlug };
