/**
 * @file Capacitor Main Entry Point
 * @author Matthew Raymer
 *
 * This file initializes the deep linking system for the TimeSafari app.
 * It sets up the connection between Capacitor's URL handling and our deep link processor.
 *
 * Deep Linking Flow:
 * 1. Capacitor receives URL open event
 * 2. Event is passed to DeepLinkHandler
 * 3. URL is validated and processed
 * 4. Router navigates to appropriate view
 *
 * Integration Points:
 * - Capacitor App plugin for URL handling
 * - Vue Router for navigation
 * - Error handling system
 * - Logging system
 *
 * Type Safety:
 * - Uses DeepLinkHandler for type-safe parameter processing
 * - Ensures type safety between Capacitor events and app routing
 * - Maintains type checking through the entire deep link flow
 *
 * @example
 * // URL open event from OS
 * timesafari://claim/123?view=details
 * // Processed and routed to appropriate view with type-safe parameters
 */

import { initializeApp } from "./main.common";
import { App as CapacitorApp } from "@capacitor/app";
import { Capacitor } from "@capacitor/core";
import router from "./router";
import { handleApiError } from "./services/api";
import { AxiosError } from "axios";
import { DeepLinkHandler } from "./services/deepLinks";
import { logger, safeStringify } from "./utils/logger";
import { PlatformServiceFactory } from "./services/PlatformServiceFactory";
import { SHARED_PHOTO_BASE64_KEY } from "./libs/util";
import { SharedImage } from "./plugins/SharedImagePlugin";
import "./utils/safeAreaInset";

// Load Daily Notification plugin at startup so native performRecovery() runs at launch (rollover recovery)
import "@timesafari/daily-notification-plugin";

logger.log("[Capacitor] 🚀 Starting initialization");
logger.log("[Capacitor] Platform:", process.env.VITE_PLATFORM);

const app = initializeApp();

// Initialize API error handling for unhandled promise rejections
window.addEventListener("unhandledrejection", (event) => {
  if (event.reason?.response) {
    handleApiError(event.reason, event.reason.config?.url || "unknown");
  }
});

const deepLinkHandler = new DeepLinkHandler(router);

// Lock to prevent duplicate processing of shared images
let isProcessingSharedImage = false;

/**
 * Stores shared image data in temp database
 * Handles clearing old data, converting base64 to data URL, and storing
 *
 * @param base64 - Raw base64 string of the image
 * @param fileName - Optional filename for logging
 * @returns Promise<void>
 */
async function storeSharedImageInTempDB(
  base64: string,
  fileName?: string,
): Promise<void> {
  const platformService = PlatformServiceFactory.getInstance();

  // Clear old image from temp DB first to ensure we get the new one
  try {
    await platformService.dbExec("DELETE FROM temp WHERE id = ?", [
      SHARED_PHOTO_BASE64_KEY,
    ]);
    logger.debug("[Main] Cleared old shared image from temp DB");
  } catch (clearError) {
    logger.debug(
      "[Main] No old image to clear (or error clearing):",
      clearError,
    );
  }

  // Convert raw base64 to data URL format that base64ToBlob expects
  // base64ToBlob expects format: "data:image/jpeg;base64,/9j/4AAQ..."
  // Try to detect image type from base64 or default to jpeg
  let mimeType = "image/jpeg"; // default
  if (base64.startsWith("/9j/") || base64.startsWith("iVBORw0KGgo")) {
    // JPEG or PNG
    mimeType = base64.startsWith("/9j/") ? "image/jpeg" : "image/png";
  }
  const dataUrl = `data:${mimeType};base64,${base64}`;

  // Use INSERT OR REPLACE to handle existing records
  await platformService.dbExec(
    "INSERT OR REPLACE INTO temp (id, blobB64) VALUES (?, ?)",
    [SHARED_PHOTO_BASE64_KEY, dataUrl],
  );

  logger.info(`[Main] Stored shared image: ${fileName || "unknown"}`);
}

/**
 * Handles deep link routing for the application
 * Processes URLs in the format timesafari://<route>/<param>
 * Maps incoming deep links to corresponding router paths with parameters
 *
 * @param {Object} data - Deep link data object
 * @param {string} data.url - The full deep link URL to process
 * @returns {Promise<void>}
 *
 * @example
 * // Handles URLs like:
 * // timesafari://claim/01JMAAFZRNSRTQ0EBSD70A8E1H
 * // timesafari://project/abc123
 *
 * @throws {Error} If URL format is invalid
 */
/**
 * Check for native shared image using SharedImage plugin
 * Reads from native layer (App Group UserDefaults on iOS, SharedPreferences on Android)
 * and stores in temp database before routing to shared-photo view
 */
