import { ADMIN_BASE_PATH, ADMIN_DEFAULT_AFTER_LOGIN_PATH, ADMIN_LOGIN_PATH, ADMIN_LOGIN_START_PATH } from '../constants';

function ensureLeadingSlash(target: string): string {
  if (!target) {
    return '/';
  }

  if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(target)) {
    return target;
  }

  return target.startsWith('/') ? target : `/${target}`;
}

export function isPermittedReturnTarget(target: string): boolean {
  if (!target) {
    return false;
  }

  const sanitized = ensureLeadingSlash(target);

  if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(sanitized)) {
    try {
      const url = new URL(sanitized);
      return url.pathname.startsWith(ADMIN_BASE_PATH);
    } catch (error) {
      if (import.meta.env.DEV) {
        console.warn('[Auth] Failed to parse return target URL', error);
      }

      return false;
    }
  }

  return sanitized.startsWith(ADMIN_BASE_PATH);
}

function base64UrlEncode(value: string): string {
  const encoder = new TextEncoder();
  const bytes = encoder.encode(value);

  let binary = '';
  bytes.forEach((byte) => {
    binary += String.fromCharCode(byte);
  });

  return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/u, '');
}

function base64UrlDecode(value: string): string | null {
  try {
    const padded = value.padEnd(value.length + ((4 - (value.length % 4)) % 4), '=');
    const normalized = padded.replace(/-/g, '+').replace(/_/g, '/');
    const binary = atob(normalized);
    const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
    const decoder = new TextDecoder();

    return decoder.decode(bytes);
  } catch (error) {
    console.warn('[Auth] Failed to decode return_to parameter', error);
    return null;
  }
}

export function encodeReturnTo(value: string): string {
  const trimmed = value.trim();
  if (trimmed === '') {
    return '';
  }

  return base64UrlEncode(trimmed);
}

export function decodeReturnTo(value: string | null): string | null {
  if (!value) {
    return null;
  }

  return base64UrlDecode(value);
}

export interface ReturnTargetResolution {
  finalTarget: string;
  encodedFinal: string;
}

export function resolveReturnTarget(raw: string | null, fallback: string): ReturnTargetResolution {
  const normalizedFallback = ensureLeadingSlash(fallback);
  const fallbackIsAllowed = isPermittedReturnTarget(normalizedFallback)
    ? normalizedFallback
    : ADMIN_DEFAULT_AFTER_LOGIN_PATH;

  if (!raw) {
    const encoded = encodeReturnTo(fallbackIsAllowed);
    return { finalTarget: fallbackIsAllowed, encodedFinal: encoded };
  }

  const decodedPrimary = decodeReturnTo(raw);
  if (!decodedPrimary) {
    const encoded = encodeReturnTo(fallbackIsAllowed);
    return { finalTarget: fallbackIsAllowed, encodedFinal: encoded };
  }

  const normalizedPrimary = decodedPrimary.trim();

  const wrapperPaths = [ADMIN_LOGIN_START_PATH, ADMIN_LOGIN_PATH];
  for (const wrapper of wrapperPaths) {
    if (normalizedPrimary.startsWith(wrapper)) {
      try {
        const url = new URL(normalizedPrimary, window.location.origin);
        const innerRaw = url.searchParams.get('return_to');
        if (!innerRaw) {
          const encoded = encodeReturnTo(fallbackIsAllowed);
          return { finalTarget: fallbackIsAllowed, encodedFinal: encoded };
        }

        return resolveReturnTarget(innerRaw, fallbackIsAllowed);
      } catch (error) {
        console.warn('[Auth] Failed to parse return_to chain', error);
        const encoded = encodeReturnTo(fallbackIsAllowed);
        return { finalTarget: fallbackIsAllowed, encodedFinal: encoded };
      }
    }
  }

  const finalTarget = ensureLeadingSlash(normalizedPrimary);
  if (!isPermittedReturnTarget(finalTarget)) {
    const encoded = encodeReturnTo(fallbackIsAllowed);
    return { finalTarget: fallbackIsAllowed, encodedFinal: encoded };
  }

  const encodedFinal = encodeReturnTo(finalTarget);

  return { finalTarget, encodedFinal };
}
