<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { invoke } from '@tauri-apps/api/core'
import { open } from '@tauri-apps/plugin-dialog'
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
import TaskQueue from './components/TaskQueue.vue'
import SubtitleEditor from './components/SubtitleEditor.vue'
import { useTaskStore } from './stores/tasks'
import type { DefaultModelPaths, OutputMode, TargetLanguage, TranslationConfig } from './lib/types'

const { t, locale } = useI18n()
const SOURCE_LANGUAGE_OPTIONS = [
  { value: 'zh', label: '中文' },
  { value: 'en', label: 'English' },
  { value: 'ja', label: '日本語' },
  { value: 'ko', label: '한국어' },
  { value: 'fr', label: 'Français' },
  { value: 'de', label: 'Deutsch' },
  { value: 'es', label: 'Español' },
  { value: 'ru', label: 'Русский' },
  { value: 'it', label: 'Italiano' },
  { value: 'pt', label: 'Português' },
  { value: 'ar', label: 'العربية' },
  { value: 'tr', label: 'Türkçe' },
  { value: 'vi', label: 'Tiếng Việt' },
  { value: 'id', label: 'Bahasa Indonesia' },
  { value: 'th', label: 'ไทย' },
  { value: 'hi', label: 'हिन्दी' },
  { value: 'uk', label: 'Українська' },
  { value: 'pl', label: 'Polski' },
  { value: 'nl', label: 'Nederlands' },
]
const MEDIA_EXTENSIONS = [
  'mp3',
  'wav',
  'm4a',
  'flac',
  'aac',
  'ogg',
  'opus',
  'mp4',
  'm4v',
  'mkv',
  'flv',
  'mov',
  'avi',
  'wmv',
  'webm',
  'ts',
  'm2ts',
  'mpeg',
  'mpg',
] as const

const taskStore = useTaskStore()
const targetLang = ref<TargetLanguage>('zh')
const outputMode = ref<OutputMode>('translate')
const sourceLang = ref('auto')
const bilingualOutput = ref(true)
const whisperModelPath = ref('')
const vadModelPath = ref('')
const defaultModelPaths = ref<DefaultModelPaths | null>(null)
const translationConfig = ref<TranslationConfig>({
  apiBase: localStorage.getItem('llm.apiBase') ?? 'https://open.bigmodel.cn/api/paas/v4',
  apiKey: localStorage.getItem('llm.apiKey') ?? '',
  model: localStorage.getItem('llm.model') ?? 'GLM-4-Flash-250414',
  batchSize: Number(localStorage.getItem('llm.batchSize') ?? '12'),
  contextSize: Number(localStorage.getItem('llm.contextSize') ?? '3'),
})
const pending = ref(false)
const feedback = ref('')
const showAdvanced = ref(false)
let unlistenMenuAction: UnlistenFn | null = null

const selectedTask = computed(() => taskStore.selectedTask)
const hasTranslationKey = computed(() => translationConfig.value.apiKey.trim().length > 0)

onMounted(() => {
  taskStore.initialize()
  void loadDefaultModelPaths()
  void bindMenuActions()
})

onUnmounted(() => {
  if (unlistenMenuAction) {
    unlistenMenuAction()
    unlistenMenuAction = null
  }
})

watch(locale, (newLocale) => {
  localStorage.setItem('locale', newLocale)
})

function persistTranslationConfig() {
  localStorage.setItem('llm.apiBase', translationConfig.value.apiBase)
  localStorage.setItem('llm.apiKey', translationConfig.value.apiKey)
  localStorage.setItem('llm.model', translationConfig.value.model)
  localStorage.setItem('llm.batchSize', String(translationConfig.value.batchSize))
  localStorage.setItem('llm.contextSize', String(translationConfig.value.contextSize))
}

function resetModelPaths() {
  whisperModelPath.value = defaultModelPaths.value?.whisperModelPath ?? ''
  vadModelPath.value = defaultModelPaths.value?.vadModelPath ?? ''
  feedback.value = t('app.feedback.restoredDefaults')
}

