<template>
  <div class="session-form">
    <BoxedIconTitleBlock
      class="session-form__heading"
      :title="isEditMode ? 'ویرایش جلسه' : 'افزودن جلسه جدید'"
      desc="در این قسمت می‌توانید جلسه خود را مدیریت کنید."
    >
      <template #icon>
        <SvgIcon name="book" :size="24" color="var(--color-primary)" />
      </template>
    </BoxedIconTitleBlock>

    <form class="session-form__form" @submit.prevent="onSubmit">
      <div class="session-form__grid">
        <div class="session-form__main-col">
          <LineTitleBlock title="اطلاعات جلسه" title-en="Session Details" />

          <!-- row 1 — title -->
          <div class="session-form__row">
            <TextField
              v-model="form.title"
              name="title"
              label="عنوان جلسه"
              :error="errors.title"
              @blur="validateAt('title', form.title)"
            >
              <template #appendIcon>
                <SvgIcon name="book" :size="20" color="var(--color-thd-gray)" />
              </template>
            </TextField>
          </div>

          <!-- row 2 — courseId / contentType -->
          <div class="session-form__row session-form__row--two">
            <SelectField
              v-model="form.courseId"
              name="courseId"
              label="دوره"
              :options="courseOptions"
              option-label="title"
              option-value="id"
              :searchable="true"
              :on-search="searchCourses"
              :error="errors.courseId"
            />
            <SelectField
              v-model="form.contentType"
              name="contentType"
              label="محتوای جلسه"
              :options="contentTypeOptions"
              option-label="label"
              option-value="value"
              :error="errors.contentType"
              @change="onContentTypeChange"
            />
          </div>

          <!-- row 3 — type / link -->
          <div class="session-form__row session-form__row--two">
            <SelectField
              v-model="form.type"
              name="type"
              label="نوع جلسه"
              :options="sessionTypeOptions"
              option-label="label"
              option-value="value"
              :error="errors.type"
              @change="onSessionTypeChange"
            />
            <TextField
              v-model="form.link"
              name="link"
              label="لینک جلسه"
              :disabled="form.type !== 'online'"
              :error="errors.link"
              @blur="validateAt('link', form.link)"
            />
          </div>

          <!-- row 4 — description -->
          <div class="session-form__row">
            <TextareaField
              v-model="form.description"
              name="description"
              label="توضیحات جلسه"
              :row="5"
            />
          </div>

          <!-- row 5 — content uploader -->
          <div class="session-form__row">
            <label class="session-form__uploader-label">محتوای جلسه</label>
            <FileUploader
              v-model="contentFiles"
              :accept="contentAccept"
              :multiple="false"
              :max-files="1"
              :max-size="contentMaxSize"
              :disabled="!form.contentType || contentUploadMutation.isPending.value"
              @select="onContentSelect"
              @remove="onContentRemove"
              @error="onContentError"
            />
          </div>
        </div>

        <div class="session-form__image-col">
          <ImageCropper
            v-model="image"
            name="image"
            bg-color="#eeeeee"
            @crop="onImageCropped"
            @error="onImageError"
          />
        </div>
      </div>

      <div class="session-form__divider" />

      <div class="session-form__actions">
        <BaseButton
          variant="transparent"
          text="منصرف شدم"
          custom-class="session-form__btn-cancel"
          @click="onCancel"
        >
          <template #prependIcon>
            <SvgIcon name="caret-right" :size="14" color="var(--color-sec-gray)" />
          </template>
        </BaseButton>
        <BaseButton
          type="submit"
          :text="isEditMode ? 'ذخیره تغییرات' : 'تایید اطلاعات'"
          :loading="submitting"
          custom-class="session-form__btn-submit"
        >
          <template #appendIcon>
            <SvgIcon name="arrow-left" :size="20" color="#fff" />
          </template>
        </BaseButton>
      </div>
    </form>
  </div>
</template>

<script setup>
import { toast } from 'vue3-toastify'
import useYup from '@/composables/useYup'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import useDebounce from '@/composables/useDebounce'
import { useQueryClient } from '@tanstack/vue-query'
import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import TextField from '@/components/form/TextField.vue'
import SelectField from '@/components/form/SelectField.vue'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import FileUploader from '@/components/form/FileUploader.vue'
import ImageCropper from '@/components/form/ImageCropper.vue'
import { objectToFormData } from '@/utils/object-to-formdata'
import { useUploadMediaMutation } from '@/services/query/auth'
import TextareaField from '@/components/form/TextareaField.vue'
import { sessionSchema } from '@/features/admin/sessions/schema'
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
import {
  COURSE_CONTENT_TYPE,
  COURSE_CONTENT_TYPE_ACCEPT,
  COURSE_CONTENT_TYPE_MAX_SIZE,
  SESSION_TYPE,
} from '@/enums'
import {
  adminSessionsKeys,
  useAddAdminSessionMutation,
  useAdminSessionQuery,
  useUpdateAdminSessionMutation,
} from '@/services/query/admin-sessions'

