/**
 * KRA - Format Utility Functions
 */
import { formatDate as formatDateUtil } from './date';

/**
 * Format boolean to Chinese string
 * @param bool - Boolean value
 * @returns '是' or '否' or ''
 */
export const formatBoolean = (bool: boolean | null | undefined): string => {
  if (bool !== null && bool !== undefined) {
    return bool ? '是' : '否';
  }
  return '';
};

/**
 * Format date to string
 * @param time - Date value
 * @returns Formatted date string
 */
export const formatDate = (time: Date | string | number | null | undefined): string => {
  if (time !== null && time !== undefined && time !== '') {
    return formatDateUtil(time, 'YYYY-MM-DD HH:mm:ss');
  }
  return '';
};

/**
 * Filter dictionary value to label
 * @param value - Value to find
 * @param options - Dictionary options
 * @returns Label string or undefined
 */
export const filterDict = (
  value: any,
  options: Array<{ value: any; label: string; children?: any[] }>
): string | undefined => {
  const findInOptions = (opts: any[], targetValue: any): any => {
    if (!opts || !Array.isArray(opts)) return null;
    for (const item of opts) {
      if (item.value === targetValue) {
        return item;
      }
      if (item.children && Array.isArray(item.children)) {
        const found = findInOptions(item.children, targetValue);
        if (found) return found;
      }
    }
    return null;
  };
  const rowLabel = findInOptions(options, value);
  return rowLabel?.label;
};

/**
 * Filter data source value to label
 * @param dataSource - Data source array
 * @param value - Value or array of values
 * @returns Label or array of labels
 */
export const filterDataSource = (
  dataSource: Array<{ value: any; label: string; children?: any[] }>,
  value: any | any[]
): string | string[] | undefined => {
  const findInDataSource = (data: any[], targetValue: any): any => {
    if (!data || !Array.isArray(data)) return null;
    for (const item of data) {
      if (item.value === targetValue) {
        return item;
      }
      if (item.children && Array.isArray(item.children)) {
        const found = findInDataSource(item.children, targetValue);
        if (found) return found;
      }
    }
    return null;
  };

  if (Array.isArray(value)) {
    return value.map((item) => {
      const rowLabel = findInDataSource(dataSource, item);
      return rowLabel?.label;
    });
  }
  const rowLabel = findInDataSource(dataSource, value);
  return rowLabel?.label;
};

/**
 * Get base URL from environment
 * @returns Base URL string
 */
export const getBaseUrl = (): string => {
  const baseUrl = process.env.REACT_APP_API_URL || '/api';
  return baseUrl === '/' ? '' : baseUrl;
};

/**
 * Return array of image URLs with base path
 * @param arr - Image path or array of paths
 * @returns Array of full image URLs
 */
export const returnArrImg = (arr: string | string[]): string[] => {
  const baseUrl = getBaseUrl();
  const imgArr: string[] = [];

  if (Array.isArray(arr)) {
    for (const item of arr) {
      if (item?.slice(0, 4) !== 'http') {
        imgArr.push(baseUrl + item);
      } else {
        imgArr.push(item);
      }
    }
  } else {
    if (arr?.slice(0, 4) !== 'http') {
      imgArr.push(baseUrl + arr);
    } else {
      imgArr.push(arr);
    }
  }
  return imgArr;
};

export const ReturnArrImg = returnArrImg;

/**
 * Download file by opening URL
 * @param url - File URL
 */
export const onDownloadFile = (url: string): void => {
  const baseUrl = getBaseUrl();
  window.open(baseUrl + url);
};

/**
 * Convert hex color to RGB array
 */
const colorToHex = (color: string): number[] => {
  const matches = color.replace('#', '').match(/../g);
  if (!matches) return [0, 0, 0];
  return matches.map((hex) => parseInt(hex, 16));
};

/**
 * Convert RGB values to hex color
 */
const hexToColor = (r: number, g: number, b: number): string => {
  const hex = [r.toString(16), g.toString(16), b.toString(16)];
  for (let i = 0; i < 3; i++) {
    if (hex[i].length === 1) hex[i] = `0${hex[i]}`;
  }
  return `#${hex.join('')}`;
};

/**
 * Generate darker color
 */
const generateAllColors = (color: string, ratio: number): string => {
  const rgb = colorToHex(color);
  const target = [10, 10, 30];
  for (let i = 0; i < 3; i++) {
    rgb[i] = Math.floor(rgb[i] * (1 - ratio) + target[i] * ratio);
  }
  return hexToColor(rgb[0], rgb[1], rgb[2]);
};

/**
 * Generate lighter color
 */
const generateAllLightColors = (color: string, ratio: number): string => {
  const rgb = colorToHex(color);
  const target = [240, 248, 255]; // Light blue white
  for (let i = 0; i < 3; i++) {
    rgb[i] = Math.floor(rgb[i] * (1 - ratio) + target[i] * ratio);
  }
  return hexToColor(rgb[0], rgb[1], rgb[2]);
};

/**
 * Add opacity to color
 */
const addOpacityToColor = (color: string, opacity: number): string => {
  const rgb = colorToHex(color);
  return `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`;
};

/**
 * Set primary color CSS variables
 * @param primaryColor - Primary color hex
 * @param darkMode - 'light' or 'dark'
 */
export const setBodyPrimaryColor = (primaryColor: string, darkMode: 'light' | 'dark'): void => {
  const fmtColorFunc = darkMode === 'light' ? generateAllLightColors : generateAllColors;

  document.documentElement.style.setProperty('--primary-color', primaryColor);
  document.documentElement.style.setProperty(
    '--primary-color-bg',
    addOpacityToColor(primaryColor, 0.4)
  );

  for (let times = 1; times <= 2; times++) {
    document.documentElement.style.setProperty(
      `--primary-color-dark-${times}`,
      fmtColorFunc(primaryColor, times / 10)
    );
  }

  for (let times = 1; times <= 10; times++) {
    document.documentElement.style.setProperty(
      `--primary-color-light-${times}`,
      fmtColorFunc(primaryColor, times / 10)
    );
  }

  document.documentElement.style.setProperty(
    '--menu-hover-bg-color',
    addOpacityToColor(primaryColor, 0.2)
  );
};

/**
 * Create UUID
 * @returns UUID string
 */
export const createUUID = (): string => {
  let d = new Date().getTime();
  if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
    d += performance.now();
  }
  return '00000000-0000-0000-0000-000000000000'.replace(/0/g, () => {
    const r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return r.toString(16);
  });
};

export const CreateUUID = createUUID;

/**
 * Format file size to human readable string
 * @param bytes - File size in bytes
 * @returns Formatted string (e.g., "1.5 MB")
 */
export const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};

/**
 * Format number with thousand separators
 * @param num - Number to format
 * @returns Formatted string
 */
export const formatNumber = (num: number): string => {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

export default {
  formatBoolean,
  formatDate,
  filterDict,
  filterDataSource,
  getBaseUrl,
  returnArrImg,
  onDownloadFile,
  setBodyPrimaryColor,
  createUUID,
  formatFileSize,
  formatNumber,
};
