<script lang="ts" setup>
import { computed, reactive, ref } from 'vue'
import { RouterLink } from 'vue-router'
import * as select from '@zag-js/select'
import { CircleAlert, CircleCheck, Trash } from '@lucide/vue'
import {
  AlertRoot,
  AlertTitle,
  AlertDescription,
} from '@/components/ui/alert'
import { Box } from '@/components/ui/box'
import { Button } from '@/components/ui/button'
import { Field, FieldError, FieldLabel } from '@/components/ui/field'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Lucide } from '@/components/ui/lucide'
import {
  SelectRoot,
  SelectControl,
  SelectTrigger,
  SelectValueText,
  SelectContent,
  SelectItemGroup,
  SelectItem,
  SelectItemText,
} from '@/components/ui/select'
import { getApiErrorMessage, getApiValidationErrors } from '@/core/utils/getApiErrorMessage'
import { useAuthStore } from '@/stores/auth'
import { usePermissions } from '@/composables/usePermissions'
import { submitFeedback } from '../services/feedback.service'
import {
  FEEDBACK_PRIORITY_OPTIONS,
  FEEDBACK_TYPE_OPTIONS,
  createEmptyFeedbackForm,
  type FeedbackFormState,
  type FeedbackPriority,
  type FeedbackType,
} from '../types/feedback.types'
import illustrationUrl from '@/assets/images/logo.svg'

type SelectOption = { label: string; value: string }

function createSelectCollection(options: SelectOption[]) {
  return select.collection({
    items: options,
    itemToValue: (item) => item.label,
  })
}

function labelToValue(options: SelectOption[], label: string | undefined): string {
  if (!label) return options[0]?.value ?? ''
  return options.find((option) => option.label === label)?.value ?? ''
}

function valueToLabel(options: SelectOption[], value: string): string[] {
  const option = options.find((item) => item.value === value)
  return option ? [option.label] : options[0] ? [options[0].label] : []
}

const MAX_IMAGE_MB = 10
const MAX_VIDEO_MB = 50

const authStore = useAuthStore()
const { hasPermission } = usePermissions()
const form = reactive<FeedbackFormState>(createEmptyFeedbackForm())
const fieldErrors = reactive<Record<string, string>>({})
const loading = ref(false)
const submitted = ref(false)
const errorMessage = ref('')
const successMessage = ref('')

const typeCollection = createSelectCollection(FEEDBACK_TYPE_OPTIONS)
const priorityCollection = createSelectCollection(FEEDBACK_PRIORITY_OPTIONS)
const typeInitial = computed(() => valueToLabel(FEEDBACK_TYPE_OPTIONS, form.type))
const priorityInitial = computed(() => valueToLabel(FEEDBACK_PRIORITY_OPTIONS, form.priority))

const isAuthenticated = computed(() => authStore.isAuthenticated)
const canViewList = computed(() => hasPermission('lihat maklum balas'))

function setTypeValue(details: { value: string[] }) {
  form.type = labelToValue(FEEDBACK_TYPE_OPTIONS, details.value[0]) as FeedbackType
}

function setPriorityValue(details: { value: string[] }) {
  form.priority = labelToValue(FEEDBACK_PRIORITY_OPTIONS, details.value[0]) as FeedbackPriority
}

function clearFieldError(key: string) {
  delete fieldErrors[key]
}

function onImagesChange(event: Event) {
  const input = event.target as HTMLInputElement
  const files = input.files ? Array.from(input.files) : []
  input.value = ''
  clearFieldError('images')

  for (const file of files) {
    if (file.size > MAX_IMAGE_MB * 1024 * 1024) {
      fieldErrors.images = `Setiap imej mesti bawah ${MAX_IMAGE_MB}MB.`
      return
    }
  }

  form.images.push(...files)
}

function onVideosChange(event: Event) {
  const input = event.target as HTMLInputElement
  const files = input.files ? Array.from(input.files) : []
  input.value = ''
  clearFieldError('videos')

  for (const file of files) {
    if (file.size > MAX_VIDEO_MB * 1024 * 1024) {
      fieldErrors.videos = `Setiap video mesti bawah ${MAX_VIDEO_MB}MB.`
      return
    }
  }

  form.videos.push(...files)
}

function removeImage(index: number) {
  form.images.splice(index, 1)
}

function removeVideo(index: number) {
  form.videos.splice(index, 1)
}

