import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";

export interface McServer {
  name: string;
  ip: string;
  port: number;
}

export interface SkinLibraryItem {
  id: string;
  name: string;
  skinBase64: string;
}

export interface CustomEdition {
  id: string;
  name: string;
  desc: string;
  url: string;
  path?: string;
  category?: string[];
  logo?: string;
}

export interface AppConfig {
  username: string;
  linuxRunner?: string;
  skinBase64?: string;
  skinLibrary?: SkinLibraryItem[];
  themeStyleId?: string;
  themePaletteId?: string;
  appleSiliconPerformanceBoost?: boolean;
  customEditions?: CustomEdition[];
  profile?: string;
  animationsEnabled?: boolean;
  vfxEnabled?: boolean;
  rpcEnabled?: boolean;
  startFullscreen?: boolean;
  musicVol?: number;
  sfxVol?: number;
  legacyMode?: boolean;
  mangohudEnabled?: boolean;
  savedServers?: McServer[];
  extraLaunchArgs?: string[];
  launchPrefix?: string;
  launchEnvVars?: Record<string, string>;
  customizations?: Record<string, { titleImage?: string; panorama?: string }>;
  customPaths?: Record<string, string>;
  skipIntro?: boolean;
}

export interface ThemePalette {
  id: string;
  name: string;
  colors: Record<string, string>;
}

export interface Runner {
  id: string;
  name: string;
  path: string;
  type: "wine" | "proton";
}

export interface MacOSSetupProgress {
  stage: string;
  message: string;
  percent?: number;
}

export interface InstalledWorkshopPackage {
  instanceId: string;
  packageId: string;
  version: string;
}

export interface PlaytimeResponse {
  totalSeconds: number;
  weekSeconds: number;
  daySeconds: number;
}

export interface PlaytimeDayEntry {
  label: string;
  seconds: number;
}

export class TauriService {
  static async saveConfig(config: AppConfig): Promise<void> {
    return invoke("save_config", { configVal: config });
  }

  static async loadConfig(): Promise<AppConfig> {
    return invoke("load_config");
  }

  static async getExternalPalettes(): Promise<ThemePalette[]> {
    return invoke("get_external_palettes");
  }

  static async importTheme(): Promise<string> {
    return invoke("import_theme");
  }

  static async exportSettings(): Promise<void> {
    return invoke("export_settings");
  }

  static async importSettings(): Promise<string> {
    return invoke("import_settings");
  }

  static async getAvailableRunners(): Promise<Runner[]> {
    return invoke("get_available_runners");
  }

  static async downloadRunner(name: string, url: string): Promise<string> {
    return invoke("download_runner", { name, url });
  }

  static async checkGameInstalled(instanceId: string): Promise<boolean> {
    return invoke("check_game_installed", { instanceId });
  }

  static async openInstanceFolder(instanceId: string): Promise<void> {
    return invoke("open_instance_folder", { instanceId });
  }

  static async deleteInstance(instanceId: string): Promise<void> {
    return invoke("delete_instance", { instanceId });
  }

  static async cancelDownload(instanceId: string): Promise<void> {
    return invoke("cancel_download", { instanceId });
  }

  static async setupMacosRuntime(): Promise<void> {
    return invoke("setup_macos_runtime");
  }

  static async downloadAndInstall(
    url: string,
    instanceId: string,
  ): Promise<string> {
    return invoke("download_and_install", { url, instanceId });
  }

  static async launchGame(
    instanceId: string,
    servers: McServer[],
    extraArgs?: string[],
  ): Promise<void> {
    return invoke("launch_game", {
      instanceId,
      servers,
      extraArgs: extraArgs ?? [],
    });
  }

  static async stopGame(instanceId: string): Promise<void> {
    return invoke("stop_game", { instanceId });
  }

  static async syncDlc(instanceId: string): Promise<void> {
    return invoke("sync_dlc", { instanceId });
  }

  static async workshopInstall(
    instanceId: string,
    packageId: string,
    zips: Record<string, string>,
    version: string,
  ): Promise<void> {
    return invoke("workshop_install", {
      request: { instanceId, packageId, zips, version },
    });
  }

  static async workshopUninstall(
    instanceId: string,
    packageId: string,
  ): Promise<void> {
    return invoke("workshop_uninstall", { instanceId, packageId });
  }

  static async workshopListInstalled(): Promise<InstalledWorkshopPackage[]> {
    return invoke("workshop_list_installed");
  }

  static onDownloadProgress(callback: (data: { instanceId: string; percent: number }) => void) {
    return listen<{ instanceId: string; percent: number }>("download-progress", (event) =>
      callback(event.payload),
    );
  }

  static onRunnerDownloadProgress(callback: (percent: number) => void) {
    return listen<number>("runner-download-progress", (event) =>
      callback(event.payload),
    );
  }

  static onMacosProgress(callback: (payload: MacOSSetupProgress) => void) {
    return listen<MacOSSetupProgress>("macos-setup-progress", (event) =>
      callback(event.payload),
    );
  }

  static onBackendError(callback: (message: string) => void) {
    return listen<string>("backend-error", (event) =>
      callback(event.payload),
    );
  }

  static onDownloadRetry(callback: (attempt: number) => void) {
    return listen<number>("download-retry", (event) =>
      callback(event.payload),
    );
  }

  static async openUrl(url: string): Promise<void> {
    return invoke("plugin:opener|open_url", { url });
  }

  static async restartLauncher(): Promise<void> {
    return invoke("restart_launcher");
  }

