"use strict";

import { Linking } from 'react-native';
import { URLParser } from "./URLParser.js";
import { RouteMatcher } from "./RouteMatcher.js";
import { DeferredLinkQueue } from "./DeferredLinkQueue.js";
import { ModalLayoutBuilder } from "./ModalLayoutBuilder.js";

/** A function that shows a layout as a modal. Mirrors `Commands.showModal`. */

/**
 * Minimal abstraction over React Native's `Linking` module so the handler
 * can be tested without touching native bindings.
 */

/**
 * Orchestrates deep linking:
 *
 *   1. Subscribes to URL events from `Linking` and the initial URL.
 *   2. Parses + matches each URL against the configured `screens` tree.
 *   3. Defers processing until both:
 *        - the first `setRoot` has resolved (so a modal can be presented), and
 *        - the user-supplied `isReady` predicate (if any) returns `true`.
 *   4. Resolves matches in this order:
 *        - `onLink(match)` if provided (full escape hatch), else
 *        - `getModal(match)` if provided, else
 *        - the default `ModalLayoutBuilder` output.
 *      Result is presented via `showModal`.
 *   5. Calls `fallback(url)` when a URL has no matching prefix or route.
 */
export class LinkingHandler {
  config = null;
  linkingSubscription = null;
  rootReady = false;
  userReadyOverride = null;
  constructor(showModal, linkingAPI) {
    this.urlParser = new URLParser();
    this.routeMatcher = new RouteMatcher();
    this.deferredQueue = new DeferredLinkQueue();
    this.modalLayoutBuilder = new ModalLayoutBuilder();
    this.showModal = showModal;
    this.linkingAPI = linkingAPI || Linking;
    this.deferredQueue.setFlushCallback(url => this.processURL(url));
  }
  configure(config) {
    this.teardown();
    this.config = config;
    const tree = this.routeMatcher.buildRouteTree(config.config.screens);
    this.routeMatcher.setRouteTree(tree);
    this.refreshReady();
    this.subscribe();
  }

  /**
   * Manually feed a URL into the pipeline as if it came from the OS.
   * Useful for URLs received from push notifications or other sources.
   */
  handleURL(url) {
    if (!this.config) return;
    if (!this.isReady()) {
      this.deferredQueue.enqueue(url);
      return;
    }
    this.processURL(url);
  }

  /**
   * Called by `NavigationRoot` after the first `setRoot` resolves. Subsequent
   * calls are no-ops.
   */
  setRootReady() {
    if (this.rootReady) return;
    this.rootReady = true;
    this.refreshReady();
  }

  /**
   * Public toggle for the app-supplied readiness gate. Overrides the
   * `config.isReady` predicate from the moment it's first called.
   */
  setLinkingReady(ready) {
    this.userReadyOverride = ready;
    this.refreshReady();
  }

  /**
   * Resolve a URL to a `RouteMatch` without side effects. Returns `null`
   * when the URL doesn't match any configured prefix or route.
   */
  resolve(url) {
    if (!this.config) return null;
    const parsed = this.urlParser.parse(url, this.config.prefixes);
    if (!parsed) return null;
    return this.routeMatcher.match(parsed.path, url, parsed.queryParams);
  }
  teardown() {
    if (this.linkingSubscription) {
      this.linkingSubscription.remove();
      this.linkingSubscription = null;
    }
    this.deferredQueue.clear();
    this.config = null;
    this.userReadyOverride = null;
  }
  subscribe() {
    this.linkingSubscription = this.linkingAPI.addEventListener('url', event => {
      this.handleURL(event.url);
    });
    this.linkingAPI.getInitialURL().then(url => {
      if (url) this.handleURL(url);
    });
  }
  processURL(url) {
    if (!this.config) return;
    const match = this.resolve(url);
    if (!match) {
      this.config.fallback?.(url);
      return;
    }
    if (this.config.onLink) {
      this.config.onLink(match);
      return;
    }
    const layout = this.config.getModal ? this.config.getModal(match) : this.modalLayoutBuilder.build(match);
    if (layout) {
      this.showModal(layout);
    }
  }
  isReady() {
    if (!this.rootReady) return false;
    if (this.userReadyOverride !== null) return this.userReadyOverride;
    if (this.config?.isReady) return this.config.isReady();
    return true;
  }
  refreshReady() {
    this.deferredQueue.setReady(this.isReady());
  }
}
//# sourceMappingURL=LinkingHandler.js.map