async function loadDefaultModelPaths() {
  try {
    const paths = await invoke<DefaultModelPaths>('get_default_model_paths')
    defaultModelPaths.value = paths
    if (!whisperModelPath.value) {
      whisperModelPath.value = paths.whisperModelPath
    }
    if (!vadModelPath.value) {
      vadModelPath.value = paths.vadModelPath
    }
  } catch (error) {
    feedback.value =
      error instanceof Error ? `${t('app.feedback.loadModelError')}${error.message}` : t('app.feedback.loadModelErrorFallback')
  }
}

async function bindMenuActions() {
  unlistenMenuAction = await listen<string>('menu:action', async ({ payload }) => {
    switch (payload) {
      case 'pick-files':
        await handlePickFiles()
        break
      case 'export-srt':
        await handleExport('srt')
        break
      case 'export-vtt':
        await handleExport('vtt')
        break
      case 'export-ass':
        await handleExport('ass')
        break
      case 'toggle-advanced':
        showAdvanced.value = !showAdvanced.value
        break
      case 'toggle-bilingual':
        bilingualOutput.value = !bilingualOutput.value
        feedback.value = bilingualOutput.value ? t('app.feedback.bilingualOn') : t('app.feedback.bilingualOff')
        break
      case 'reset-models':
        resetModelPaths()
        break
      case 'set-lang-zh-CN':
        locale.value = 'zh-CN'
        break
      case 'set-lang-en':
        locale.value = 'en'
        break
      default:
        break
    }
  })
}

async function submitFiles(filePaths: string[]) {
  pending.value = true
  feedback.value = ''

  try {
    const fallbackToSource = outputMode.value === 'translate' && !hasTranslationKey.value
    const effectiveOutputMode: OutputMode = fallbackToSource ? 'source' : outputMode.value

    for (const filePath of filePaths) {
      await taskStore.startTask({
        filePath,
        sourceLang: sourceLang.value === 'auto' ? null : sourceLang.value,
        targetLang: targetLang.value,
        outputMode: effectiveOutputMode,
        bilingualOutput: bilingualOutput.value,
        translationConfig: effectiveOutputMode === 'translate' ? translationConfig.value : null,
        whisperModelPath: whisperModelPath.value || null,
        vadModelPath: vadModelPath.value || null,
      })
    }
    if (fallbackToSource) {
      feedback.value = t('app.feedback.fallbackSource')
    } else {
      feedback.value = t('app.feedback.submitted', { count: filePaths.length })
    }
  } catch (error) {
    feedback.value = error instanceof Error ? error.message : t('app.feedback.submitFailed')
  } finally {
    pending.value = false
  }
}

async function handlePickFiles() {
  try {
    feedback.value = ''
    persistTranslationConfig()
    const selected = await open({
      multiple: true,
      directory: false,
      title: t('app.pickFiles'),
      filters: [
        {
          name: t('app.mediaFiles'),
          extensions: [...MEDIA_EXTENSIONS],
        },
      ],
    })

    if (!selected) return

    const filePaths = Array.isArray(selected) ? selected : [selected]
    if (filePaths.length === 0) return

    await submitFiles(filePaths)
  } catch (error) {
    feedback.value = error instanceof Error ? `${t('app.feedback.dialogError')}${error.message}` : t('app.feedback.dialogErrorFallback')
  }
}

async function handleFiles(event: Event) {
  const input = event.target as HTMLInputElement
  const files = Array.from(input.files ?? [])
  const filePaths = files
    .map((file) => (file as File & { path?: string }).path)
    .filter((path): path is string => Boolean(path))

  if (filePaths.length === 0) {
    await handlePickFiles()
    input.value = ''
    return
  }

  await submitFiles(filePaths)
  input.value = ''
}

async function handleExport(format: 'srt' | 'vtt' | 'ass') {
  if (!selectedTask.value) return
  const output = await taskStore.exportTask(selectedTask.value.id, format)
  feedback.value = output
}
</script>