const route = useRoute()
const router = useRouter()
const queryClient = useQueryClient()

const sessionId = computed(() => (route.params.id ? Number(route.params.id) : null))
const presetCourseId = computed(() => (route.query.courseId ? Number(route.query.courseId) : null))
const isEditMode = computed(() => !!sessionId.value)

const sessionTypeOptions = [
  { value: 'offline', label: SESSION_TYPE.offline },
  { value: 'online', label: SESSION_TYPE.online },
]

const contentTypeOptions = Object.entries(COURSE_CONTENT_TYPE).map(([value, label]) => ({
  value,
  label,
}))

const form = ref({
  title: '',
  courseId: presetCourseId.value ?? '',
  contentType: '',
  type: '',
  link: '',
  description: '',
})

const image = ref(null)
const contentFiles = ref([])
const coverMediaId = ref(null)
const contentMediaId = ref(null)

const contentAccept = computed(() => COURSE_CONTENT_TYPE_ACCEPT[form.value.contentType] || '*')
const contentMaxSize = computed(
  () => COURSE_CONTENT_TYPE_MAX_SIZE[form.value.contentType] || 50 * 1024 * 1024
)

const { validate, validateAt, errors } = useYup(sessionSchema)

const courseSearch = ref('')
const courseFilters = computed(() => ({ title: courseSearch.value }))
const coursePagination = ref({ page: 1, perPage: 10 })
const { data: coursesResponse } = useAdminCoursesListQuery(courseFilters, coursePagination)
const selectedCourse = ref(null)
const courseOptions = computed(() => {
  const base = coursesResponse.value?.data ?? []
  if (selectedCourse.value && !base.some((c) => c.id === selectedCourse.value.id)) {
    return [...base, selectedCourse.value]
  }
  return base
})

const searchCourses = useDebounce((q) => {
  courseSearch.value = q || ''
}, 400)

const onContentTypeChange = () => {
  contentFiles.value = []
  contentMediaId.value = null
}

const onSessionTypeChange = () => {
  if (form.value.type !== 'online') form.value.link = ''
}

const { data: existingSession } = useAdminSessionQuery(sessionId, {
  enabled: () => !!sessionId.value,
})

const collectionToContentType = (collectionName) => {
  if (collectionName === 'video') return 'video'
  if (collectionName === 'voice') return 'voice'
  if (collectionName === 'pdf') return 'text'
  return ''
}

watch(
  existingSession,
  (session) => {
    if (!session) return
    if (session.course) selectedCourse.value = session.course
    const media = Array.isArray(session.media) ? session.media : []
    const coverMedia = media.find((m) => m.collectionName === 'cover')
    const contentMedia = media.find((m) => m.collectionName !== 'cover')
    const contentType = collectionToContentType(contentMedia?.collectionName)
    form.value = {
      title: session.title ?? '',
      courseId: session.course?.id ?? '',
      contentType,
      type: session.type ?? '',
      link: session.link ?? '',
      description: session.description ?? '',
    }
    coverMediaId.value = coverMedia?.id ?? null
    contentMediaId.value = contentMedia?.id ?? null
    if (contentMedia) {
      contentFiles.value = [
        {
          id: contentMedia.id,
          name: contentMedia.fileName ?? 'file',
          size: contentMedia.fileSize ?? 0,
          url: contentMedia.url,
        },
      ]
    }
    if (coverMedia?.url) image.value = { url: coverMedia.url }
  },
  { immediate: true }
)

const contentUploadMutation = useUploadMediaMutation()
const coverUploadMutation = useUploadMediaMutation()

const purposeForContentType = (contentType) => {
  if (contentType === 'video') return 'video'
  if (contentType === 'voice') return 'voice'
  return 'pdf'
}

const onContentSelect = async (files) => {
  const file = files?.[0]
  if (!file) return
  try {
    const formData = objectToFormData({
      file,
      purpose: purposeForContentType(form.value.contentType),
      context: 'session',
    })
    const response = await contentUploadMutation.mutateAsync(formData)
    const payload = response?.data ?? response
    const id = payload?.id ?? payload?.uploadId
    contentFiles.value = [{ id, name: file.name, size: file.size, url: payload?.url }]
    contentMediaId.value = id
  } catch {
    contentFiles.value = []
  }
}

