import { QuasarAppPaths } from "../app-paths";
import * as ElectronBuilder from "electron-builder";
import { QuasarCapacitorTargets } from "./capacitor-conf";
import {
  QuasarElectronBundlers,
  ElectronBuilderTargets,
  ElectronBuilderArchs,
  ElectronPackagerTargets,
  ElectronPackagerArchs
} from "./electron-conf";
import { QuasarCordovaTargets } from "./cordova-conf";

export type QuasarMode =
  | "spa"
  | "ssr"
  | "pwa"
  | "cordova"
  | "capacitor"
  | "electron"
  | "bex";

interface BaseQuasarContext {
  /** True if we are in development mode */
  dev: boolean;
  /** True if we are in production mode */
  prod: boolean;
  /** App mode */
  mode: { [index in QuasarMode]?: true };
  modeName: QuasarMode;
  /** True if debugging is enabled */
  debug: boolean;
  /** True if opening remote Vue Devtools in development mode. */
  vueDevtools: boolean;
  /** Util dealing with app paths */
  appPaths: QuasarAppPaths;
}

interface CapacitorQuasarContext extends BaseQuasarContext {
  mode: { capacitor: true };
  modeName: "capacitor";
  /**
   * App target.
   *
   * @default 'none'
   */
  target: {
    [index in QuasarCapacitorTargets]?: true;
  };
  /** App target name. */
  targetName: QuasarCapacitorTargets;
}

interface CordovaQuasarContext extends BaseQuasarContext {
  mode: { cordova: true };
  modeName: "cordova";
  /**
   * App target.
   *
   * @default 'all installed'
   */
  target: {
    [index in QuasarCordovaTargets]?: true;
  };
  /** App target name. */
  targetName: QuasarCordovaTargets;
  /**
   * Emulator name, may be present only for Cordova mode.
   *
   * @example
   * 'iPhone-7', 'iPhone-X', 'iPhone-X', 'com.apple.CoreSimulator.SimRuntime.iOS-12-2'
   */
  emulator: string;
}

interface BaseElectronQuasarContext extends BaseQuasarContext {
  mode: { electron: true };
  modeName: "electron";
  bundler: { [index in QuasarElectronBundlers]?: true };
  bundlerName: QuasarElectronBundlers;
}

interface ElectronBuilderQuasarContext extends BaseElectronQuasarContext {
  bundler: { builder: true };
  bundlerName: "builder";
  /**
   * App target.
   *
   * @default 'current system'
   */
  target: {
    [index in ElectronBuilderTargets]?: true;
  };
  /** App target name. */
  targetName: ElectronBuilderTargets;
  arch: {
    [index in ElectronBuilderArchs]?: true;
  };
  archName: ElectronBuilderArchs;
  /**
   * Publish options.
   *
   * If not set, its default value is deduced by the environment.
   * See https://www.electron.build/configuration/publish#how-to-publish
   */
  publish?: "onTag" | "onTagOrDraft" | "always" | "never";
  /**
   * Electron-builder configuration for publishing.
   * See https://www.electron.build/configuration
   */
  builder: ElectronBuilder.Configuration;
}

interface ElectronPackagerQuasarContext extends BaseElectronQuasarContext {
  bundler: { packager: true };
  bundlerName: "packager";
  /**
   * App target.
   *
   * @default 'current system'
   */
  target: {
    [index in ElectronPackagerTargets]?: true;
  };
  /** App target name. */
  targetName: ElectronPackagerTargets;
  arch: {
    [index in ElectronPackagerArchs]?: true;
  };
  archName: ElectronPackagerArchs;
}

type ElectronQuasarContext =
  | ElectronBuilderQuasarContext
  | ElectronPackagerQuasarContext;

interface SpaQuasarContext extends BaseQuasarContext {
  mode: { spa: true };
  modeName: "spa";
}

interface PwaQuasarContext extends BaseQuasarContext {
  mode: { pwa: true };
  modeName: "pwa";
}

interface SsrQuasarContext extends BaseQuasarContext {
  mode: { ssr: true; pwa?: true };
  modeName: "ssr";
}

type QuasarBexTargets = "chrome" | "firefox";
interface BexQuasarContext extends BaseQuasarContext {
  mode: { bex: true };
  modeName: "bex";
  /**
   * App target.
   */
  target: Partial<Record<QuasarBexTargets, true>>;
  /** App target name. */
  targetName: QuasarBexTargets;
}

export type QuasarContext =
  | SpaQuasarContext
  | PwaQuasarContext
  | SsrQuasarContext
  | CapacitorQuasarContext
  | CordovaQuasarContext
  | ElectronQuasarContext
  | BexQuasarContext;

type CacheProxyModuleKey =
  | "animations"
  | "capCli"
  | "cssVariables"
  | "electron"
  | "eslint"
  | "hasTypescript"
  | "nodePackager"
  | "storeProvider"
  | "vueRouterVersion"
  | "workboxBuild";
interface CacheProxy {
  getRuntime: (key: string, getInitialValue: () => any) => any;
  setRuntime: (key: string, value: any) => void;
  getModule: (key: CacheProxyModuleKey) => Promise<any>;
}

/**
 * @internal
 */
export type InternalQuasarContext = QuasarContext & {
  pkg: {
    appPkg: Record<string, any>;
    quasarPkg: Record<string, any>;
    vitePkg: Record<string, any>;
  };
  cacheProxy: CacheProxy;
  // TODO: add proper type
  appExt: any;
};