<template>
  <main class="app-shell">
    <section class="topbar panel">
      <div class="toolbar-main">
        <div class="toolbar-title">
          <strong>CrossSubtitle</strong>
          <span class="credit-line">
            by <a href="https://kuraa.cc" target="_blank" rel="noreferrer">kuraa</a>
          </span>
        </div>
        <div class="toolbar-actions">
          <button class="button secondary toggle-button" type="button" @click="showAdvanced = !showAdvanced">
            {{ showAdvanced ? $t('app.collapse') : $t('app.settings') }}
          </button>
          <button class="button" type="button" :disabled="pending" @click="handlePickFiles">
            {{ pending ? $t('app.submitting') : $t('app.addTask') }}
          </button>
        </div>
      </div>

      <div class="workspace-toolbar">
        <div class="toolbar-group">
          <div class="form-grid">
            <label class="field">
              <span>{{ $t('app.mode') }}</span>
              <select v-model="outputMode">
                <option value="source">{{ $t('app.source') }}</option>
                <option value="translate">{{ $t('app.translate') }}</option>
              </select>
            </label>
            <label v-if="outputMode === 'translate'" class="field">
              <span>{{ $t('app.targetLang') }}</span>
              <select v-model="targetLang">
                <option value="zh">{{ $t('app.chinese') }}</option>
                <option value="en">{{ $t('app.english') }}</option>
              </select>
            </label>
            <label class="field">
              <span>{{ $t('app.sourceLang') }}</span>
              <select v-model="sourceLang">
                <option value="auto">{{ $t('app.autoDetect') }}</option>
                <option
                  v-for="option in SOURCE_LANGUAGE_OPTIONS"
                  :key="option.value"
                  :value="option.value"
                >
                  {{ option.label }}
                </option>
              </select>
            </label>
            <label class="check desktop-check">
              <input v-model="bilingualOutput" type="checkbox" />
              <span>{{ $t('app.bilingualExport') }}</span>
            </label>
          </div>
        </div>

        <p v-if="feedback" class="feedback status-text">{{ feedback }}</p>
      </div>

      <div v-if="showAdvanced" class="advanced-shell">
        <span class="group-title">{{ $t('app.advanced') }}</span>
        <div class="advanced-grid">
          <template v-if="outputMode === 'translate'">
            <label class="field wide">
              <span>{{ $t('app.llm.apiBase') }}</span>
              <input v-model="translationConfig.apiBase" placeholder="https://api.openai.com/v1" />
            </label>
            <label class="field wide">
              <span>{{ $t('app.llm.apiKey') }}</span>
              <input v-model="translationConfig.apiKey" type="password" placeholder="sk-..." />
            </label>
            <label class="field">
              <span>{{ $t('app.llm.model') }}</span>
              <input v-model="translationConfig.model" placeholder="GLM-4-Flash-250414" />
            </label>
            <label class="field">
              <span>{{ $t('app.llm.batchSize') }}</span>
              <input v-model.number="translationConfig.batchSize" type="number" min="10" max="15" />
            </label>
            <label class="field">
              <span>{{ $t('app.llm.contextSize') }}</span>
              <input v-model.number="translationConfig.contextSize" type="number" min="0" max="5" />
            </label>
          </template>
          <label class="field wide">
            <span>{{ $t('app.model.whisper') }}</span>
            <input
              v-model="whisperModelPath"
              :placeholder="defaultModelPaths?.whisperModelPath || $t('app.model.defaultWhisper')"
            />
          </label>
          <label class="field wide">
            <span>{{ $t('app.model.vad') }}</span>
            <input
              v-model="vadModelPath"
              :placeholder="defaultModelPaths?.vadModelPath || $t('app.model.defaultVad')"
            />
          </label>
        </div>
      </div>
    </section>

    <section class="content-grid">
      <TaskQueue
        :tasks="taskStore.tasks"
        :selected-task-id="taskStore.selectedTaskId"
        @select="taskStore.selectTask"
        @retry="taskStore.retryTask"
      />
      <SubtitleEditor
        :task="selectedTask"
        :logs="taskStore.selectedTaskLogs"
        @save="taskStore.updateSegment"
        @export="handleExport"
      />
    </section>
  </main>
</template>
