function isStandaloneDisplayMode() {
  if (typeof window === 'undefined') {
    return false;
  }

  return (
    window.matchMedia?.('(display-mode: standalone)').matches === true ||
    (window.navigator as Navigator & { standalone?: boolean }).standalone === true
  );
}

function isMobileLikeViewport() {
  if (typeof window === 'undefined') {
    return false;
  }

  return (
    window.matchMedia?.('(max-width: 1180px)').matches === true ||
    window.matchMedia?.('(pointer: coarse)').matches === true
  );
}

export function shouldOpenDownloadInNewWindow() {
  return isStandaloneDisplayMode() && isMobileLikeViewport();
}

function decodeDownloadFileName(value: string) {
  const normalized = String(value ?? '').trim();

  if (!normalized) {
    return '';
  }

  try {
    return decodeURIComponent(normalized);
  } catch {
    return normalized;
  }
}

function resolveFileNameFromUrl(url: string) {
  try {
    const parsed = new URL(url, typeof window !== 'undefined' ? window.location.href : 'https://local.invalid');
    return decodeDownloadFileName(parsed.pathname.split('/').filter(Boolean).at(-1) ?? '');
  } catch {
    return '';
  }
}

function parseContentDispositionFileName(headerValue: string | null) {
  const normalized = String(headerValue ?? '').trim();

  if (!normalized) {
    return '';
  }

  const utf8Match = normalized.match(/filename\*=UTF-8''([^;]+)/i);

  if (utf8Match?.[1]) {
    return decodeDownloadFileName(utf8Match[1]);
  }

  const quotedMatch = normalized.match(/filename="([^"]+)"/i);

  if (quotedMatch?.[1]) {
    return decodeDownloadFileName(quotedMatch[1]);
  }

  const plainMatch = normalized.match(/filename=([^;]+)/i);
  return plainMatch?.[1] ? decodeDownloadFileName(plainMatch[1].replace(/^["']|["']$/g, '')) : '';
}

function isHtmlFileName(fileName: string) {
  return /\.html?$/i.test(fileName.trim());
}

function downloadBlob(blob: Blob, fileName: string) {
  if (typeof document === 'undefined') {
    throw new Error('download-unavailable');
  }

  const objectUrl = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = objectUrl;
  link.download = fileName;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  window.setTimeout(() => {
    URL.revokeObjectURL(objectUrl);
  }, 0);
}

function triggerAnchorDownload(url: string, fileName?: string) {
  if (typeof document === 'undefined') {
    throw new Error('download-unavailable');
  }

  const link = document.createElement('a');
  link.href = url;

  if (shouldOpenDownloadInNewWindow()) {
    link.target = '_blank';
    link.rel = 'noreferrer';
  } else if (typeof fileName === 'string' && fileName.trim()) {
    link.download = fileName.trim();
  } else {
    link.download = '';
  }

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

function buildDownloadErrorMessage(response: Response) {
  if (response.status === 401) {
    return '인증이 없어 파일을 내려받지 못했습니다.';
  }

  if (response.status === 403) {
    return '권한이 없어 파일을 내려받지 못했습니다.';
  }

  if (response.status === 404) {
    return '파일을 찾지 못했습니다.';
  }

  return `다운로드에 실패했습니다. (${response.status})`;
}

export async function triggerResourceDownload(url: string, fileName?: string) {
  if (typeof window === 'undefined' || typeof document === 'undefined') {
    throw new Error('download-unavailable');
  }

  const parsedUrl = new URL(url, window.location.href);
  const preferredFileName = fileName?.trim() || resolveFileNameFromUrl(parsedUrl.toString()) || 'resource';

  if (parsedUrl.origin !== window.location.origin) {
    triggerAnchorDownload(parsedUrl.toString(), preferredFileName);
    return;
  }

  const response = await fetch(parsedUrl.toString(), {
    credentials: 'include',
  });

  if (!response.ok) {
    throw new Error(buildDownloadErrorMessage(response));
  }

  const contentType = response.headers.get('content-type')?.toLowerCase() ?? '';
  const contentDisposition = response.headers.get('content-disposition');
  const responseFileName = parseContentDispositionFileName(contentDisposition);
  const resolvedFileName = responseFileName || preferredFileName;
  const blob = await response.blob();

  if (contentType.includes('text/html') && !isHtmlFileName(resolvedFileName)) {
    const htmlPreview = (await blob.text()).trimStart().toLowerCase();

    if (htmlPreview.startsWith('<!doctype html') || htmlPreview.startsWith('<html') || htmlPreview.includes('<head')) {
      throw new Error('실제 파일 대신 앱 HTML이 반환되어 다운로드를 중단했습니다.');
    }
  }

  downloadBlob(blob, resolvedFileName);
}
