import logoStr from '../style/icons/box.svg';
import autoReloadStr from '../style/icons/autoreload.svg';
import linkStr from '../style/icons/externallink.svg';
import dashStr from '../style/icons/Plotly-Logo-Black.svg';
import streamlitStr from '../style/icons/streamlit-logo-primary.svg';
import shinyStr from '../style/icons/shiny-for-python.svg';
import panelStr from '../style/icons/panel_logo_stacked.svg';
import { LabIcon } from '@jupyterlab/ui-components';
import { Contents } from '@jupyterlab/services';
import { PathExt } from '@jupyterlab/coreutils';

export const IS_LITE = !!document.getElementById('jupyter-lite-main');

export const logoIcon = new LabIcon({
  name: 'jupyterpack:logo',
  svgstr: logoStr
});

export const autoReloadIcon = new LabIcon({
  name: 'jupyterpack:autoReload',
  svgstr: autoReloadStr
});

export const linkIcon = new LabIcon({
  name: 'jupyterpack:externalLink',
  svgstr: linkStr
});

export const dashIcon = new LabIcon({
  name: 'jupyterpack:dashBlack',
  svgstr: dashStr
});

export const streamlitIcon = new LabIcon({
  name: 'jupyterpack:streamlitBlack',
  svgstr: streamlitStr
});

export const shinyIcon = new LabIcon({
  name: 'jupyterpack:shinyLogo',
  svgstr: shinyStr
});
export const panelIcon = new LabIcon({
  name: 'jupyterpack:panelLogo',
  svgstr: panelStr
});

export function removePrefix(path: string, prefix: string): string {
  if (path.startsWith(prefix)) {
    return path.slice(prefix.length);
  }
  // If the prefix doesn't match, return the original path
  return path;
}

export function arrayBufferToBase64(buffer: ArrayBuffer) {
  let binary = '';
  const bytes = new Uint8Array(buffer);
  const chunkSize = 32768; // process in chunks for large buffers
  for (let i = 0; i < bytes.length; i += chunkSize) {
    const chunk = bytes.subarray(i, i + chunkSize);
    binary += String.fromCharCode(...chunk);
  }
  return btoa(binary);
}

export function base64ToArrayBuffer(base64: string): Uint8Array {
  const binaryString = atob(base64);
  const bytes = new Uint8Array(binaryString.length);
  for (let i = 0; i < binaryString.length; i++) {
    bytes[i] = binaryString.charCodeAt(i);
  }
  return bytes;
}

export function base64ToString(base64: string): string {
  const bytes = base64ToArrayBuffer(base64);
  return new TextDecoder('utf-8').decode(bytes);
}

export function stringToBase64(str: string): string {
  const bytes = new TextEncoder().encode(str);
  let binary = '';
  for (let i = 0; i < bytes.length; i++) {
    binary += String.fromCharCode(bytes[i]);
  }
  return window.btoa(binary);
}

export function stringOrNone(content?: string) {
  return content ? `"${content}"` : 'None';
}

export function isBinaryContentType(contentType?: string) {
  if (!contentType) {
    // no Content-Type → assume binary for safety
    return true;
  }

  contentType = contentType.toLowerCase().trim();

  const textTypes = [
    'text/',
    'application/json',
    'application/javascript',
    'application/xml',
    'application/xhtml+xml',
    'application/x-www-form-urlencoded',
    'application/sql',
    'application/graphql',
    'application/yaml'
  ];

  const binaryIndicators = [
    'image/',
    'audio/',
    'video/',
    'font/',
    'application/octet-stream',
    'application/pdf',
    'application/zip',
    'application/x-protobuf',
    'application/vnd'
  ];

  // Starts with text/ or one of the textual types
  if (textTypes.some(t => contentType.startsWith(t))) {
    return false;
  }

  // Starts with binary-indicating prefix
  if (binaryIndicators.some(t => contentType.startsWith(t))) {
    return true;
  }

  // If charset is specified → text
  if (contentType.includes('charset=')) {
    return false;
  }

  // Default: assume binary
  return true;
}

export async function newDirectory(options: {
  dirName: string;
  contentsManager: Contents.IManager;
  cwd: string;
}): Promise<string> {
  const { dirName, contentsManager, cwd } = options;
  const currentDirContent = await contentsManager.get(cwd, {
    content: true
  });
  const allDir = ((currentDirContent.content ?? []) as Contents.IModel[]).map(
    c => c.name
  );

  let createdDir = dirName;
  if (allDir.includes(createdDir)) {
    let idx = 1;
    createdDir = `${dirName} (${idx})`;
    while (allDir.includes(createdDir)) {
      idx += 1;
      createdDir = `${dirName} (${idx})`;
    }
  }
  const res = await contentsManager.newUntitled({
    path: cwd,
    type: 'directory'
  });

  const renameRes = await contentsManager.rename(
    res.path,
    PathExt.join(cwd, createdDir)
  );
  return renameRes.path;
}