const onContentRemove = () => {
  contentFiles.value = []
  contentMediaId.value = null
}

const onContentError = (msg) => toast.error(msg)

const onImageCropped = async (file) => {
  try {
    const formData = objectToFormData({ file, purpose: 'cover', context: 'session' })
    const response = await coverUploadMutation.mutateAsync(formData)
    const payload = response?.data ?? response
    image.value = { url: payload?.url, ...payload }
    coverMediaId.value = payload?.id ?? null
  } catch {
    /* handled globally */
  }
}

const onImageError = (msg) => toast.error(msg)

const buildPayload = (values) => {
  const mediaIds = [coverMediaId.value, contentMediaId.value].filter((id) => id != null)
  const payload = {
    title: values.title,
    courseId: values.courseId,
    type: values.type,
    link: values.type === 'online' ? values.link : undefined,
    description: values.description,
    mediaIds,
  }
  Object.keys(payload).forEach((key) => {
    const value = payload[key]
    if (value === undefined || value === '' || value === null) {
      delete payload[key]
    }
  })
  return payload
}

const addMutation = useAddAdminSessionMutation()
const updateMutation = useUpdateAdminSessionMutation()

const submitting = computed(
  () =>
    contentUploadMutation.isPending.value ||
    coverUploadMutation.isPending.value ||
    addMutation.isPending.value ||
    updateMutation.isPending.value
)

const onSubmit = async () => {
  if (contentUploadMutation.isPending.value || coverUploadMutation.isPending.value) {
    toast.info('لطفاً تا پایان بارگذاری محتوای جلسه منتظر بمانید.')
    return
  }
  const { isValid } = await validate(form.value)
  if (!isValid) return
  if (form.value.contentType && contentMediaId.value == null) {
    toast.error('برای نوع محتوای انتخاب‌شده، فایل جلسه را بارگذاری کنید.')
    return
  }
  const payload = buildPayload(form.value)
  try {
    if (isEditMode.value) {
      await updateMutation.mutateAsync({ id: sessionId.value, payload })
    } else {
      await addMutation.mutateAsync(payload)
    }
  } catch {
    return
  }
  // The list query is inactive while we're on the form page, and the global
  // `refetchOnMount: false` means navigating back won't refetch a merely-stale
  // query — so force a refetch of all matching queries, active or not.
  await queryClient.invalidateQueries({ queryKey: adminSessionsKeys.all, refetchType: 'all' })
  router.push({ name: 'admin-sessions' })
}

const onCancel = () => router.push({ name: 'admin-sessions' })
</script>

<style lang="scss" scoped>
.session-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;

  &__heading {
    margin-bottom: 0.75rem;
  }

  &__form {
    background: rgba(255, 255, 255, 60%);
    padding: 1rem;
    border-radius: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
  }

  &__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;

    @media (min-width: 1024px) {
      grid-template-columns: 8fr 4fr;
    }

    @media (min-width: 1280px) {
      grid-template-columns: 9fr 3fr;
    }
  }

  &__image-col {
    @media (min-width: 1024px) {
      padding: 0.5rem;
    }
  }

  &__main-col {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;

    @media (min-width: 1024px) {
      padding-inline-end: 1.25rem;
    }
  }

  &__row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem;

    &--two {
      @media (min-width: 768px) {
        grid-template-columns: repeat(2, 1fr);
      }
    }

    &--three {
      @media (min-width: 768px) {
        grid-template-columns: repeat(2, 1fr);
      }

      @media (min-width: 1024px) {
        grid-template-columns: repeat(3, 1fr);
      }
    }
  }

  &__uploader-label {
    display: block;
    margin-bottom: 0.5rem;
    font-family: var(--font-family-fa);
    font-weight: 300;
    line-height: 1.5rem;
    font-size: 0.875rem;
    color: var(--color-prim-gray);
  }

  &__preview {
    place-items: center center;
  }

  &__media {
    max-width: 100%;
    border-radius: 0.75rem;
    background: #000;
  }

  &__file-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--color-primary);
    text-decoration: none;
    font-family: var(--font-family-fa);
    font-size: 0.875rem;
    padding: 0.5rem 0;

    &:hover {
      text-decoration: underline;
    }
  }

  &__divider {
    border-block-end: 1px solid var(--color-thd-gray);
    margin-block: 1rem;
  }

  &__actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  &__btn-cancel {
    min-width: 9rem;
  }

  &__btn-submit {
    min-width: 12rem;
  }
}
</style>
