/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import type { History } from 'history';
import { guaranteeNonNullable } from '@finos/legend-shared';

/**
 * This is an initial attempt to try to generalize the application
 * to other platforms. But regardless, this is more convenient for testing.
 *
 * NOTE: this is **NOT** the right way to do this. Our intention here is to make
 * app navigator something generic enough so we are somewhat platform-agnostic
 * i.e. browser, electron, PC, UNIX, etc.
 *
 * Parameterize on the type of the location might not be the best thing to do.
 * Because typing wise, this forces us to also parameterize consumers of this,
 * which is `ApplicationStore`. It means that we must dictate in the source
 * code the platform the app depends on, clearly for web browser, `string` is the
 * easy option, but if we do so, it defeats the purpose of this abstraction in the
 * first place.
 *
 * As such, instead, we should design a more generic concept `Location` to pass around.
 * We would need to flesh out the details, but this is the rough idea.
 *
 * Another thought is that we should also generalize Router so it handles more than just
 * URLs. If we make `router` and `navigator` work together, we can potentially generalize
 * application navigation
 *
 * However, this depends on how and when we move to another platform, like `electron` for example
 * See https://github.com/finos/legend-studio/issues/718
 */
interface ApplicationNavigator<T> {
  reload(): void;
  goTo(location: T): void;
  jumpTo(location: T): void;
  openNewWindow(location: T): void;
  getCurrentLocation(): T;
  getCurrentLocationPath(): T;
  generateLocation(locationPath: T): T;
}

export class WebApplicationNavigator implements ApplicationNavigator<string> {
  private readonly historyAPI: History;

  private get window(): Window {
    return guaranteeNonNullable(
      window,
      `Window object is not available in non-web environment`,
    );
  }

  constructor(historyApiClient: History) {
    this.historyAPI = historyApiClient;
  }

  reload(): void {
    this.window.location.reload();
  }

  goTo(location: string): void {
    this.historyAPI.push(location);
  }

  jumpTo(location: string): void {
    this.window.location.href = location;
  }

  openNewWindow(location: string): void {
    this.window.open(location, '_blank');
  }

  getCurrentLocation(): string {
    return this.window.location.href;
  }

  getCurrentLocationPath(): string {
    return this.historyAPI.location.pathname;
  }

  generateLocation(locationPath: string): string {
    return (
      window.location.origin +
      this.historyAPI.createHref({ pathname: locationPath })
    );
  }
}