import Path from 'node:path'

/**
 * Parse output from the `synctex view` command
 */
function parseViewOutput(output) {
  return _parseOutput(output, (record, label, value) => {
    switch (label) {
      case 'Page':
        _setIntProp(record, 'page', value)
        break
      case 'h':
        _setFloatProp(record, 'h', value)
        break
      case 'v':
        _setFloatProp(record, 'v', value)
        break
      case 'W':
        _setFloatProp(record, 'width', value)
        break
      case 'H':
        _setFloatProp(record, 'height', value)
        break
    }
  })
}

/**
 * Parse output from the `synctex edit` command
 */
function parseEditOutput(output, baseDir) {
  return _parseOutput(output, (record, label, value) => {
    switch (label) {
      case 'Input':
        if (Path.isAbsolute(value)) {
          record.file = Path.relative(baseDir, value)
        } else {
          record.file = value
        }
        break
      case 'Line':
        _setIntProp(record, 'line', value)
        break
      case 'Column':
        _setIntProp(record, 'column', value)
        break
    }
  })
}

/**
 * Generic parser for synctex output
 *
 * Parses the output into records. Each line is split into a label and a value,
 * which are then sent to `processLine` for further processing.
 */
function _parseOutput(output, processLine) {
  const lines = output.split('\n')
  let currentRecord = null
  const records = []
  for (const line of lines) {
    const [label, value] = _splitLine(line)

    // A line that starts with 'Output:' indicates a new record
    if (label === 'Output') {
      // Start new record
      currentRecord = {}
      records.push(currentRecord)
      continue
    }

    // Ignore the line if we're not in a record yet
    if (currentRecord == null) {
      continue
    }

    // Process the line
    processLine(currentRecord, label, value)
  }
  return records
}

/**
 * Split a line in label and value components.
 *
 * The components are separated by a colon. Note that this is slightly
 * different from `line.split(':', 2)`. This version puts the entirety of the
 * line after the colon in the value component, even if there are more colons
 * on the line.
 */
function _splitLine(line) {
  const splitIndex = line.indexOf(':')
  if (splitIndex === -1) {
    return ['', line]
  }
  return [line.slice(0, splitIndex).trim(), line.slice(splitIndex + 1).trim()]
}

function _setIntProp(record, prop, value) {
  const intValue = parseInt(value, 10)
  if (!isNaN(intValue)) {
    record[prop] = intValue
  }
}

function _setFloatProp(record, prop, value) {
  const floatValue = parseFloat(value)
  if (!isNaN(floatValue)) {
    record[prop] = floatValue
  }
}

export default { parseViewOutput, parseEditOutput }
