<script lang="ts" setup>
import { useTemplateRef } from 'vue'

const emit = defineEmits<{
  start: [name: string]
  progress: [read: number, total: number]
  success: [data: ArrayBuffer]
  error: [message: string]
}>()

const MAX_FILE_SIZE = 1440 * 1024

const fileInput = useTemplateRef('file-input')

async function onOpenClick() {
  fileInput.value?.click()
}

async function onFileChange(event: Event) {
  const files = (event.target as HTMLInputElement).files
  if (!files?.length) {
    return
  }

  try {
    const data = await readFile(files[0])
    emit('success', data)
  } catch (e) {
    let error
    if (!(e instanceof Error)) {
      error = new Error('' + e)
    } else {
      error = e
    }
    emit('error', error.message)
  }
}

function readFile(file: File): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    if (file.size > MAX_FILE_SIZE) {
      reject(new Error('Maximum file size exceeded'))
      return
    }
    const reader = new FileReader()

    reader.onloadstart = (event: ProgressEvent) => {
      emit('progress', event.loaded, event.total)
    }

    reader.onprogress = (event: ProgressEvent) => {
      emit('progress', event.loaded, event.total)
    }

    reader.onload = (event: ProgressEvent) => {
      emit('progress', event.loaded, event.total)
      const result = (event.target as FileReader).result as ArrayBuffer
      resolve(result)
    }

    reader.onerror = () => {
      reject(`read error`)
    }

    reader.onabort = () => {
      reject('read aborted')
    }

    reader.readAsArrayBuffer(file)
    emit('start', file.name)
  })
}
</script>

<template>
  <div>
    <input id="disk-file" ref="file-input" type="file" @change="onFileChange" />
    <button type="button" @click="onOpenClick">Open a disk image...</button>
  </div>
</template>

<style scoped>
input[type='file'] {
  display: none;
}
</style>
