import { db } from '@/editor/indexeddb/db'
import { generateChannels } from '@/editor/yaml/generate/channels'
import { generateConfig } from '@/editor/yaml/generate/config'
import { generateEmailAddresses } from '@/editor/yaml/generate/email'
import { generateInjects } from '@/editor/yaml/generate/injects'
import { generateMilestones } from '@/editor/yaml/generate/milestones'
import { generateObjectives } from '@/editor/yaml/generate/objectives'
import { generateQuestionnaires } from '@/editor/yaml/generate/questionnaires'
import { generateTools } from '@/editor/yaml/generate/tools'
import JSZip from 'jszip'
import { stringify } from 'yaml'
import { InjectType } from '../indexeddb/types'
import type { EditorConfig } from '../useEditorStorage'
import {
  CHANNELS_FILE_NAME,
  CONFIG_FILE_NAME,
  CONTENT_FOLDER_NAME,
  EMAIL_FILE_NAME,
  FILES_FOLDER_NAME,
  INJECTS_FILE_NAME,
  MILESTONES_FILE_NAME,
  OBJECTIVES_FILE_NAME,
  QUESTIONNAIRES_FILE_NAME,
  TOOLS_FILE_NAME,
} from './utils'

export type FileMapping = {
  name: string
  content: string | Blob
}

export const generateFileContents = async (config: EditorConfig) => {
  const emailAddressesCount = await db.emailAddresses.count()
  const toolsCount = await db.tools.count()
  const questionnairesCount = await db.injectInfos
    .where({ type: InjectType.QUESTIONNAIRE })
    .count()
  const files = await db.files.toArray()

  const generatedChannels = await generateChannels(config)
  const generatedConfig = await generateConfig(config)
  const generatedInjects = await generateInjects()
  const generatedMilestones = await generateMilestones(config)
  const generatedObjectives = await generateObjectives()
  const generatedEmail = emailAddressesCount
    ? await generateEmailAddresses()
    : undefined
  const generatedQuestionnaires = questionnairesCount
    ? await generateQuestionnaires()
    : undefined
  const generatedTools = toolsCount ? await generateTools() : undefined

  const markdowns = await db.markdownContents.toArray()

  const fileMapping = [
    { name: CHANNELS_FILE_NAME, content: stringify(generatedChannels) },
    { name: CONFIG_FILE_NAME, content: stringify(generatedConfig) },
    { name: INJECTS_FILE_NAME, content: stringify(generatedInjects) },
    { name: MILESTONES_FILE_NAME, content: stringify(generatedMilestones) },
    { name: OBJECTIVES_FILE_NAME, content: stringify(generatedObjectives) },
    { name: EMAIL_FILE_NAME, content: stringify(generatedEmail) },
    {
      name: QUESTIONNAIRES_FILE_NAME,
      content: stringify(generatedQuestionnaires),
    },
    { name: TOOLS_FILE_NAME, content: stringify(generatedTools) },
    ...files.map(file => ({
      name: `${FILES_FOLDER_NAME}/${file.name}`,
      content: file.blob,
    })),
    ...markdowns.map(markdown => ({
      name: `${CONTENT_FOLDER_NAME}/${markdown.fileName}`,
      content: markdown.content,
    })),
  ].filter(file => file.content)

  await db.markdownContents.clear()

  return fileMapping
}

export const createDefinitionZip = async (
  fileMapping: {
    name: string
    content: Blob | string
  }[]
) => {
  const zip = new JSZip()
  fileMapping.forEach(file => zip.file(file.name, file.content))
  return zip.generateAsync({ type: 'blob' })
}

export const downloadDefinitionZip = async (config: EditorConfig) => {
  const fileMapping = await generateFileContents(config)

  createDefinitionZip(fileMapping).then(content => {
    const link = document.createElement('a')
    link.href = URL.createObjectURL(content)
    link.download = 'definition.zip'
    link.click()
    URL.revokeObjectURL(link.href)
  })
}
