export function downloadFile(content, fileName, mimeType = 'text/plain;charset=utf-8') {
  const blob = new Blob([content], { type: mimeType })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = fileName
  a.click()
  URL.revokeObjectURL(url)
}

export function normalizeNewlines(text) {
  return text.replace(/\r\n/g, '\n')
}

export function createId() {
  return typeof crypto !== 'undefined' && crypto.randomUUID
    ? crypto.randomUUID()
    : `block-${Date.now()}-${Math.random().toString(16).slice(2)}`
}

export function formatLetterDate(value) {
  if (!value) return ''
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return value
  const day = String(date.getDate()).padStart(2, '0')
  const month = String(date.getMonth() + 1).padStart(2, '0')
  const year = date.getFullYear()
  return `${day}-${month}-${year}`
}

export function buildLetterName(title, date) {
  const formatted = formatLetterDate(date)
  const trimmed = String(title || '').trim()
  if (!trimmed) return formatted
  return `${formatted} ${trimmed}`
}

export function escapeHtml(value) {
  return value
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
}

export function visualizeLineBreaks(value) {
  const escaped = escapeHtml(value)
  return escaped.replace(/\n/g, '<span class="newline">\\n</span><br>')
}

export function escapeRegExp(text) {
  return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

export function unquoteValue(raw) {
  const value = String(raw ?? '').trim()
  const first = value[0]
  const last = value[value.length - 1]
  if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
    return value.slice(1, -1)
  }
  return value
}

export function normalizeHtmlForCopy(html) {
  return html
    .replace(/\t+/g, '')
    .split('\n')
    .map((line) => line.replace(/\s+$/g, '').replace(/^ +/g, ''))
    .join('\n')
    .replace(/ {2,}/g, ' ')
    .replace(/\n{3,}/g, '\n\n')
    .trim()
}

export function parseOptionCode(code) {
  if (!code) return null
  const parts = code.split(':')
  if (parts.length < 2) return null
  const key = parts.shift().trim()
  const value = parts.join(':').trim()
  if (!key || !value) return null
  return { key, value }
}

export function parseOptionsObject(text) {
  const map = {}
  if (!text) return map
  const regex = /([a-zA-Z0-9_]+)\s*:\s*([^,}]+)/g
  let match
  while ((match = regex.exec(text))) {
    map[match[1]] = match[2].trim()
  }
  return map
}

export function stringifyOptions(map, order = []) {
  const keys = []
  order.forEach((key) => {
    if (Object.prototype.hasOwnProperty.call(map, key)) keys.push(key)
  })
  Object.keys(map).forEach((key) => {
    if (!keys.includes(key)) keys.push(key)
  })
  return keys.map((key) => `${key}: ${map[key]}`).join(', ')
}
