import { Block } from '../types';

import { getNumberInRange } from '@/modules/@common/helpers/number';

export const PAD = (n: number, len: number) => n.toString().padStart(len, '0');

export const safetyParseValue = (value: number | string) => {
  const num = typeof value === 'number' ? value : parseInt(value, 10);

  return Number.isFinite(num) ? num : 0;
};

export const buildBlocks = (opts: { hh: boolean; ms: boolean }): Block[] => {
  let pos = 0;

  const blocks: Array<Omit<Block, 'start' | 'end'> | undefined> = [
    opts.hh ? { key: 'H', len: 2, min: 0, max: 99 } : undefined,
    { key: 'm', len: 2, min: 0, max: 59 },
    { key: 's', len: 2, min: 0, max: 59 },
    opts.ms ? { key: 'M', len: 3, min: 0, max: 999 } : undefined,
  ];

  return blocks
    .filter((block) => block !== undefined)
    .map((block) => {
      const start = pos;
      const end = start + block.len;
      pos = end + 1;

      return { ...block, start, end };
    });
};

export const joinMs = (h: number, m: number, s: number, ms: number) => h * 3_600_000 + m * 60_000 + s * 1_000 + ms;

export const formatFromMs = (msRaw: number, blocks: Block[]) => {
  const ms = !Number.isFinite(msRaw) || msRaw < 0 ? 0 : msRaw;

  const hours = Math.floor(ms / 3_600_000);
  const minutes = getNumberInRange(Math.floor((ms % 3_600_000) / 60_000), 0, 59);
  const seconds = getNumberInRange(Math.floor((ms % 60_000) / 1_000), 0, 59);
  const millis = getNumberInRange(Math.floor(ms % 1_000), 0, 999);

  const parts: string[] = [];

  // eslint-disable-next-line no-restricted-syntax
  for (const b of blocks) {
    if (b.key === 'H') {
      parts.push(PAD(getNumberInRange(hours, b.min, b.max), b.len));
    }

    if (b.key === 'm') {
      parts.push(PAD(minutes, b.len));
    }

    if (b.key === 's') {
      parts.push(PAD(seconds, b.len));
    }

    if (b.key === 'M') {
      parts.push(PAD(millis, b.len));
    }
  }

  return parts.join(':');
};

export const parseBlock = (str: string, start: number, end: number) => parseInt(str.slice(start, end), 10) || 0;
export const putBlock = (str: string, start: number, end: number, nextDigits: string) =>
  str.slice(0, start) + nextDigits + str.slice(end);

export const getBlockIndexFromPos = (pos: number, sepEnds: number[]): number => {
  for (let i = 0; i < sepEnds.length; i++) {
    if (pos <= sepEnds[i]) {
      return i;
    }
  }

  return sepEnds.length - 1;
};

export const parseTemplateOrMs = (input: string, blocks: Block[]): number | null => {
  const re = new RegExp(`^${blocks.map((b) => `(\\d{${b.len}})`).join(':')}$`);
  const m = input.match(re);

  if (m) {
    let h = 0;
    let mm = 0;
    let ss = 0;
    let mss = 0;
    let gi = 1;

    // eslint-disable-next-line no-restricted-syntax
    for (const b of blocks) {
      const val = parseInt(m[(gi += 1)] ?? '0', 10) || 0;
      if (b.key === 'H') h = val;
      else if (b.key === 'm') {
        mm = val;
      } else if (b.key === 's') {
        ss = val;
      } else if (b.key === 'M') {
        mss = val;
      }
    }

    return joinMs(h, mm, ss, mss);
  }

  const asNum = parseInt(input, 10);

  return Number.isFinite(asNum) ? asNum : null;
};
