import { createAssetView, resolveDocumentAssetUrl } from '../asset_manager';
import type {
  DocumentLike as AssetManagerDocumentLike,
  DocumentVersionLike,
  AssetLike as AssetManagerAssetLike,
  GetAsset as AssetManagerGetAsset,
} from '../asset_manager';

const BASE_FETCH_OPTIONS = { start: 1, limit: 1 } as const;

interface DocumentVersion extends DocumentVersionLike {
  download_path?: string | null;
}

export interface DocumentLike extends AssetManagerDocumentLike {
  current_version?: DocumentVersion | null;
}

export type AssetLike = AssetManagerAssetLike;

export type EnsurePreviewData = (id: string | number) => Promise<DocumentLike | null | undefined>;
export type EnsureAssetUrl = (
  id: string | number,
  asset: AssetLike,
  options?: { start?: number; limit?: number; force?: boolean },
) => Promise<AssetLike | null | undefined>;
export type GetDocumentAsset = AssetManagerGetAsset;

interface ResolveOcrTextUrlOptions {
  document: DocumentLike | null;
  ensurePreviewData?: EnsurePreviewData;
  getDocumentAsset?: GetDocumentAsset;
  ensureAssetUrl?: EnsureAssetUrl;
}

const pickAsset = (doc: DocumentLike | null | undefined, getDocumentAsset?: GetDocumentAsset): AssetLike | null => {
  if (!doc || !getDocumentAsset) {
    return null;
  }
  return getDocumentAsset(doc, 'ocr-text') || null;
};

export async function resolveOcrTextUrl({
  document,
  ensurePreviewData,
  getDocumentAsset,
  ensureAssetUrl,
}: ResolveOcrTextUrlOptions): Promise<string | null> {
  if (!document?.id) {
    return null;
  }

  let docRef = document;
  let asset = pickAsset(docRef, getDocumentAsset);

  if (!asset && ensurePreviewData) {
    const refreshed = await ensurePreviewData(docRef.id);
    if (refreshed) {
      docRef = refreshed;
    }
    asset = pickAsset(docRef, getDocumentAsset);
  }

  if (!asset) {
    return null;
  }

  const baseView = createAssetView(asset);
  const hasUrl = Boolean(baseView.getPrimaryUrl());

  let entry: AssetLike = asset;
  if (ensureAssetUrl) {
    const ensureOptions = { ...BASE_FETCH_OPTIONS, force: !hasUrl };
    const ensured = await ensureAssetUrl(docRef.id!, asset, ensureOptions);
    if (ensured) {
      entry = ensured;
    }
  }

  const ensuredView = createAssetView(entry);
  const directUrl = ensuredView.getPrimaryUrl();
  if (directUrl) {
    return directUrl;
  }

  return (
    resolveDocumentAssetUrl(docRef, 'ocr-text', {
      ensureAssetUrl,
      getAsset: getDocumentAsset,
      ensureOptions: { ...BASE_FETCH_OPTIONS, force: true },
      objectOrdinal: 1,
    }) || null
  );
}

export async function openOcrTextInNewTab(options: ResolveOcrTextUrlOptions): Promise<boolean> {
  const popup = window.open('', '_blank');
  const popupAvailable = Boolean(popup);

  if (popupAvailable) {
    try {
      popup.opener = null;
    } catch {
      /* ignore */
    }
  }

  try {
    const url = await resolveOcrTextUrl(options);
    if (!url) {
      if (popupAvailable) {
        popup.close();
      }
      return false;
    }

    if (popupAvailable) {
      try {
        popup.location.replace(url);
      } catch {
        try {
          popup.location.href = url;
        } catch (secondError) {
          popup.close();
          throw secondError;
        }
      }
    } else {
      const finalWindow = window.open(url, '_blank');
      if (finalWindow) {
        try {
          finalWindow.opener = null;
        } catch {
          /* ignore */
        }
      }
    }

    return true;
  } catch (error) {
    if (popupAvailable) {
      popup.close();
    }
    throw error;
  }
}
