import { computed, onMounted, ref } from "vue";
import { auth, authFetch } from "../auth";
import { useOnboardingGuides } from "./useOnboardingGuides";
import { useOnboardingNavigation } from "./useOnboardingNavigation";
import { statusLabel, statusPillClass, taskPillClass } from "./onboardingLabels";
import { SECTION_DEFS, STEP_PREREQS, VAULTWARDEN_TEMP_STEP } from "./onboardingSections";

/**
 * Build the Onboarding page state machine.
 * WHY: onboarding coordinates request status, guide media, password reveal,
 * and service attestation flow; isolating that state keeps the view focused
 * on layout and makes the workflow independently testable.
 * @param {import("vue-router").RouteLocationNormalizedLoaded} route - active route with optional request code query params.
 * @returns {object} reactive onboarding state and event handlers.
 */
export function useOnboardingFlow(route) {
  const requestCode = ref("");
  const requestUsername = ref("");
  const status = ref("");
  const loading = ref(false);
  const error = ref("");
  const onboarding = ref({ required_steps: [], optional_steps: [], completed_steps: [] });
  const initialPassword = ref("");
  const initialPasswordRevealedAt = ref("");
  const revealPassword = ref(false);
  const passwordCopied = ref(false);
  const usernameCopied = ref(false);
  const tasks = ref([]);
  const blocked = ref(false);
  const retrying = ref(false);
  const retryMessage = ref("");
  const keycloakPasswordRotationRequested = ref(false);
  const activeSectionId = ref("vaultwarden");
  const {
    guideShots,
    guidePage,
    lightboxShot,
    guideGroups,
    guideKey,
    guideIndex,
    guideSet,
    guidePrev,
    guideNext,
    guideShot,
    shouldOpenGuide,
    openLightbox,
    closeLightbox,
    loadGuideShots,
  } = useOnboardingGuides({ isStepDone, isStepBlocked });
  const confirmingStepId = ref("");

  const showPasswordCard = computed(() => Boolean(initialPassword.value || initialPasswordRevealedAt.value));
  const passwordRevealLocked = computed(() => Boolean(!initialPassword.value && initialPasswordRevealedAt.value));
  const passwordRevealHint = computed(() =>
    passwordRevealLocked.value
      ? "This password was already revealed and cannot be shown again. Ask an admin to reset it if you missed it."
      : "",
  );
  const vaultwardenRecoveryEmail = computed(() => onboarding.value?.vaultwarden?.recovery_email || "");
  const vaultwardenMatched = computed(() => Boolean(onboarding.value?.vaultwarden?.matched));
  const vaultwardenLoginEmail = computed(() => {
    if (vaultwardenMatched.value) {
      return vaultwardenRecoveryEmail.value || "your recovery email";
    }
    if (requestUsername.value) {
      return `${requestUsername.value}@bstein.dev`;
    }
    return "your @bstein.dev address";
  });
  const vaultwardenLoginEmailLower = computed(() => (vaultwardenLoginEmail.value || "").toLowerCase());
  const mailAddress = computed(() => (requestUsername.value ? `${requestUsername.value}@bstein.dev` : "your @bstein.dev address"));
  const mailAddressLower = computed(() => (mailAddress.value || "").toLowerCase());

  const sections = computed(() =>
    SECTION_DEFS.map((section) => {
      if (section.id !== "vaultwarden") return section;
      const steps = [...section.steps];
      if (vaultwardenMatched.value) {
        steps.splice(1, 0, VAULTWARDEN_TEMP_STEP);
      }
      return { ...section, steps };
    }),
  );
  const {
    activeSection,
    nextSectionItem,
    hasPrevSection,
    hasNextSection,
    selectSection,
    prevSection,
    nextSection,
    stepCardClass,
    sectionProgress,
    sectionStatusLabel,
    sectionPillClass,
    isSectionLocked,
    isSectionDone,
    sectionCardClass,
    sectionGateComplete,
  } = useOnboardingNavigation({ sections, activeSectionId, isStepDone, isStepRequired, isStepBlocked });

  const showOnboarding = computed(() => status.value === "awaiting_onboarding" || status.value === "ready");
  function isStepDone(stepId) {
    const steps = onboarding.value?.completed_steps || [];
    return Array.isArray(steps) ? steps.includes(stepId) : false;
  }

  function isStepRequired(stepId) {
    const required = onboarding.value?.required_steps || [];
    return Array.isArray(required) && required.includes(stepId);
  }

  function isStepBlocked(stepId) {
    const prereqs = STEP_PREREQS[stepId] || [];
    if (!prereqs.length) return false;
    return prereqs.some((req) => !isStepDone(req));
  }

  // WHY: service login rules vary by step; @returns optional helper copy.
  function stepNote(step) {
    if (step.id === "vaultwarden_master_password") {
      return `Vaultwarden uses an email login. Use ${vaultwardenLoginEmailLower.value} to sign in.`;
    }
    if (step.id === "vaultwarden_store_temp_password") {
      return "Store the temporary Keycloak password in Vaultwarden so you can rotate it safely later.";
    }
    if (step.id === "firefly_password_rotated") {
      return `Firefly uses an email login. Use ${mailAddressLower.value} to sign in.`;
    }
    if (step.id === "mail_client_setup") {
      return `Your mailbox address is ${mailAddressLower.value}.`;
    }
    return "";
  }

  // WHY: step state combines completion, prerequisites, and backend automation; @returns pill text.
  function stepPillLabel(step) {
    if (isStepDone(step.id)) return "done";
    if (isStepBlocked(step.id)) return "blocked";
    if (step.action === "auto") return "pending";
    if (!isStepRequired(step.id)) return "optional";
    if (step.id === "keycloak_password_rotated") {
      return keycloakPasswordRotationRequested.value ? "rotate now" : "ready";
    }
    return "pending";
  }

  function stepPillClass(step) {
    if (isStepDone(step.id)) return "pill-ok";
    if (isStepBlocked(step.id)) return "pill-wait";
    if (!isStepRequired(step.id)) return "pill-info";
    if (step.id === "keycloak_password_rotated" && !keycloakPasswordRotationRequested.value) {
      return "pill-info";
    }
    return "pill-warn";
  }

  function isConfirming(step) {
    return confirmingStepId.value === step.id;
  }

  function confirmLabel(step) {
    return isConfirming(step) ? "Confirming..." : "Confirm";
  }

  function selectDefaultSection() {
    const list = sections.value;
    const firstIncomplete = list.find((section) => !isSectionDone(section) && !isSectionLocked(section));
    activeSectionId.value = (firstIncomplete || list[0] || {}).id || "vaultwarden";
  }

  async function check() {
    if (loading.value) return;
    error.value = "";
    loading.value = true;
    try {
      const resp = await fetch("/api/access/request/status", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          request_code: requestCode.value.trim(),
          reveal_initial_password: true,
        }),
      });
      const data = await resp.json().catch(() => ({}));
      if (!resp.ok) throw new Error(data.error || resp.statusText || `status ${resp.status}`);
      status.value = data.status || "unknown";
      requestUsername.value = data.username || "";
      onboarding.value = data.onboarding || { required_steps: [], optional_steps: [], completed_steps: [] };
      keycloakPasswordRotationRequested.value = Boolean(data.onboarding?.keycloak?.password_rotation_requested);
      tasks.value = Array.isArray(data.tasks) ? data.tasks : [];
      blocked.value = Boolean(data.blocked);
      initialPassword.value = data.initial_password || "";
      initialPasswordRevealedAt.value = data.initial_password_revealed_at || "";
      if (showOnboarding.value) {
        selectDefaultSection();
      }
    } catch (err) {
      error.value = err?.message || "Failed to check status";
      tasks.value = [];
      blocked.value = false;
      keycloakPasswordRotationRequested.value = false;
    } finally {
      loading.value = false;
    }
  }

  async function retryProvisioning() {
    if (retrying.value) return;
    retryMessage.value = "";
    const code = requestCode.value.trim();
    if (!code) return;
    retrying.value = true;
    try {
      const retryTasks = tasks.value
        .filter((item) => item.status === "error")
        .map((item) => item.task)
        .filter(Boolean);
      const resp = await fetch("/api/access/request/retry", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        cache: "no-store",
        body: JSON.stringify({ request_code: code, tasks: retryTasks }),
      });
      const data = await resp.json().catch(() => ({}));
      if (!resp.ok) throw new Error(data.error || resp.statusText || `status ${resp.status}`);
      retryMessage.value = "Retry requested. Check again in a moment.";
      await check();
    } catch (err) {
      retryMessage.value = err?.message || "Retry request failed.";
    } finally {
      retrying.value = false;
    }
  }

  function togglePassword() {
    revealPassword.value = !revealPassword.value;
  }

  async function copyText(text, setFlag) {
    if (!text) return;
    try {
      if (navigator?.clipboard?.writeText) {
        await navigator.clipboard.writeText(text);
      } else {
        const fallback = document.createElement("textarea");
        fallback.value = text;
        fallback.setAttribute("readonly", "");
        fallback.style.position = "fixed";
        fallback.style.top = "-9999px";
        fallback.style.left = "-9999px";
        document.body.appendChild(fallback);
        fallback.select();
        fallback.setSelectionRange(0, fallback.value.length);
        document.execCommand("copy");
        document.body.removeChild(fallback);
      }
      setFlag(true);
      setTimeout(() => setFlag(false), 1500);
    } catch (err) {
      error.value = err?.message || "Copy failed";
    }
  }

  function copyInitialPassword() {
    copyText(initialPassword.value, (value) => (passwordCopied.value = value));
  }

  function copyUsername() {
    copyText(requestUsername.value, (value) => (usernameCopied.value = value));
  }

  async function toggleStep(stepId, event) {
    const checked = Boolean(event?.target?.checked);
    await setStepCompletion(stepId, checked);
  }

  async function setStepCompletion(stepId, completed, extra = {}) {
    if (!requestCode.value.trim()) {
      error.value = "Request code is missing.";
      return;
    }
    if (isStepBlocked(stepId)) {
      return;
    }
    loading.value = true;
    error.value = "";
    try {
      const requester = auth.authenticated ? authFetch : fetch;
      let resp = await requester("/api/access/request/onboarding/attest", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request_code: requestCode.value.trim(), step: stepId, completed, ...extra }),
      });
      if ([401, 403].includes(resp.status) && requester === authFetch) {
        resp = await fetch("/api/access/request/onboarding/attest", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ request_code: requestCode.value.trim(), step: stepId, completed, ...extra }),
        });
      }
      const data = await resp.json().catch(() => ({}));
      if (!resp.ok) throw new Error(data.error || resp.statusText || `status ${resp.status}`);
      status.value = data.status || status.value;
      onboarding.value = data.onboarding || onboarding.value;
    } catch (err) {
      error.value = err?.message || "Failed to update onboarding";
    } finally {
      loading.value = false;
    }
  }

  async function confirmStep(step) {
    if (!step || isStepBlocked(step.id) || isStepDone(step.id)) return;
    confirmingStepId.value = step.id;
    try {
      if (step.id === "keycloak_password_rotated") {
        await requestKeycloakPasswordRotation();
        await check();
        return;
      }
      if (step.action === "auto") {
        if (step.id === "firefly_password_rotated") {
          const result = await runRotationCheck("firefly");
          if (result && result.rotated === false) {
            throw new Error("Firefly still uses the initial password. Change it in Firefly, then confirm again.");
          }
        }
        if (step.id === "wger_password_rotated") {
          const result = await runRotationCheck("wger");
          if (result && result.rotated === false) {
            throw new Error("Wger still uses the initial password. Change it in Wger, then confirm again.");
          }
        }
        await check();
        return;
      }
      if (step.action === "confirm") {
        await check();
        if (!isStepDone(step.id)) {
          await setStepCompletion(step.id, true);
        }
        return;
      }
      await setStepCompletion(step.id, true);
    } catch (err) {
      error.value = err?.message || "Failed to confirm step";
    } finally {
      confirmingStepId.value = "";
    }
  }

  async function runRotationCheck(service) {
    if (!auth.authenticated) {
      throw new Error("Log in to update onboarding steps.");
    }
    const endpoint =
      service === "firefly"
        ? "/api/account/firefly/rotation/check"
        : "/api/account/wger/rotation/check";
    const resp = await authFetch(endpoint, { method: "POST" });
    const data = await resp.json().catch(() => ({}));
    if (!resp.ok) {
      throw new Error(data.error || resp.statusText || `status ${resp.status}`);
    }
    return data;
  }

  async function requestKeycloakPasswordRotation() {
    if (!requestCode.value.trim()) {
      error.value = "Request code is missing.";
      return;
    }
    if (isStepBlocked("keycloak_password_rotated")) {
      error.value = "Complete earlier onboarding steps first.";
      return;
    }
    if (keycloakPasswordRotationRequested.value) return;

    loading.value = true;
    error.value = "";
    try {
      const requester = auth.authenticated ? authFetch : fetch;
      let resp = await requester("/api/access/request/onboarding/keycloak-password-rotate", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request_code: requestCode.value.trim() }),
      });
      if ([401, 403].includes(resp.status) && requester === authFetch) {
        resp = await fetch("/api/access/request/onboarding/keycloak-password-rotate", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ request_code: requestCode.value.trim() }),
        });
      }
      const data = await resp.json().catch(() => ({}));
      if (!resp.ok) throw new Error(data.error || resp.statusText || `status ${resp.status}`);
      onboarding.value = data.onboarding || onboarding.value;
      status.value = data.status || status.value;
      keycloakPasswordRotationRequested.value = Boolean(data.onboarding?.keycloak?.password_rotation_requested);
    } catch (err) {
      error.value = err?.message || "Failed to request password rotation";
    } finally {
      loading.value = false;
    }
  }

  onMounted(async () => {
    const code = route.query.code || route.query.request_code || "";
    if (typeof code === "string" && code.trim()) {
      requestCode.value = code.trim();
      await check();
    }
    await loadGuideShots();
  });

  return {
    requestCode,
    requestUsername,
    status,
    loading,
    error,
    onboarding,
    initialPassword,
    initialPasswordRevealedAt,
    revealPassword,
    passwordCopied,
    usernameCopied,
    tasks,
    blocked,
    retrying,
    retryMessage,
    keycloakPasswordRotationRequested,
    activeSectionId,
    guideShots,
    guidePage,
    lightboxShot,
    confirmingStepId,
    showPasswordCard,
    passwordRevealLocked,
    passwordRevealHint,
    vaultwardenRecoveryEmail,
    vaultwardenMatched,
    vaultwardenLoginEmail,
    vaultwardenLoginEmailLower,
    mailAddress,
    mailAddressLower,
    sections,
    activeSection,
    nextSectionItem,
    hasPrevSection,
    hasNextSection,
    showOnboarding,
    selectSection,
    prevSection,
    nextSection,
    statusLabel,
    statusPillClass,
    isStepDone,
    isStepRequired,
    isStepBlocked,
    stepNote,
    stepPillLabel,
    stepPillClass,
    isConfirming,
    confirmLabel,
    stepCardClass,
    sectionProgress,
    sectionStatusLabel,
    sectionPillClass,
    isSectionLocked,
    isSectionDone,
    sectionCardClass,
    sectionGateComplete,
    guideGroups,
    guideKey,
    guideIndex,
    guideSet,
    guidePrev,
    guideNext,
    guideShot,
    shouldOpenGuide,
    openLightbox,
    closeLightbox,
    taskPillClass,
    selectDefaultSection,
    check,
    retryProvisioning,
    togglePassword,
    copyText,
    copyInitialPassword,
    copyUsername,
    toggleStep,
    setStepCompletion,
    confirmStep,
    runRotationCheck,
    requestKeycloakPasswordRotation,
    loadGuideShots,
  };
}
