type HostedRuntimeUnavailableReason = 'missing' | 'not-live' | 'unauthorized';

export interface IHostedRuntimeRecoveryInput {
  readonly runtimeRoot?: string | null;
  readonly authorityRoot?: string | null;
  readonly requestedRoot?: string | null;
  readonly unavailableReason?: string | null;
  readonly currentHref?: string | null;
}

export interface IHostedRuntimeRecoveryAction {
  readonly key: 'retry' | 'auto' | 'shell';
  readonly label: string;
  readonly href: string;
  readonly title: string;
}

export interface IHostedRuntimeRecoveryPlan {
  readonly requestedRoot: string;
  readonly runtimeRoot: string;
  readonly authorityRoot: string;
  readonly unavailableReason: HostedRuntimeUnavailableReason;
  readonly summary: string;
  readonly actions: IHostedRuntimeRecoveryAction[];
}

function normalize(value: string | null | undefined): string {
  return typeof value === 'string' ? value.trim() : '';
}

function serializeRelativeUrl(url: URL): string {
  return `${url.pathname}${url.search}${url.hash}`;
}

function resolveCurrentHref(currentHref?: string | null): string | null {
  const direct = normalize(currentHref);
  if (direct) {
    return direct;
  }
  if (typeof window !== 'undefined' && typeof window.location?.href === 'string') {
    return window.location.href;
  }
  return null;
}

function buildSummary(
  requestedRoot: string,
  runtimeRoot: string,
  authorityRoot: string,
  unavailableReason: HostedRuntimeUnavailableReason,
): string {
  if (unavailableReason === 'unauthorized') {
    const authorityLabel = authorityRoot || 'the signed-in authority';
    return `Requested target ${requestedRoot} is not authorized for ${authorityLabel}.`;
  }
  const reasonText = unavailableReason === 'not-live'
    ? 'is registered but currently offline'
    : 'is no longer registered';
  if (requestedRoot === runtimeRoot) {
    return `Requested runtime ${requestedRoot} ${reasonText}.`;
  }
  if (!runtimeRoot) {
    const authorityLabel = authorityRoot || 'the selected authority';
    return `Requested runtime ${requestedRoot} ${reasonText}; no live runtime is currently attached for ${authorityLabel}.`;
  }
  return `Requested runtime ${requestedRoot} ${reasonText}; clear the selected target before using ${runtimeRoot}.`;
}

export function resolveHostedRuntimeRecoveryPlan(
  input: IHostedRuntimeRecoveryInput,
): IHostedRuntimeRecoveryPlan | null {
  const requestedRoot = normalize(input.requestedRoot);
  const runtimeRoot = normalize(input.runtimeRoot);
  const authorityRoot = normalize(input.authorityRoot);
  const unavailableReasonRaw = normalize(input.unavailableReason);
  const unavailableReason = unavailableReasonRaw === 'missing'
    || unavailableReasonRaw === 'not-live'
    || unavailableReasonRaw === 'unauthorized'
    ? unavailableReasonRaw
    : null;
  if (!requestedRoot || !unavailableReason) {
    return null;
  }

  const summary = buildSummary(requestedRoot, runtimeRoot, authorityRoot, unavailableReason);
  const actions: IHostedRuntimeRecoveryAction[] = [];
  const href = resolveCurrentHref(input.currentHref);

  if (href) {
    try {
      const currentUrl = new URL(href, 'https://matrix.invalid');
      const hasExplicitTarget = currentUrl.searchParams.has('daemonRoot') || currentUrl.searchParams.has('daemonRealm');
      const relativeCurrentHref = serializeRelativeUrl(currentUrl);
      actions.push({
        key: 'retry',
        label: 'Retry',
        href: relativeCurrentHref,
        title: 'Retry the current hosted app target.',
      });
      if (hasExplicitTarget) {
        const autoUrl = new URL(currentUrl.toString());
        autoUrl.searchParams.delete('daemonRoot');
        autoUrl.searchParams.delete('daemonRealm');
        actions.push({
          key: 'auto',
          label: 'Use Auto',
          href: serializeRelativeUrl(autoUrl),
          title: 'Clear the explicit runtime target and let the shell pick the current live target.',
        });
      }
      actions.push({
        key: 'shell',
        label: 'Open Shell',
        href: `/apps/web/#dashboard?redirect=${encodeURIComponent(relativeCurrentHref)}`,
        title: 'Open the Matrix shell and return to this app after choosing a target.',
      });
      return {
        requestedRoot,
        runtimeRoot,
        authorityRoot,
        unavailableReason,
        summary,
        actions,
      };
    } catch {
      // Ignore malformed URLs and show shell-only recovery.
    }
  }

  actions.push({
    key: 'shell',
    label: 'Open Shell',
    href: '/apps/web/#dashboard',
    title: 'Open the Matrix shell to inspect or switch attached runtimes.',
  });

  return {
    requestedRoot,
    runtimeRoot,
    authorityRoot,
    unavailableReason,
    summary,
    actions,
  };
}
