import type { DiaryEntry } from '../stores/diary-store'

/**
 * Diary export helpers. Three flavours:
 *   - Markdown: human-readable log grouped by month
 *   - JSON: faithful dump for backups or re-import
 *   - CSV: Letterboxd-import-compatible (Title, Watched Date, Rating, Rewatch, Review, Tags)
 *
 * All produce a string ready to hand to triggerDownload(). No file IO here -
 * keeps these pure and testable.
 */

export type ExportFormat = 'markdown' | 'json' | 'csv'

function pad(n: number) {
  return n < 10 ? '0' + n : String(n)
}

function ymd(iso: string): string {
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return ''
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
}

function monthLabel(iso: string): string {
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return 'Undated'
  return d.toLocaleString('en-US', { month: 'long', year: 'numeric' })
}

function escapeCsv(value: string): string {
  if (value === '') return ''
  if (/[",\n\r]/.test(value)) {
    return '"' + value.replace(/"/g, '""') + '"'
  }
  return value
}

export function toMarkdown(entries: DiaryEntry[]): string {
  const sorted = [...entries].sort((a, b) => b.watchedAt.localeCompare(a.watchedAt))
  const groups = new Map<string, DiaryEntry[]>()
  for (const e of sorted) {
    const key = monthLabel(e.watchedAt)
    const arr = groups.get(key)
    if (arr) arr.push(e)
    else groups.set(key, [e])
  }
  const lines: string[] = []
  lines.push('# Watch diary')
  lines.push('')
  lines.push(`_${sorted.length} ${sorted.length === 1 ? 'entry' : 'entries'} - exported ${ymd(new Date().toISOString())}_`)
  lines.push('')
  for (const [label, items] of groups) {
    lines.push(`## ${label}`)
    lines.push('')
    for (const e of items) {
      const date = ymd(e.watchedAt)
      const rating = e.rating ? ` - ${e.rating}/10` : ''
      const rewatch = e.rewatch ? ' (rewatch)' : ''
      const emoji = e.emoji ? ` ${e.emoji}` : ''
      lines.push(`- **${date}** - ${e.itemName}${rating}${rewatch}${emoji}`)
      if (e.note && e.note.trim()) {
        for (const line of e.note.trim().split(/\r?\n/)) {
          lines.push(`    > ${line}`)
        }
      }
    }
    lines.push('')
  }
  return lines.join('\n')
}

export function toJson(entries: DiaryEntry[]): string {
  const sorted = [...entries].sort((a, b) => b.watchedAt.localeCompare(a.watchedAt))
  return JSON.stringify(
    {
      exportedAt: new Date().toISOString(),
      count: sorted.length,
      entries: sorted,
    },
    null,
    2,
  )
}

/**
 * Letterboxd import format. Columns chosen from their documented set
 * (https://letterboxd.com/about/importing-data/). Title + Watched Date
 * are the only required fields; everything else is optional and they'll
 * tolerate missing values cleanly. Rating is converted from our 1-10
 * scale to their 0.5-5 scale by halving.
 */
export function toLetterboxdCsv(entries: DiaryEntry[]): string {
  const header = ['Title', 'Watched Date', 'Rating', 'Rewatch', 'Review', 'Tags']
  const sorted = [...entries].sort((a, b) => b.watchedAt.localeCompare(a.watchedAt))
  const rows = sorted.map(e => {
    const rating = e.rating ? (e.rating / 2).toFixed(1) : ''
    const rewatch = e.rewatch ? 'Yes' : ''
    const review = e.note || ''
    const tags = e.emoji || ''
    return [
      escapeCsv(e.itemName),
      ymd(e.watchedAt),
      rating,
      rewatch,
      escapeCsv(review),
      escapeCsv(tags),
    ].join(',')
  })
  return [header.join(','), ...rows].join('\r\n')
}

const MIME: Record<ExportFormat, string> = {
  markdown: 'text/markdown;charset=utf-8',
  json: 'application/json;charset=utf-8',
  csv: 'text/csv;charset=utf-8',
}

const EXT: Record<ExportFormat, string> = {
  markdown: 'md',
  json: 'json',
  csv: 'csv',
}

export function triggerDownload(content: string, format: ExportFormat): void {
  const blob = new Blob([content], { type: MIME[format] })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `diary-${ymd(new Date().toISOString())}.${EXT[format]}`
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  setTimeout(() => URL.revokeObjectURL(url), 0)
}

export function exportDiary(entries: DiaryEntry[], format: ExportFormat): void {
  const content =
    format === 'markdown' ? toMarkdown(entries)
    : format === 'json' ? toJson(entries)
    : toLetterboxdCsv(entries)
  triggerDownload(content, format)
}
