import "../styles/style.scss";

// サードパーティ
// Third-party libraries
import lilGUI from "lil-gui";
import { Vector3 } from "three";

// neglの読み込み
// Loading negl
import { setup, utils } from "negl";

/**
 * NOTE 以下使用は任意。なくても negl 自体は問題なく稼働。
 * NOTE The following imports are optional. negl works fine without them.
 */
// パフォーマンス測定用関数
// Function for performance measurement
import { performanceMonitor } from "#/parts/helper/performance-monitor";
// サファリで画面復帰の際にリロードする関数
// Function to reload on Safari when returning to the screen
import { reloadOnSafari } from "#/parts/helper/safariBlurReload";
// GPU性能の測定
// Measuring GPU performance
import { definePerformanceMode } from "#/parts/helper/detectGPU";
// カメラ位置にマウスを連動する関数
// Function to link mouse movement to camera position
import { mouseCamera } from "#/parts/helper/mouseCamera";
/**
 * toggleTheme：海と空の色を変更する関数
 * setupSkyOcean：海と空のセットアップ
 *
 * toggleTheme: Function to change the colors of the sea and sky
 * setupSkyOcean: Setup for the sea and sky
 */
import { setupSkyOcean, toggleTheme } from "#/parts/sky-ocean";
// マウスアニメーション設定用関数
// Function for setting up mouse animations
import initMouseClick from "#/parts/mouse/mouse-click";

/**
 * ページトランジション
 * Page transitions
 */
// 基本的なトランジション操作を行う関数
// Function for basic transition operations
import { registTransitionBase } from "#/parts/transition/transition-base";
// ジブリ用のトランジションを行う関数
// Function for Ghibli-specific transitions
import { registTransitionGhibli } from "#/parts/transition-ghibli";

// 画面初期表示時のローダー用の処理
// Processing for the loader at the initial screen display
import { letsBegin } from "#/parts/loader-ghibli";

/**
 * デバックモード判定を行う関数
 * デバッグモードの時、true。それ以外、false。
 *
 * Function to determine debug mode
 * Returns true in debug mode, false otherwise.
 */
const enableDebugMode = (debug) => {
  return debug && import.meta.env.DEV;
};

// ページの読み込み
// Page loading
const pageResolver = (type) => import(`./page/${type}.js`);

// OBの読み込み
// Loading OB
const obResolver = async (type) => {
  const module = await import(`./parts/glsl/${type}/index.js`);
  return module.default;
};

(async () => {
  // パフォーマンスモードの初期化
  // Initialization of performance mode
  await definePerformanceMode(2, 35);

  const debug = enableDebugMode(1);

  /**
   * neglの設定
   * setup関数 - https://docs.not-equal.dev/tutorial/installation/
   * config設定 - https://docs.not-equal.dev/reference/interfaces/Config/
   *
   * Configuration for negl
   * setup function - https://docs.not-equal.dev/tutorial/installation/
   * config settings - https://docs.not-equal.dev/reference/interfaces/Config/
   */
  const { start } = setup({
    resolver: {
      page: pageResolver,
      ob: obResolver,
    },
    viewport: {
      cameraZ: 600,
      far: 2000,
      near: 0.1,
      // スマホの時は2とした方が綺麗に見える
      // デスクトップは1でないと重くなる
      // For mobile devices, a value of 2 looks better
      // For desktops, a value other than 1 will be too heavy
      devicePixelRatio: utils.isTouchDevices() ? 2 : 1,
    },
    transition: { defaultType: "ghibli", spaMode: true },
    addon: { lilGUI },
    debug,
  });

  /**
   * neglの初期化
   * 以降、negl内の全てのオブジェクトにアクセス可能。
   *
   * Initialization of negl
   * From this point on, all objects within negl are accessible.
   */
  const negl = await start();
  const { world } = negl;

  // 左上に表示されるstats-jsのパフォーマンス状況を表示
  // Display the performance status of stats-js in the upper left corner
  performanceMonitor(negl);

  // 海と空の設定
  // Setting up the sea and sky
  await setupSkyOcean(negl);

  // 全ての要素のscroll処理を切る（位置計算をしなくなるため、パフォーマンスが少し良くなる。）
  // Disable scroll processing for all elements (this improves performance slightly as position calculations are no longer performed).
  world.os.forEach((o) => (o.fixed = true));

  // カメラをマウスで動かす&カメラのローディング完了時のアニメーション
  // カメラの初期位置を設定
  // Move the camera with the mouse & animation when camera loading is complete
  // Set the initial camera position
  setupMouseCamera(negl);

  // テーマ切り替えボタンの初期化
  // Initialize the theme toggle button
  addToggleThemeAction();

  // レンダリングの開始
  // Start rendering
  negl.renderStart();

  // マウスのアニメーションを定義
  // Define mouse animations
  const mouseLoad = initMouseClick(negl);

  // ロード完了時アニメーション
  // Animation upon load completion
  await letsBegin(negl);

  /**
   * この時点でローディングの表示は消えています。
   * 以下の処理は画面の初期表示時には完了している必要がない処理のため、letsBeginより下に記述しています。
   *
   * At this point, the loading display has disappeared.
   * The following processes do not need to be completed at the time of the initial screen display, so they are described below letsBegin.
   */

  /**
   * トランジション用の設定
   * Configuration for transitions
   */
  // トランジションに基本的に必要な設定
  // Basic settings required for transitions
  registTransitionBase(negl);
  // ジブリ専用のトランジション設定
  // Ghibli-specific transition settings
  registTransitionGhibli(negl);

  // サファリでタブ復帰時には画面リロード
  // Reload the screen when returning to the tab on Safari
  reloadOnSafari(negl);
  // マウス表示
  // Display the mouse
  mouseLoad();
})();

function setupMouseCamera(negl) {
  const { world, viewport } = negl;

  const cameraY = 250, // カメラのY軸
    // The Y-axis of the camera
    lookAt = new Vector3(0, cameraY, -1); // xy平面に水平かつ-z方向にカメラを向ける
  // Orient the camera horizontally on the xy plane and towards the -z direction

  // カメラの設定
  // Camera settings
  world.camera.position.y = cameraY;
  world.camera.lookAt(lookAt);

  // カメラのマウスアニメーション設定
  // Camera mouse animation settings
  mouseCamera(
    // Negl オブジェクトを渡します。
    // Pass the Negl object.
    negl,
    // マウスが動いた際のカメラの位置を { x, y, z } のオブジェクト形式で返却する関数を渡します。
    // Pass a function that returns the camera position as an { x, y, z } object when the mouse moves.
    ({ x, y }) => ({
      x: x * 100,
      y: cameraY + y * 40,
      z: viewport.cameraZ + Math.abs(y * 100),
    }),
    // カメラの向きを定義した Vector3 のオブジェクトを渡します。
    // Pass the Vector3 object that defines the camera's orientation.
    lookAt
  );
}

/**
 * 左下のテーマ切り替えボタンをイベントにバインドします。
 * Bind the theme toggle button at the bottom left to an event.
 */
function addToggleThemeAction() {
  const toggleBtn = document.querySelector(".toggle-theme");

  /**
   * 画面表示時の時間帯が夜間の時、チェックを付けます。
   * Check the box if the time of day at the time of screen display is at night.
   */
  if (window.ghibli.isNight()) {
    toggleBtn.firstElementChild.checked = !toggleBtn.firstElementChild.checked;
  }

  /**
   * クリックされた際にテーマを切り替えます。
   * Switch the theme when clicked.
   */
  toggleBtn.addEventListener("change", () => {
    toggleTheme();
  });
}