function validate(): boolean {
  Object.keys(fieldErrors).forEach((key) => delete fieldErrors[key])

  if (!form.title.trim()) fieldErrors.title = 'Tajuk diperlukan.'
  if (!form.description.trim()) fieldErrors.description = 'Penerangan diperlukan.'

  return Object.keys(fieldErrors).length === 0
}

function resetForm() {
  Object.assign(form, createEmptyFeedbackForm())
  submitted.value = false
  successMessage.value = ''
  errorMessage.value = ''
}

async function handleSubmit() {
  if (loading.value || !validate()) return

  loading.value = true
  errorMessage.value = ''
  successMessage.value = ''

  try {
    const response = await submitFeedback({
      type: form.type,
      title: form.title.trim(),
      description: form.description.trim(),
      priority: form.priority,
      page_url: form.page_url.trim() || undefined,
      steps_to_reproduce: form.steps_to_reproduce.trim() || undefined,
      expected_behavior: form.expected_behavior.trim() || undefined,
      actual_behavior: form.actual_behavior.trim() || undefined,
      additional_notes: form.additional_notes.trim() || undefined,
      images: form.images,
      videos: form.videos,
      screen_resolution: `${window.screen.width}x${window.screen.height}`,
      viewport_size: `${window.innerWidth}x${window.innerHeight}`,
      timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    })

    submitted.value = true
    successMessage.value = response.message ?? 'Maklum balas berjaya dihantar. Terima kasih!'
  } catch (err) {
    const validationErrors = getApiValidationErrors(err)
    if (validationErrors) {
      Object.assign(fieldErrors, validationErrors)
    }
    errorMessage.value = getApiErrorMessage(err, 'Gagal menghantar maklum balas.')
  } finally {
    loading.value = false
  }
}
</script>