async function checkAndStoreNativeSharedImage(): Promise<{
  success: boolean;
  fileName?: string;
}> {
  // Prevent duplicate processing
  if (isProcessingSharedImage) {
    logger.debug(
      "[Main] ⏸️ Shared image processing already in progress, skipping",
    );
    return { success: false };
  }

  isProcessingSharedImage = true;

  try {
    if (
      !Capacitor.isNativePlatform() ||
      (Capacitor.getPlatform() !== "ios" &&
        Capacitor.getPlatform() !== "android")
    ) {
      isProcessingSharedImage = false;
      return { success: false };
    }

    // Use SharedImage plugin to get shared image data directly from native layer
    // No file I/O or polling needed - direct native-to-JS communication
    let result;
    try {
      result = await SharedImage.getSharedImage();
    } catch (error) {
      logger.error("[Main] Error calling SharedImage.getSharedImage():", {
        error: error instanceof Error ? error.message : String(error),
        stack: error instanceof Error ? error.stack : undefined,
      });
      isProcessingSharedImage = false;
      return { success: false };
    }

    // Check if we have valid image data (base64 must be non-null and non-empty)
    if (result && result.base64 && result.base64.trim().length > 0) {
      const fileName = result.fileName || "shared-image.jpg";

      // Store in temp database using extracted method
      logger.info(
        "[Main] Native shared image found (via plugin), storing in temp DB",
      );
      await storeSharedImageInTempDB(result.base64, fileName);

      isProcessingSharedImage = false;
      return { success: true, fileName };
    }

    // No shared image found
    logger.debug("[Main] No shared image found via plugin");
    isProcessingSharedImage = false;
    return { success: false };
  } catch (error) {
    logger.error("[Main] Error checking for native shared image:", error);
    isProcessingSharedImage = false;
    return { success: false };
  }
}

const handleDeepLink = async (data: { url: string }) => {
  const { url } = data;
  logger.debug(`[Main] 🌐 Deeplink received from Capacitor: ${url}`);

  try {
    // Handle empty path URLs from share extension (timesafari://)
    // These are used to open the app, and we should check for shared images
    const isEmptyPathUrl = url === "timesafari://" || url === "timesafari:///";

    if (
      isEmptyPathUrl &&
      Capacitor.isNativePlatform() &&
      Capacitor.getPlatform() === "ios"
    ) {
      logger.debug(
        "[Main] 📸 Empty path URL from share extension, checking for native shared image",
      );

      // Try to get shared image from App Group and store in temp database
      // AppDelegate writes the file when the deep link is received, so we may need to retry
      // The checkAndStoreNativeSharedImage function now uses polling internally, so we just call it once
      try {
        const imageResult = await checkAndStoreNativeSharedImage();

        if (imageResult.success) {
          logger.info(
            "[Main] ✅ Native shared image found, navigating to shared-photo",
          );

          // Wait for router to be ready
          await router.isReady();

          // Navigate directly to shared-photo route
          // Use replace if already on shared-photo to force refresh, otherwise push
          const fileName = imageResult.fileName || "shared-image.jpg";
          const isAlreadyOnSharedPhoto =
            router.currentRoute.value.path === "/shared-photo";

          if (isAlreadyOnSharedPhoto) {
            // Force refresh by replacing the route
            await router.replace({
              path: "/shared-photo",
              query: { fileName, _refresh: Date.now().toString() }, // Add timestamp to force update
            });
          } else {
            await router.push({
              path: "/shared-photo",
              query: { fileName },
            });
          }

          logger.info(
            `[Main] ✅ Navigated to /shared-photo?fileName=${fileName}`,
          );
          return; // Exit early, don't process as deep link
        } else {
          logger.debug(
            "[Main] ℹ️ No native shared image found, ignoring empty path URL",
          );
          return; // Exit early, don't process empty path as deep link
        }
      } catch (error) {
        logger.error("[Main] Error processing native shared image:", error);
        // If check fails, don't process as deep link (empty path would fail validation anyway)
        return;
      }
    }

    // Wait for router to be ready
    logger.debug(`[Main] ⏳ Waiting for router to be ready...`);
    await router.isReady();
    logger.debug(`[Main] ✅ Router is ready, processing deeplink`);

    // Process the deeplink
    logger.debug(`[Main] 🚀 Starting deeplink processing`);
    await deepLinkHandler.handleDeepLink(url);
    logger.debug(`[Main] ✅ Deeplink processed successfully`);
  } catch (error) {
    logger.error(`[Main] ❌ Deeplink processing failed:`, {
      url,
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
      timestamp: new Date().toISOString(),
    });

    // Log additional context for debugging
    logger.error(`[Main] 🔍 Debug context:`, {
      routerReady: router.isReady(),
      currentRoute: router.currentRoute.value,
      appMounted: app._instance?.isMounted,
      timestamp: new Date().toISOString(),
    });

    // Fallback to original error handling
    let message: string =
      error instanceof Error ? error.message : safeStringify(error);
    if (url) {
      message += `\nURL: ${url}`;
    }
    handleApiError({ message } as AxiosError, "deep-link");
  }
};

