/**
 * @file Deep Link Handler Service
 * @author Matthew Raymer
 *
 * This service handles the processing and routing of deep links in the TimeSafari app.
 * It provides a type-safe interface between the raw deep links and the application router.
 *
 * Architecture:
 * 1. DeepLinkHandler class encapsulates all deep link processing logic
 * 2. Uses Zod schemas from types/deepLinks for parameter validation
 * 3. Provides consistent error handling and logging
 * 4. Maps validated parameters to Vue router calls
 *
 * Error Handling Strategy:
 * - All errors are wrapped in DeepLinkError interface
 * - Errors include error codes for systematic handling
 * - Detailed error information is logged for debugging
 * - Errors are propagated to the global error handler
 *
 * Validation Strategy:
 * - URL structure validation
 * - Route-specific parameter validation using Zod schemas
 * - Query parameter validation and sanitization
 * - Type-safe parameter passing to router
 *
 * @example
 * const handler = new DeepLinkHandler(router);
 * await handler.handleDeepLink("timesafari://claim/123?view=details");
 */

import { Router } from "vue-router";
import {
  deepLinkSchemas,
  baseUrlSchema,
  routeSchema,
  DeepLinkRoute,
} from "../types/deepLinks";
import { logConsoleAndDb } from "../db";
import type { DeepLinkError } from "../interfaces/deepLinks";

export class DeepLinkHandler {
  private router: Router;

  constructor(router: Router) {
    this.router = router;
  }

  /**
   * Parses deep link URL into path, params and query components
   */
  private parseDeepLink(url: string) {
    const parts = url.split("://");
    if (parts.length !== 2) {
      throw { code: "INVALID_URL", message: "Invalid URL format" };
    }

    // Validate base URL structure
    baseUrlSchema.parse({
      scheme: parts[0],
      path: parts[1],
      queryParams: {}, // Will be populated below
    });

    const [path, queryString] = parts[1].split("?");
    const [routePath, param] = path.split("/");

    const query: Record<string, string> = {};
    if (queryString) {
      new URLSearchParams(queryString).forEach((value, key) => {
        query[key] = value;
      });
    }

    return {
      path: routePath,
      params: param ? { id: param } : {},
      query,
    };
  }

  /**
   * Processes incoming deep links and routes them appropriately
   * @param url The deep link URL to process
   */
  async handleDeepLink(url: string): Promise<void> {
    try {
      logConsoleAndDb("[DeepLink] Processing URL: " + url, false);
      const { path, params, query } = this.parseDeepLink(url);
      // Ensure params is always a Record<string,string> by converting undefined to empty string
      const sanitizedParams = Object.fromEntries(
        Object.entries(params).map(([key, value]) => [key, value ?? ""]),
      );
      await this.validateAndRoute(path, sanitizedParams, query);
    } catch (error) {
      const deepLinkError = error as DeepLinkError;
      logConsoleAndDb(
        `[DeepLink] Error (${deepLinkError.code}): ${deepLinkError.message}`,
        true,
      );

      throw {
        code: deepLinkError.code || "UNKNOWN_ERROR",
        message: deepLinkError.message,
        details: deepLinkError.details,
      };
    }
  }

  /**
   * Routes the deep link to appropriate view with validated parameters
   */
  private async validateAndRoute(
    path: string,
    params: Record<string, string>,
    query: Record<string, string>,
  ): Promise<void> {
    const routeMap: Record<string, string> = {
      "user-profile": "user-profile",
      "project-details": "project-details",
      "onboard-meeting-setup": "onboard-meeting-setup",
      "invite-one-accept": "invite-one-accept",
      "contact-import": "contact-import",
      "confirm-gift": "confirm-gift",
      claim: "claim",
      "claim-cert": "claim-cert",
      "claim-add-raw": "claim-add-raw",
      "contact-edit": "contact-edit",
      contacts: "contacts",
      did: "did",
    };

    // First try to validate the route path
    let routeName: string;

    try {
      // Validate route exists
      const validRoute = routeSchema.parse(path) as DeepLinkRoute;
      routeName = routeMap[validRoute];
    } catch (error) {
      // Log the invalid route attempt
      logConsoleAndDb(`[DeepLink] Invalid route path: ${path}`, true);

      // Redirect to error page with information about the invalid link
      await this.router.replace({
        name: "deep-link-error",
        query: {
          originalPath: path,
          errorCode: "INVALID_ROUTE",
          message: `The link you followed (${path}) is not supported`,
        },
      });

      throw {
        code: "INVALID_ROUTE",
        message: `Unsupported route: ${path}`,
      };
    }

    // Continue with parameter validation as before...
    const schema = deepLinkSchemas[path as keyof typeof deepLinkSchemas];

    try {
      const validatedParams = await schema.parseAsync({
        ...params,
        ...query,
      });

      await this.router.replace({
        name: routeName,
        params: validatedParams,
        query,
      });
    } catch (error) {
      // For parameter validation errors, provide specific error feedback
      await this.router.replace({
        name: "deep-link-error",
        query: {
          originalPath: path,
          errorCode: "INVALID_PARAMETERS",
          message: `The link parameters are invalid: ${(error as Error).message}`,
        },
      });

      throw {
        code: "INVALID_PARAMETERS",
        message: (error as Error).message,
        details: error,
      };
    }
  }
}