<template>
  <div class="min-h-screen bg-background px-4 py-10">
    <div class="mx-auto w-full max-w-3xl">
      <div class="mb-8 flex items-center gap-3">
        <img :src="illustrationUrl" alt="MyKOPKB" class="h-10 w-auto" />
        <div>
          <h1 class="text-2xl font-semibold">Maklum Balas</h1>
          <p class="text-sm opacity-70">
            Laporkan ralat, cadangan atau isu.
          </p>
        </div>
      </div>

      <Box v-if="submitted" class="p-8 text-center">
        <CircleCheck class="mx-auto size-12 text-success" />
        <h2 class="mt-4 text-xl font-medium">Terima kasih!</h2>
        <p class="mt-2 opacity-70">{{ successMessage }}</p>
        <div class="mt-6 flex flex-wrap justify-center gap-3">
          <Button variant="primary" @click="resetForm">Hantar lagi</Button>
          <RouterLink v-if="isAuthenticated && canViewList" :to="{ name: 'list-feedback' }">
            <Button look="outline">Lihat senarai</Button>
          </RouterLink>
          <RouterLink v-else-if="!isAuthenticated" :to="{ name: 'login' }">
            <Button look="outline">Log masuk</Button>
          </RouterLink>
        </div>
      </Box>

      <Box v-else class="p-6 sm:p-8">
        <AlertRoot v-if="errorMessage" class="mb-6" variant="danger">
          <CircleAlert class="size-4" />
          <AlertTitle>Ralat</AlertTitle>
          <AlertDescription>{{ errorMessage }}</AlertDescription>
        </AlertRoot>

        <form class="space-y-5" @submit.prevent="handleSubmit">
          <div class="grid gap-5 sm:grid-cols-2">
            <Field>
              <FieldLabel>Jenis</FieldLabel>
              <SelectRoot :key="typeInitial[0]" :collection="typeCollection" :default-value="typeInitial"
                @value-change="setTypeValue">
                <SelectControl>
                  <SelectTrigger>
                    <SelectValueText placeholder="Pilih jenis" />
                  </SelectTrigger>
                </SelectControl>
                <SelectContent>
                  <SelectItemGroup>
                    <SelectItem v-for="item in typeCollection.items" :key="item.label" :item="item">
                      <SelectItemText>{{ item.label }}</SelectItemText>
                    </SelectItem>
                  </SelectItemGroup>
                </SelectContent>
              </SelectRoot>
            </Field>

            <Field>
              <FieldLabel>Keutamaan</FieldLabel>
              <SelectRoot :key="priorityInitial[0]" :collection="priorityCollection" :default-value="priorityInitial"
                @value-change="setPriorityValue">
                <SelectControl>
                  <SelectTrigger>
                    <SelectValueText placeholder="Pilih keutamaan" />
                  </SelectTrigger>
                </SelectControl>
                <SelectContent>
                  <SelectItemGroup>
                    <SelectItem v-for="item in priorityCollection.items" :key="item.label" :item="item">
                      <SelectItemText>{{ item.label }}</SelectItemText>
                    </SelectItem>
                  </SelectItemGroup>
                </SelectContent>
              </SelectRoot>
            </Field>
          </div>

          <Field :invalid="!!fieldErrors.title">
            <FieldLabel>Tajuk</FieldLabel>
            <Input v-model="form.title" placeholder="Ringkasan isu atau cadangan" @input="clearFieldError('title')" />
            <FieldError v-if="fieldErrors.title">{{ fieldErrors.title }}</FieldError>
          </Field>

          <Field :invalid="!!fieldErrors.description">
            <FieldLabel>Penerangan</FieldLabel>
            <Textarea v-model="form.description" rows="5" placeholder="Terangkan dengan terperinci..."
              @input="clearFieldError('description')" />
            <FieldError v-if="fieldErrors.description">{{ fieldErrors.description }}</FieldError>
          </Field>

          <Field>
            <FieldLabel>URL halaman (pilihan)</FieldLabel>
            <Input v-model="form.page_url" type="url" placeholder="https://" />
          </Field>

          <Field>
            <FieldLabel>Langkah untuk menghasilkan semula (pilihan)</FieldLabel>
            <Textarea v-model="form.steps_to_reproduce" rows="3" />
          </Field>

          <div class="grid gap-5 sm:grid-cols-2">
            <Field>
              <FieldLabel>Kelakuan dijangka (pilihan)</FieldLabel>
              <Textarea v-model="form.expected_behavior" rows="3" />
            </Field>
            <Field>
              <FieldLabel>Kelakuan sebenar (pilihan)</FieldLabel>
              <Textarea v-model="form.actual_behavior" rows="3" />
            </Field>
          </div>

          <Field>
            <FieldLabel>Nota tambahan (pilihan)</FieldLabel>
            <Textarea v-model="form.additional_notes" rows="2" />
          </Field>

          <Field :invalid="!!fieldErrors.images">
            <FieldLabel>Imej (pilihan)</FieldLabel>
            <Input type="file" accept="image/jpeg,image/png,image/gif,image/webp" multiple @change="onImagesChange" />
            <p class="mt-1 text-xs opacity-60">JPEG, PNG, GIF, WebP — maks {{ MAX_IMAGE_MB }}MB setiap fail</p>
            <FieldError v-if="fieldErrors.images">{{ fieldErrors.images }}</FieldError>
            <ul v-if="form.images.length" class="mt-2 space-y-1">
              <li v-for="(file, index) in form.images" :key="`${file.name}-${index}`"
                class="flex items-center justify-between rounded border border-foreground/10 px-3 py-2 text-sm">
                <span class="truncate">{{ file.name }}</span>
                <button type="button" class="text-danger" @click="removeImage(index)">
                  <Trash class="size-4" />
                </button>
              </li>
            </ul>
          </Field>

          <Field :invalid="!!fieldErrors.videos">
            <FieldLabel>Video (pilihan)</FieldLabel>
            <Input type="file" accept="video/mp4,video/quicktime,video/webm" multiple @change="onVideosChange" />
            <p class="mt-1 text-xs opacity-60">MP4, MOV, WebM — maks {{ MAX_VIDEO_MB }}MB setiap fail</p>
            <FieldError v-if="fieldErrors.videos">{{ fieldErrors.videos }}</FieldError>
            <ul v-if="form.videos.length" class="mt-2 space-y-1">
              <li v-for="(file, index) in form.videos" :key="`${file.name}-${index}`"
                class="flex items-center justify-between rounded border border-foreground/10 px-3 py-2 text-sm">
                <span class="truncate">{{ file.name }}</span>
                <button type="button" class="text-danger" @click="removeVideo(index)">
                  <Trash class="size-4" />
                </button>
              </li>
            </ul>
          </Field>

          <div class="flex flex-wrap gap-3 pt-2">
            <Button type="submit" variant="primary" :disabled="loading">
              <Lucide v-if="loading" icon="LoaderCircle" class="mr-2 size-4 animate-spin" />
              {{ loading ? 'Menghantar...' : 'Hantar Maklum Balas' }}
            </Button>
            <RouterLink v-if="!isAuthenticated" :to="{ name: 'login' }">
              <Button type="button" look="outline">Kembali ke log masuk</Button>
            </RouterLink>
          </div>
        </form>
      </Box>
    </div>
  </div>
</template>
