(function initVisaFlowXAutomation(global) {
  "use strict";

  if (global.top && global.top !== global) return;
  if (global.__VisaFlowXAutomationReady) return;
  global.__VisaFlowXAutomationReady = true;

  const {
    CaptchaSolver,
    Detector,
    DomUtils,
    NotificationHandler,
    OtpMonitor,
    RetryEngine,
    Storage,
    Timers
  } = global.VisaFlowX;

  function log(message) {
    console.log("[VisaFlowX]", message);
  }

  function logVerification(event, details = {}) {
    console.log("[VisaFlowX][Verification]", event, details);
  }

  const VERIFICATION_COMPLETION_SIGNAL_MS = 5000;
  const DOM_EVALUATION_DEBOUNCE_MS = 25;
  const CF_MONITOR_MS = 50;
  const TOKEN_RECHECK_MS = 50;
  const SIGNIN_WAIT_MS = 200;
  const SIGNIN_CLICK_GUARD_MS = 300;
  const SIGNIN_RETRY_SAFETY_MS = 500;
  const SIGNIN_FAILED_RETRY_MS = 300;
  const OTP_WAIT_MS = 300;
  const WATCHDOG_MS = 1000;
  const STUCK_RECOVERY_MS = 10000;
  const VERIFICATION_COMPLETION_SOURCES = new Set(["captcha_solved", "verification_completed"]);
  const VERIFICATION_MONITOR_SOURCES = new Set([
    "cf_monitor",
    "token_stabilize",
    "verification_completed",
    "captcha_solved",
    "verification_reconcile"
  ]);
  const PRIORITY_EVALUATION_SOURCES = new Set([
    ...VERIFICATION_MONITOR_SOURCES,
    "signin_failed_retry",
    "signin_retry_safety",
    "otp_wait"
  ]);

  class IvacAutomation {
    constructor() {
      this.running = false;
      this.otpLocked = false;
      this.runToken = 0;
      this.credentials = {};
      this.retrySettings = {};
      this.settings = {};
      this.observer = null;
      this.evaluationTimer = null;
      this.evaluating = false;
      this.lastSignInClickAt = 0;
      this.signInAttemptCount = 0;
      this.autofillReported = false;
      this.verificationSeen = false;
      this.lastVerificationCompletedAt = 0;
      this.lastProgressAt = Date.now();
      this.retryEngine = new RetryEngine(this);
      this.handleLoginWorkflow = this.handleLoginWorkflow.bind(this);
      this.debouncedEvaluate = Timers.debounce(() => this.handleLoginWorkflow("dom_change"), DOM_EVALUATION_DEBOUNCE_MS);
      this.handlePageHide = () => this.stop("pagehide", { silent: true });
    }

    async start(payload = {}) {
      this.stop("restart", { silent: true });
      this.runToken += 1;
      this.otpLocked = false;
      const defaults = await Storage.ensureDefaults();
      this.credentials = payload.credentials || defaults.credentials;
      this.retrySettings = payload.retry || defaults.retry;
      this.settings = payload.settings || defaults.settings;
      this.running = true;
      this.lastSignInClickAt = 0;
      this.signInAttemptCount = 0;
      this.autofillReported = false;
      this.verificationSeen = false;
      this.lastVerificationCompletedAt = 0;
      this.retryEngine.reset();
      OtpMonitor.reset?.();
      OtpMonitor.startWatching?.(this.settings);
      this.observe();
      global.VisaFlowX?.CooldownManager?.installServerCooldownWatcher?.((parsed) => {
        if (!this.running || this.otpLocked) return;
        this.retryEngine._handleServerCooldown(parsed, this.retrySettings).catch((error) => {
          console.warn("[VisaFlowX]", "Server cooldown handling failed", error?.message || error);
        });
      });
      log("Automation started");
      this.lastProgressAt = Date.now();
      await this.updateStatus({
        state: "RUNNING",
        page: location.href,
        verificationState: "Checking",
        otpState: "Idle",
        lastAction: "Automation started",
        lastError: ""
      });
      await this.handleLoginWorkflow("start");
    }

    stop(reason = "manual", options = {}) {
      this.runToken += 1;
      this.running = false;
      if (reason === "otp_detected" || reason === "reload_blocked") this.otpLocked = true;
      if (this.observer) this.observer.disconnect();
      this.observer = null;
      this.clearEvaluationTimer();
      this.retryEngine.reset();
      this.lastVerificationCompletedAt = 0;
      if (reason !== "otp_detected") OtpMonitor.stopWatching?.();
      global.VisaFlowX?.CooldownManager?.stopServerCooldownWatcher?.();
      window.removeEventListener("pageshow", this.debouncedEvaluate);
      window.removeEventListener("focus", this.debouncedEvaluate);
      window.removeEventListener("pagehide", this.handlePageHide);
      if (!options.silent) {
        this.updateStatus({
          state: reason === "completed" ? "RUNNING" : "STOPPED",
          retryCountdownEndsAt: null,
          verificationState: "Idle",
          lastAction: reason === "completed" ? "Signed in. Waiting for OTP page." : `Automation stopped (${reason})`
        });
      }
    }

    pauseForServerCooldown() {
      if (!this.running && !this.retryEngine.hasPendingRetry()) return;
      log("Automation paused for server cooldown");
      this.stop("server_cooldown", { silent: true });
    }

    isCurrentRun(token = this.runToken) {
      return this.running && !this.otpLocked && this.runToken === token;
    }

    markVerificationCompleted(source = "completion_signal") {
      this.lastVerificationCompletedAt = Date.now();
      this.verificationSeen = true;
      this.lastProgressAt = Date.now();
      log(`Verification completed (${source}). Resuming sign-in.`);
    }

    shouldBypassRetryForVerification(source, pageState = {}) {
      if (pageState.type !== "signin") return false;
      const verification = pageState.verification || {};
      return Boolean(
        VERIFICATION_MONITOR_SOURCES.has(source)
        || this.verificationSeen
        || this.hasFreshVerificationCompletion()
        || verification.present === true
        || verification.pending === true
        || verification.completed === true
      );
    }

    async resumeAutomation(source = "verification_completed") {
      this.markVerificationCompleted(source);
      logVerification("resumeAutomation called", { source });
      await this.updateStatus({
        state: "RUNNING",
        verificationState: "Verification completed",
        lastAction: "Signing in",
        lastError: ""
      });
      return this.handleLoginWorkflow(source);
    }

    hasFreshVerificationCompletion() {
      return Date.now() - this.lastVerificationCompletedAt <= VERIFICATION_COMPLETION_SIGNAL_MS;
    }

    clearEvaluationTimer() {
      if (this.evaluationTimer) clearTimeout(this.evaluationTimer);
      this.evaluationTimer = null;
    }

    scheduleEvaluation(source = "watchdog", delayMs = 0) {
      const token = this.runToken;
      const priority = PRIORITY_EVALUATION_SOURCES.has(source);
      if (!this.isCurrentRun(token) || (this.retryEngine.hasPendingRetry() && !priority)) return;
      this.clearEvaluationTimer();
      
      const timeout = Math.max(0, Number(delayMs) || 0);
      this.evaluationTimer = setTimeout(() => {
        this.evaluationTimer = null;
        if (!this.isCurrentRun(token)) return;

        // Watchdog: recover without adding a tight foreground loop.
        const elapsedSinceProgress = Date.now() - this.lastProgressAt;
        if (elapsedSinceProgress > STUCK_RECOVERY_MS && source === "watchdog") {
          log("Watchdog triggered: Automation appears stuck. Recovering...");
          this.lastProgressAt = Date.now();
          source = "recovery_watchdog";
        }

        this.handleLoginWorkflow(source).catch((error) => {
          if (!this.isCurrentRun(token)) return;
          this.updateStatus({
            state: "RETRYING",
            lastAction: "Recovering from automation error",
            lastError: error.message
          });
        });
      }, timeout);
    }

    observe() {
      const target = document.documentElement || document.body;
      if (!target) return;
      if (this.observer) this.observer.disconnect();
      this.observer = new MutationObserver(this.debouncedEvaluate);
      this.observer.observe(target, {
        childList: true,
        subtree: true,
        characterData: true,
        attributes: true,
        attributeFilter: ["class", "style", "disabled", "aria-disabled", "hidden", "value"]
      });
      window.addEventListener("pageshow", this.debouncedEvaluate, { passive: true });
      window.addEventListener("focus", this.debouncedEvaluate, { passive: true });
      window.addEventListener("pagehide", this.handlePageHide, { passive: true });
    }

    async updateStatus(patch, options = {}) {
      if (!chrome?.runtime?.sendMessage) return;
      const status = {
        page: location.href,
        activeSite: location.hostname,
        updatedAt: new Date().toISOString(),
        ...patch
      };
      await chrome.runtime.sendMessage({
        type: "STATUS_UPDATE",
        status,
        notify: options.notify || ""
      }).catch(() => {});
    }

    hasCredentials() {
      return Boolean(this.credentials.contactNumber && this.credentials.password);
    }

    async autofill(pageState) {
      if (!this.hasCredentials()) {
        await this.updateStatus({
          state: "RETRYING",
          lastAction: "Credentials required",
          lastError: "Save contact number and password before starting automation."
        });
        return false;
      }

      const contactAlreadyFilled = String(pageState.contact?.value || "") === String(this.credentials.contactNumber || "");
      const passwordAlreadyFilled = String(pageState.password?.value || "") === String(this.credentials.password || "");
      const contactFilled = DomUtils.setInputValue(pageState.contact, this.credentials.contactNumber);
      const passwordFilled = DomUtils.setInputValue(pageState.password, this.credentials.password);
      if (!contactFilled || !passwordFilled) {
        await this.updateStatus({
          state: "RETRYING",
          lastAction: "Autofill failed",
          lastError: "Could not find the IVAC contact or password field."
        });
        return false;
      }

      if (!this.autofillReported || !contactAlreadyFilled || !passwordAlreadyFilled) {
        this.autofillReported = true;
        await this.updateStatus({
          state: "RUNNING",
          verificationState: pageState.verification.present ? "Visible" : "Not visible",
          lastAction: "Credentials autofilled",
          lastError: ""
        });
      }
      return true;
    }

    async waitForVerification(pageState) {
      const firstSeen = !this.verificationSeen;
      this.verificationSeen = true;
      this.lastProgressAt = Date.now(); // Verification detection is progress
      logVerification("verification detected", {
        selector: pageState.verification?.selector || "",
        completed: pageState.verification?.completed === true
      });

      const target = Detector.resolveTurnstileTarget?.(document);
      const verification = target?.element
        ? { ...pageState.verification, selector: target.selector, element: target.element }
        : pageState.verification;
      
      DomUtils.focusElement(verification.element);
      DomUtils.pulseHighlight(verification.element);
      
      if (!verification.completed) {
        await this.reportChallengeState(true, verification);
      }
      
      // Step 2 & 3: High-frequency Turnstile monitoring and auto-click checkbox
      const assist = await CaptchaSolver?.tryAutoSolve?.(verification).catch(() => null);
      
      if (assist?.solved === true) {
        log("Verification solved via assistant.");
        this.markVerificationCompleted("assistant");
        await this.reportChallengeState(false, {
          ...verification,
          completed: true,
          selector: verification.selector || "cf-turnstile-response"
        });
        logVerification("verification success detected", {
          source: "assistant",
          selector: verification.selector || "cf-turnstile-response"
        });
        this.verificationSeen = false;
        return { completed: true };
      }
      
      await this.updateStatus({
        state: "WAITING_VERIFICATION",
        verificationState: "Waiting for verification completion",
        lastAction: firstSeen ? "Verification detected" : "Waiting for verification completion",
        lastError: ""
      });
      return { completed: false };
    }

    async reportChallengeState(active, verification = {}) {
      if (!chrome?.runtime?.sendMessage) return null;
      return chrome.runtime.sendMessage({
        type: "CHALLENGE_STATE",
        active,
        completed: active === true ? false : verification.completed === true,
        selector: verification.selector || "",
        source: "automation",
        url: location.href
      }).catch(() => null);
    }

    submitWithFallback(button) {
      const form = button?.form || button?.closest?.("form");
      if (!form) return false;
      try {
        if (typeof form.requestSubmit === "function") {
          form.requestSubmit(button);
          logVerification("Sign In requestSubmit fallback used");
          return true;
        }
      } catch (_) {
        // Fall through to the native submit fallback.
      }

      try {
        if (typeof form.submit === "function") {
          form.submit();
          logVerification("Sign In form.submit fallback used");
          return true;
        }
      } catch (_) {
        return false;
      }
      return false;
    }

    async clickSignIn(pageState, runToken = this.runToken) {
      if (!this.isCurrentRun(runToken)) return false;
      logVerification("Sign In resolver started", {
        source: pageState.verification?.selector || "no_verification"
      });
      const verification = Detector.detectVerification(document);
      if (
        (verification.present === true || verification.pending === true)
        && verification.completed !== true
        && !this.hasFreshVerificationCompletion()
      ) {
        logVerification("Sign In blocked until verification completes", {
          selector: verification.selector || ""
        });
        await this.reportChallengeState(true, verification);
        await this.updateStatus({
          state: "WAITING_VERIFICATION",
          verificationState: "Waiting for verification completion",
          lastAction: "Waiting for verification completion",
          lastError: ""
        });
        this.scheduleEvaluation("cf_monitor", CF_MONITOR_MS);
        return false;
      }

      const button = Detector.isSafeSignInButton?.(pageState.signInButton)
        ? pageState.signInButton
        : Detector.findSignInButton(document);

      if (!Detector.isSafeSignInButton?.(button)) {
        await this.updateStatus({
          state: "RUNNING",
          lastAction: "Waiting for Sign In button",
          lastError: ""
        });
        if (this.isCurrentRun(runToken)) this.scheduleEvaluation("signin_wait", SIGNIN_WAIT_MS);
        return false;
      }

      const elapsed = Date.now() - this.lastSignInClickAt;
      if (elapsed < SIGNIN_CLICK_GUARD_MS && this.signInAttemptCount > 0 && !this.verificationSeen) {
        this.scheduleEvaluation("debounced_signin", SIGNIN_CLICK_GUARD_MS - elapsed);
        return false;
      }

      if (this.signInAttemptCount >= 2 && elapsed < SIGNIN_RETRY_SAFETY_MS) {
        log("Maximum sign-in attempts reached. Waiting for page transition.");
        return false;
      }

      this.lastSignInClickAt = Date.now();
      this.signInAttemptCount = (this.signInAttemptCount || 0) + 1;
      
      log(`Attempting Sign In (Attempt ${this.signInAttemptCount})`);
      await this.updateStatus({
        state: "RUNNING",
        verificationState: "Verification completed",
        lastAction: "Signing in",
        lastError: ""
      });
      
      const clicked = await DomUtils.dispatchPointerClick(button);
      
      if (!clicked && !this.submitWithFallback(button)) {
        log("Sign In click failed. Scheduling retry.");
        this.scheduleEvaluation("signin_failed_retry", SIGNIN_FAILED_RETRY_MS);
        return false;
      }

      await this.updateStatus({
        state: "RUNNING",
        verificationState: this.verificationSeen ? "Completed or no longer visible" : "Not required",
        lastAction: `Sign In clicked (Attempt ${this.signInAttemptCount})`,
        lastError: ""
      });
      logVerification("Sign In clicked", {
        attempt: this.signInAttemptCount,
        selector: pageState.verification?.selector || ""
      });

      if (this.signInAttemptCount < 2) {
        this.scheduleEvaluation("signin_retry_safety", SIGNIN_RETRY_SAFETY_MS);
      }

      return true;
    }

    async handleLoginWorkflow(source = "manual") {
      const runToken = this.runToken;
      if (!this.isCurrentRun(runToken)) return;
      if (this.evaluating) {
        if (source === "captcha_solved" || source === "verification_completed") {
          this.evaluating = false; // Force re-evaluation for completion signals
        } else {
          this.scheduleEvaluation(source, 50);
          return;
        }
      }
      this.evaluating = true;
      this.clearEvaluationTimer();
      let keepWatching = true;

      try {
        const pageState = Detector.detectPage();

        // ── Step 9: OTP page — TERMINAL STATE ────────────────────────
        if (pageState.type === "otp") {
          log("OTP detected. Stopping all login automation.");
          logVerification("OTP detected", { reason: pageState.otp?.reason || "" });
          keepWatching = false;
          this.otpLocked = true;
          this.signInAttemptCount = 0;
          this.lastProgressAt = Date.now();
          
          const otpSignal = OtpMonitor.trigger(pageState, this.settings);
          this.stop("otp_detected", { silent: true });
          this.clearEvaluationTimer();
          
          await otpSignal.catch((error) => {
            console.warn("[VisaFlowX]", "OTP trigger failed", error?.message || error);
          });

          await this.updateStatus({
            state: "OTP_DETECTED",
            otpState: "Detected",
            retryCountdownEndsAt: null,
            lastAction: "OTP detected. Handoff to user.",
            lastError: ""
          }, { notify: "otp" });
          
          return;
        }

        // ── Signed in but waiting for OTP page to appear ────────────
        if (pageState.type === "completed") {
          this.lastProgressAt = Date.now();
          await this.updateStatus({
            state: "RUNNING",
            verificationState: "Completed",
            otpState: "Waiting",
            retryCountdownEndsAt: null,
            lastAction: "Login successful. Waiting for OTP page...",
            lastError: ""
          });
          if (this.isCurrentRun(runToken)) this.scheduleEvaluation("otp_wait", OTP_WAIT_MS);
          return;
        }

        // ── Page-level errors / retry messages / Cooldowns ──────────
        if (!this.isCurrentRun(runToken)) return;
        const bypassRetryPause = this.shouldBypassRetryForVerification(source, pageState);
        if (!bypassRetryPause && await this.retryEngine.handlePageState(pageState, this.retrySettings)) {
          this.lastProgressAt = Date.now(); // Error detection/handling is progress
          return;
        }
        if (bypassRetryPause && VERIFICATION_COMPLETION_SOURCES.has(source)) {
          logVerification("retry-engine pause bypassed", { source });
        }

        // ── Not on signin page yet ──────────────────────────────────
        if (pageState.type !== "signin") {
          await this.updateStatus({
            state: "RETRYING",
            lastAction: source === "start" ? "Navigating to IVAC signin" : "Redirected. Returning to signin...",
            lastError: pageState.type === "unsupported" ? "Open https://appointment.ivacbd.com/signin" : ""
          });
          await this.retryEngine.schedule(0, "Navigating to signin", "reload", this.retrySettings);
          return;
        }

        // ── Step 1: Autofill ────────────────────────────────────────
        if (!this.isCurrentRun(runToken)) return;
        if (!await this.autofill(pageState)) return;

        // ── Step 2 & 4: Turnstile Monitoring & Success Detection ─────
        let latestVerification = Detector.detectVerification(document);
        if (
          VERIFICATION_COMPLETION_SOURCES.has(source)
          || (
            this.hasFreshVerificationCompletion()
            && (latestVerification.present || latestVerification.pending)
          )
        ) {
          latestVerification = {
            ...latestVerification,
            present: false,
            pending: false,
            completed: true,
            selector: latestVerification.selector || "verification_completion_signal"
          };
        }

        if (latestVerification.present || latestVerification.completed) {
          this.verificationSeen = true;
          let completed = latestVerification.completed;
          
          if (!completed) {
            const verificationResult = await this.waitForVerification({ ...pageState, verification: latestVerification });
            completed = !!verificationResult?.completed;
          }

          if (!completed) {
            // Step 2: High-frequency lightweight monitoring
            if (this.isCurrentRun(runToken)) this.scheduleEvaluation("cf_monitor", CF_MONITOR_MS);
            return;
          }
          
          // Step 5: Instant Sign In Continuation after success
          log("Verification successful. Triggering instant sign-in.");
          await this.reportChallengeState(false, {
            ...latestVerification,
            completed: true,
            selector: latestVerification.selector || "cf-turnstile-response"
          });
          await this.clickSignIn({ ...pageState, verification: latestVerification }, runToken);
          return;
        }

        if (latestVerification.pending) {
          await this.updateStatus({
            state: "WAITING_VERIFICATION",
            verificationState: "Waiting for verification completion",
            lastAction: "Verification in progress",
            lastError: ""
          });
          if (this.isCurrentRun(runToken)) this.scheduleEvaluation("token_stabilize", TOKEN_RECHECK_MS);
          return;
        }

        if (this.verificationSeen) {
          this.lastProgressAt = Date.now();
          await this.reportChallengeState(false, {
            ...latestVerification,
            completed: true,
            selector: latestVerification.selector || "verification_no_longer_visible"
          });
          this.verificationSeen = false;
        }

        // No captcha — Step 5: Instant Sign In
        await this.clickSignIn({ ...pageState, verification: latestVerification }, runToken);

      } catch (error) {
        if (!this.isCurrentRun(runToken)) return;
        await this.updateStatus({
          state: "RETRYING",
          retryCountdownEndsAt: null,
          lastAction: "Automation error encountered",
          lastError: error.message
        });
        await this.retryEngine.schedule(0, `Error: ${error.message}`, "reload", this.retrySettings);
      } finally {
        this.evaluating = false;
        if (keepWatching && this.isCurrentRun(runToken) && !this.retryEngine.hasPendingRetry()) {
          // Standard watchdog loop
          if (source !== "watchdog" && source !== "cf_monitor" && source !== "otp_wait") {
            this.scheduleEvaluation("watchdog", WATCHDOG_MS);
          }
        }
      }
    }
  }

  const automation = global.VisaFlowXAutomation || new IvacAutomation();
  global.VisaFlowXAutomation = automation;
  global.VisaFlowX = Object.assign(global.VisaFlowX || {}, { automation, IvacAutomation });

  chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
    (async () => {
      switch (message?.type) {
        case "PING":
          return { ok: true, ready: true, running: automation.running, url: location.href };
        case "START_AUTOMATION":
          await automation.start(message);
          return { ok: true };
        case "STOP_AUTOMATION":
          automation.stop(message.reason || "manual");
          NotificationHandler.stopAlarm();
          return { ok: true };
        case "PAUSE_FOR_SERVER_COOLDOWN":
          automation.pauseForServerCooldown();
          return { ok: true };
        case "UNLOCK_AUDIO_CONTEXT":
          return { ok: true, ignored: true, reason: "audio_unlock_requires_page_gesture" };
        case "TEST_ALARM":
          await NotificationHandler.playAlarm({ volume: message.volume ?? 1, muted: false });
          return { ok: true };
        case "STOP_ALARM":
          NotificationHandler.stopAlarm();
          return { ok: true };
        case "MUTE_ALARM":
          NotificationHandler.muteAlarm();
          return { ok: true };
        case "SET_ALARM_VOLUME":
          NotificationHandler.setVolume(message.volume ?? 1);
          return { ok: true };
        case "CAPTCHA_RESULT":
          if (message.success) {
            logVerification("runtime message received", { type: "CAPTCHA_RESULT" });
            logVerification("verificationResolved=true", { source: "CAPTCHA_RESULT" });
            automation.resumeAutomation("captcha_solved").catch(console.error);
          }
          return { ok: true };
        case "VERIFICATION_COMPLETED":
          logVerification("runtime message received", { type: "VERIFICATION_COMPLETED" });
          logVerification("verificationResolved=true", { source: "VERIFICATION_COMPLETED" });
          automation.resumeAutomation("verification_completed").catch(console.error);
          return { ok: true };
        case "VERIFICATION_STALE":
          automation.verificationSeen = false;
          automation.lastVerificationCompletedAt = 0;
          automation.handleLoginWorkflow("verification_stale").catch(console.error);
          return { ok: true };
        case "GET_VERIFICATION_STATE": {
          const verification = Detector.detectVerification(document);
          return {
            ok: true,
            verification: {
              present: verification.present === true,
              completed: verification.completed === true,
              pending: verification.pending === true,
              selector: verification.selector || "",
              url: location.href,
              hostname: location.hostname
            }
          };
        }
        default:
          return { ok: false, error: "Unknown content message" };
      }
    })()
      .then((response) => sendResponse(response))
      .catch((error) => sendResponse({ ok: false, error: error.message }));
    return true;
  });

  if (chrome?.runtime?.sendMessage) {
    chrome.runtime.sendMessage({
      type: "STATUS_UPDATE",
      status: {
        page: location.href,
        verificationState: "Idle",
        otpState: "Idle",
        lastAction: "IVAC content script ready",
        lastError: ""
      }
    }).catch(() => {});
  }
})(typeof globalThis !== "undefined" ? globalThis : this);