// Function to register the deeplink listener
const registerDeepLinkListener = async () => {
  try {
    logger.info(
      `[Main] 🔗 Attempting to register deeplink handler with Capacitor`,
    );

    // Check if Capacitor App plugin is available
    logger.debug(`[Main] 🔍 Checking Capacitor App plugin availability...`);
    if (!CapacitorApp) {
      throw new Error("Capacitor App plugin not available");
    }
    logger.info(`[Main] ✅ Capacitor App plugin is available`);

    // Check available methods on CapacitorApp
    logger.debug(
      `[Main] 🔍 Capacitor App plugin methods:`,
      Object.getOwnPropertyNames(CapacitorApp),
    );
    logger.debug(
      `[Main] 🔍 Capacitor App plugin addListener method:`,
      typeof CapacitorApp.addListener,
    );

    // Wait for router to be ready first
    await router.isReady();
    logger.debug(
      `[Main] ✅ Router is ready, proceeding with listener registration`,
    );

    // Try to register the listener
    logger.info(`[Main] 🧪 Attempting to register appUrlOpen listener...`);
    const listenerHandle = await CapacitorApp.addListener(
      "appUrlOpen",
      handleDeepLink,
    );
    logger.info(
      `[Main] ✅ appUrlOpen listener registered successfully with handle:`,
      listenerHandle,
    );

    return listenerHandle;
  } catch (error) {
    logger.error(`[Main] ❌ Failed to register deeplink listener:`, {
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
      timestamp: new Date().toISOString(),
    });
    throw error;
  }
};

/**
 * Check for shared image and navigate to shared-photo route if found
 * This is called when app becomes active (from share extension or app launch)
 */
async function checkForSharedImageAndNavigate() {
  if (
    !Capacitor.isNativePlatform() ||
    (Capacitor.getPlatform() !== "ios" && Capacitor.getPlatform() !== "android")
  ) {
    return;
  }

  try {
    logger.debug("[Main] 🔍 Checking for shared image on app activation");
    const imageResult = await checkAndStoreNativeSharedImage();

    if (imageResult.success) {
      logger.info(
        "[Main] ✅ Shared image found, navigating to shared-photo route",
      );

      // Wait for router to be ready
      await router.isReady();

      // Navigate to shared-photo route with fileName if available
      // Use replace if already on shared-photo to force refresh, otherwise push
      const fileName = imageResult.fileName || "shared-image.jpg";
      const isAlreadyOnSharedPhoto =
        router.currentRoute.value.path === "/shared-photo";

      if (isAlreadyOnSharedPhoto) {
        // Force refresh by replacing the route
        await router.replace({
          path: "/shared-photo",
          query: { fileName, _refresh: Date.now().toString() }, // Add timestamp to force update
        });
      } else {
        const route = imageResult.fileName
          ? `/shared-photo?fileName=${encodeURIComponent(imageResult.fileName)}`
          : "/shared-photo";
        await router.push(route);
      }

      logger.info(`[Main] ✅ Navigated to /shared-photo?fileName=${fileName}`);
    } else {
      logger.debug("[Main] ℹ️ No shared image found");
    }
  } catch (error) {
    logger.error("[Main] ❌ Error checking for shared image:", error);
  }
}

logger.log("[Capacitor] 🚀 Mounting app");
app.mount("#app");
logger.info(`[Main] ✅ App mounted successfully`);

// Check for shared image on initial load (in case app was launched from share sheet)
// On Android, share intents are processed in MainActivity.onCreate, so we need to check
// after a delay to ensure the native code has finished processing
if (
  Capacitor.isNativePlatform() &&
  (Capacitor.getPlatform() === "ios" || Capacitor.getPlatform() === "android")
) {
  // Use multiple checks with increasing delays to handle timing issues
  // Android share intent processing happens in onCreate, which may complete after JS loads
  const checkDelays =
    Capacitor.getPlatform() === "android"
      ? [500, 1500, 3000] // Android needs more time for share intent processing
      : [1000]; // iOS is faster

  checkDelays.forEach((delay) => {
    setTimeout(async () => {
      await checkForSharedImageAndNavigate();
    }, delay);
  });
}

// Listen for app state changes to detect when app becomes active
if (
  Capacitor.isNativePlatform() &&
  (Capacitor.getPlatform() === "ios" || Capacitor.getPlatform() === "android")
) {
  CapacitorApp.addListener("appStateChange", async ({ isActive }) => {
    if (isActive) {
      logger.debug("[Main] 📱 App became active, checking for shared image");
      await checkForSharedImageAndNavigate();
    }
  });
}

// Register deeplink listener after app is mounted
setTimeout(async () => {
  try {
    logger.info(
      `[Main] ⏳ Delaying listener registration to ensure Capacitor is ready...`,
    );
    await registerDeepLinkListener();
    logger.info(`[Main] 🎉 Deep link system fully initialized!`);
  } catch (error) {
    logger.error(`[Main] ❌ Deep link system initialization failed:`, error);
  }
}, 2000); // 2 second delay to ensure Capacitor is fully ready

// Log app initialization status
setTimeout(() => {
  logger.info(`[Main] 📊 App initialization status:`, {
    routerReady: router.isReady(),
    currentRoute: router.currentRoute.value,
    appMounted: app._instance?.isMounted,
    timestamp: new Date().toISOString(),
  });
}, 1000);