  static async checkMacOSRuntimeInstalled(): Promise<boolean> {
    return invoke("check_macos_runtime_installed");
  }

  static async checkMacOSRuntimeInstalledFast(): Promise<boolean> {
    return invoke("check_macos_runtime_installed_fast");
  }

  static async setupMacOSRuntimeOptimized(): Promise<void> {
    return invoke("setup_macos_runtime_optimized");
  }

  static async fetchSkin(username: string): Promise<[string, string]> {
    return invoke("fetch_skin", { username });
  }

  static async saveGlobalSkinPck(pckData: Uint8Array): Promise<void> {
    return invoke("save_global_skin_pck", { pckData: Array.from(pckData) });
  }

  static async checkGameUpdate(
    instanceId: string,
    url: string,
  ): Promise<boolean> {
    return invoke("check_game_update", { instanceId, url });
  }

  static async pickFolder(): Promise<string> {
    return invoke("pick_folder");
  }

  static async pickFile(title: string, filters: string[]): Promise<string> {
    return invoke("pick_file", { title, filters });
  }

  static async saveFileDialog(
    title: string,
    filename: string,
    filters: string[],
  ): Promise<string> {
    return invoke("save_file_dialog", { title, filename, filters });
  }

  static async writeBinaryFile(path: string, data: Uint8Array): Promise<void> {
    return invoke("write_binary_file", { path, data: Array.from(data) });
  }

  static async readBinaryFile(path: string): Promise<Uint8Array> {
    const data: number[] = await invoke("read_binary_file", { path });
    return new Uint8Array(data);
  }

  static async downloadLogo(id: string, url: string): Promise<string> {
    return invoke("download_logo", { id, url });
  }

  static async addToSteam(
    instanceId: string,
    name: string,
    titleBase64: string,
    panoramaBase64: string,
  ): Promise<void> {
    return invoke("add_to_steam", {
      instanceId,
      name,
      titleBase64,
      panoramaBase64,
    });
  }

  static async stunDiscover(): Promise<{ ip: string; port: number }> {
    return invoke("stun_discover");
  }

  static async startDirectProxy(
    targetIp: string,
    targetPort: number,
  ): Promise<number> {
    return invoke("start_direct_proxy", { targetIp, targetPort });
  }

  static async startRelayProxy(
    apiBaseUrl: string,
    accessToken: string,
    sessionId: string,
  ): Promise<number> {
    return invoke("start_relay_proxy", { apiBaseUrl, accessToken, sessionId });
  }

  static async startHostRelay(
    apiBaseUrl: string,
    accessToken: string,
    sessionId: string,
    gamePort: number,
  ): Promise<void> {
    return invoke("start_host_relay", {
      apiBaseUrl,
      accessToken,
      sessionId,
      gamePort,
    });
  }

  static async stopProxy(sessionId: string): Promise<void> {
    return invoke("stop_proxy", { sessionId });
  }

  static async stopAllProxies(): Promise<void> {
    return invoke("stop_all_proxies");
  }

  static async joinGame(
    apiBaseUrl: string,
    accessToken: string,
    hostIp: string,
    hostPort: number,
    sessionId: string,
    instanceId: string,
  ): Promise<void> {
    return invoke("join_game", {
      apiBaseUrl,
      accessToken,
      hostIp,
      hostPort,
      sessionId,
      instanceId,
    });
  }

  static async httpProxyRequest(
    method: string,
    url: string,
    body: string | null,
    headers: Record<string, string>,
  ): Promise<{ status: number; body: string }> {
    return invoke("http_proxy_request", { method, url, body, headers });
  }

  static async getPlaytime(instanceId: string): Promise<PlaytimeResponse> {
    return invoke("get_playtime", { instanceId });
  }

  static async getPlaytimeDaily(
    instanceId: string,
    days: number,
  ): Promise<PlaytimeDayEntry[]> {
    return invoke("get_playtime_daily", { instanceId, days });
  }

  static async getInstancePath(instanceId: string): Promise<string> {
    return invoke("get_instance_path", { instanceId });
  }

  static async readScreenshotAsDataUrl(path: string): Promise<string> {
    return invoke("read_screenshot_as_data_url", { path });
  }

  static async backupInstance(instanceId: string): Promise<void> {
    return invoke("backup_instance", { instanceId });
  }

  static async restoreInstance(): Promise<string> {
    return invoke("restore_instance");
  }

  static async getPluginsDir(): Promise<string> {
    return invoke("get_plugins_dir");
  }

  static async createPluginDir(pluginId: string): Promise<string> {
    return invoke("create_plugin_dir", { pluginId });
  }

  static async removePluginDir(pluginId: string): Promise<void> {
    return invoke("remove_plugin_dir", { pluginId });
  }

  static async listDirectory(
    path: string,
  ): Promise<Array<{ name: string; is_dir: boolean }>> {
    return invoke("list_directory", { path });
  }

  static async listGitDirectory(
    repoUrl: string,
    branch: string,
    path: string,
  ): Promise<Array<{ name: string; is_dir: boolean }>> {
    return invoke("list_git_directory", { repoUrl, branch, path });
  }

  static async downloadDlcFiles(
    instanceId: string,
    repoUrl: string,
    branch: string,
    dlcFolder: string,
  ): Promise<void> {
    return invoke("download_dlc_files", { instanceId, repoUrl, branch, dlcFolder });
  }

  static async importWorld(
    inputPath: string,
    outputPath: string,
  ): Promise<string> {
    return invoke("import_world", { inputPath, outputPath });
  }
}
