// @ts-check
const { log } = require('cozy-konnector-libs')
const moment = require('moment')
const Sentry = require('@sentry/node')

/**
 * Return User PDL
 * @param {string} result
 * @returns {string}
 */
function parseUserPdl(result) {
  log('info', 'Parsing User Pdl')
  const json = JSON.stringify(result)
  return JSON.parse(json)['Envelope']['Body']['rechercherPointResponse'][
    'points'
  ]['point']['$'].id
}

/**
 * Return User address
 * @param {string} result
 * @returns {Address}
 */
function parseUserAddress(result) {
  log('info', 'Parsing user Address')
  const json = JSON.stringify(result)
  return JSON.parse(json)['Envelope']['Body'][
    'consulterDonneesTechniquesContractuellesResponse'
  ]['point']['donneesGenerales']['adresseInstallation']
}

/**
 * Return User off-peak hours
 * @param {string} result
 * @returns {string}
 * @example "3H00-8H00;13H30-16H30"
 */
function parseUserOffPeakHours(result) {
  log('info', 'Parsing user off-peak hours')
  const json = JSON.stringify(result)
  const rawOffPeakHours =
    JSON.parse(json)['Envelope']['Body'][
      'consulterDonneesTechniquesContractuellesResponse'
    ]['point']['situationComptage']['dispositifComptage']['relais'][
      'plageHeuresCreuses'
    ]
  // extract off-peak hours from parentheses
  let match = rawOffPeakHours.match(/\((.*?)\)/)
  // Check if there is a match and return the content
  if (match) {
    return match[1]
  } else {
    throw new Error('invalid off-peak hours format')
  }
}

/**
 * Return User contract start date
 * @param {string} result
 * @returns {Contract[] | Contract}
 */
function parseContracts(result) {
  log('info', 'Parsing contract')
  const json = JSON.stringify(result)
  return JSON.parse(json)['Envelope']['Body'][
    'rechercherServicesSouscritsMesuresResponse'
  ]['servicesSouscritsMesures']['serviceSouscritMesures']
}

/**
 * Return User contract start date
 * @param {string} result
 * @returns {number}
 */
function parseServiceId(result) {
  log('info', 'Parsing serviceId')
  const json = JSON.stringify(result)
  return JSON.parse(json)['Envelope']['Body'][
    'commanderCollectePublicationMesuresResponse'
  ]['serviceSouscritId']
}

/**
 * Parsing SGE xml reply to get only mesure data
 * @param {string} result
 * @returns {SGEData[]}
 */
function parseSgeXmlData(result) {
  log('info', 'Parsing list of documents')
  const json = JSON.stringify(result)
  return JSON.parse(json)['Envelope']['Body'][
    'consulterMesuresDetailleesResponseV3'
  ]['grandeur']['points']
}

/**
 * Format data for DB storage
 * @param {SGEData[]} data
 * @returns {Promise<EnedisKonnectorData[]>} Parsed timestamp array
 */
async function formateDataForDoctype(data) {
  log('info', 'Formatting data')
  return data.map(record => {
    const date = moment(record.d, 'YYYY/MM/DD h:mm:ss')
    return {
      year: parseInt(date.format('YYYY')),
      month: parseInt(date.format('M')),
      day: parseInt(date.format('D')),
      hour: parseInt(date.format('H')),
      minute: parseInt(date.format('m')),
      load: record.v,
    }
  })
}

/**
 * Check if response contains contracts
 * @param {string} parsedReply
 * @return {boolean}
 */
function checkContractExists(parsedReply) {
  const json = JSON.stringify(parsedReply)
  return JSON.parse(json)['Envelope']['Body'][
    'rechercherServicesSouscritsMesuresResponse'
  ]['servicesSouscritsMesures']
}

/**
 * Format tag in order to be manipulated easily
 * @param {string} name
 * @returns {string} name
 */
function parseTags(name) {
  if (name.split(':')[1] !== undefined) {
    return name.split(':')[1]
  }
  return name
}

/**
 *
 * @param {string} value
 * @param {string} name
 * @returns {string|number} value
 */
function parseValue(value, name) {
  // Wh => KWh
  if (name === 'v') {
    return parseFloat((parseInt(value) / 1000).toFixed(2))
  }
  return value
}

/**
 *
 * @param {string} value
 * @param {string} name
 * @returns {string|number} value
 */
function parseValueHalfHour(value, name) {
  // W * 1/2h => KW * h
  if (name === 'v') {
    return parseFloat((parseInt(value) / 2000).toFixed(2))
  }
  return value
}

/**
 * Remove SGE useless multiple white spaces
 * @param {string} str
 * @returns {string}
 */
function removeMultipleSpaces(str) {
  return str.replace(/  +/g, ' ')
}

/**
 * Remove SGE useless dots
 * This regular expression matches one or more consecutive dots
 * and then in the replacement function, it checks if the dots are surrounded by non-dot characters.
 * If so, it replaces them with a space; otherwise, it removes them
 * @example
 * console.log(removeDots(".....03G2")); // Outputs: "03G2"
 * console.log(removeDots("....ETG..4...D")); // Outputs: "ETG 4 D"
 * console.log(removeDots("ETG 4 D")); // Outputs: "ETG 4 D"
 * @param {string} input - The input string containing dots to be removed.
 * @returns {string} The input string without dots.
 */
function removeDots(input) {
  return input.replace(/\.+/g, (match, offset, string) => {
    if (
      offset > 0 &&
      offset < string.length - match.length &&
      string[offset - 1] !== '.' &&
      string[offset + match.length] !== '.'
    ) {
      return ' '
    }
    return ''
  })
}

/**
 * Remove SGE address number
 * @param {string} str
 * @returns {string}
 */
function removeAddressNumber(str) {
  return str.replace(/\d+ |b |B |T |t |\d+/g, '')
}

/**
 * Parse PDL and to validate correct length of 14 digits
 * @param {number} pointId - some pdl start with 0
 * @returns {string} pointId with 14 digits
 * @example "07123456789012"
 */
function parsePointId(pointId) {
  const strPointId = pointId.toString()
  if (strPointId.length === 14) {
    return strPointId
  } else if (strPointId.length === 13) {
    return `0${strPointId}`
  } else {
    const errorMessage = 'PointId is malformed'
    Sentry.captureException(errorMessage, {
      tags: {
        section: 'parsePointId',
      },
      extra: {
        pointId: pointId,
      },
    })
    throw new Error(errorMessage)
  }
}

module.exports = {
  checkContractExists,
  formateDataForDoctype,
  parseContracts,
  parsePointId,
  parseServiceId,
  parseSgeXmlData,
  parseTags,
  parseUserAddress,
  parseUserOffPeakHours,
  parseUserPdl,
  parseValue,
  parseValueHalfHour,
  removeAddressNumber,
  removeMultipleSpaces,
  removeDots,
}