import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { useRouter } from 'vue-router'

import { fetchFileBlobByURL, uploadFile } from '@/shared/api/files'
import {
  emptyListingPublishOptions,
  emptyListingSalePriceConfig,
  fetchListingPublishOptions,
  fetchListingSalePriceConfig,
  type ChargeMode,
  type ListingPublishOptions,
  type PublishSalePriceConfig,
  type ScreenshotKey,
} from '@/features/listings/api/listingOptions'
import { createListing } from '@/features/listings/api/listings'
import { usePricingCalculator } from '@/shared/composables/usePricingCalculator'
import {
  buildPublishDraft,
  clearRecord,
  defaultPublishForm,
  readPublishDraft,
  removePublishDraft,
  writePublishDraft,
} from '@/features/seller/composables/usePublishDraft'
import type { PublishForm } from '@/types/publish'
import { commonOnlineTimes, dailyLossOptions, formatNumber, roundRatio } from '@/utils/pricing'

const draftSaveDelay = 400

interface UsePublishFormOptions {
  draftKey: string
  submitSuccessPath: string
  persistBeforeUnload?: boolean
  confirmReset?: () => Promise<void>
  notifySuccess: (message: string) => void
  notifyWarning: (message: string) => void
  notifyError: (message: string) => void
}

export function usePublishForm(options: UsePublishFormOptions) {
  const router = useRouter()
  const loading = ref(false)
  const uploading = ref(false)
  const suppressDraftSave = ref(false)
  const draftReady = ref(false)
  const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
  const salePriceConfig = ref<PublishSalePriceConfig>(emptyListingSalePriceConfig)
  const fileInput = ref<HTMLInputElement | null>(null)
  const activeUploadKey = ref<ScreenshotKey>('coin')
  const form = reactive<PublishForm>(defaultPublishForm())
  const quantityValues = reactive<Record<string, number>>({})
  const quantityModes = reactive<Record<string, ChargeMode>>({})
  const screenshotFiles = reactive<Record<string, string>>({})
  const screenshotPreviews = reactive<Record<string, string>>({})
  const selectedSkins = ref<string[]>([])
  let draftSaveTimer: number | undefined

  const pricing = usePricingCalculator({
    form,
    publishOptions,
    salePriceConfig,
    quantityValues,
    quantityModes,
    screenshotFiles,
    selectedSkins,
  })
  const uploadedScreenshotCount = computed(() => pricing.screenshotUrls.value.length)
  const requiredScreenshotCount = ref(0)

  onMounted(() => {
    restoreDraft()
    draftReady.value = true
    if (options.persistBeforeUnload) window.addEventListener('beforeunload', handleBeforeUnload)
    loadPublishOptions()
  })

  onBeforeUnmount(() => {
    saveDraft({ force: true })
    if (options.persistBeforeUnload) window.removeEventListener('beforeunload', handleBeforeUnload)
    revokeAllScreenshotPreviews()
  })

  watch(
    [form, quantityValues, quantityModes, screenshotFiles, selectedSkins],
    () => {
      saveDraft()
    },
    { deep: true },
  )

  watch(
    pricing.recommendedDepositAmount,
    () => {
      syncRecommendedDeposit()
    },
    { immediate: true },
  )

  watch(
    [() => form.season_insurance, pricing.quantityItems],
    () => {
      clearForbiddenQuantityItems()
    },
    { deep: true },
  )

  watch(
    [pricing.screenshotSlots, () => form.ban_record],
    () => {
      requiredScreenshotCount.value = pricing.screenshotSlots.value.filter((item) => isScreenshotRequired(item)).length
    },
    { immediate: true, deep: true },
  )

  async function loadPublishOptions() {
    try {
      const [nextPublishOptions, nextSalePriceConfig] = await Promise.all([
        fetchListingPublishOptions(),
        fetchListingSalePriceConfig(),
      ])
      publishOptions.value = nextPublishOptions
      salePriceConfig.value = nextSalePriceConfig

      // 默认数字都是0
      for (const item of nextPublishOptions.quantity_items) {
        if (quantityValues[item.key] === undefined) {
          quantityValues[item.key] = 0
        }
      }
    } catch {
      publishOptions.value = emptyListingPublishOptions
      salePriceConfig.value = emptyListingSalePriceConfig
    }
  }

  function saveDraft(saveOptions: { force?: boolean } = {}) {
    if (suppressDraftSave.value) {
      clearDraftSaveTimer()
      return
    }
    if (!saveOptions.force && !draftReady.value) return
    if (!saveOptions.force) {
      scheduleDraftSave()
      return
    }
    clearDraftSaveTimer()
    writeDraft()
  }

  function scheduleDraftSave() {
    clearDraftSaveTimer()
    draftSaveTimer = window.setTimeout(() => {
      draftSaveTimer = undefined
      writeDraft()
    }, draftSaveDelay)
  }

  function clearDraftSaveTimer() {
    if (draftSaveTimer === undefined) return
    window.clearTimeout(draftSaveTimer)
    draftSaveTimer = undefined
  }

  function writeDraft() {
    writePublishDraft(
      options.draftKey,
      buildPublishDraft({
        form,
        quantityValues,
        quantityModes,
        screenshotFiles,
        selectedSkins: selectedSkins.value,
      }),
    )
  }

  function handleSaveDraft() {
    saveDraft({ force: true })
    options.notifySuccess('草稿已保存')
  }

  function handleBeforeUnload() {
    saveDraft({ force: true })
  }

  function restoreDraft() {
    const draft = readPublishDraft(options.draftKey)
    if (!draft) return
    Object.assign(form, draft.form)
    normalizeOnlineTime()
    clearRecord(quantityValues)
    clearRecord(quantityModes)
    clearRecord(screenshotFiles)
    Object.assign(quantityValues, draft.quantityValues)
    Object.assign(quantityModes, draft.quantityModes)
    Object.assign(screenshotFiles, draft.screenshotFiles)
    selectedSkins.value = draft.selectedSkins
    hydrateScreenshotPreviews()
  }

  function resetDraftState() {
    Object.assign(form, defaultPublishForm())
    clearRecord(quantityValues)
    clearRecord(quantityModes)
    clearRecord(screenshotFiles)
    revokeAllScreenshotPreviews()
    selectedSkins.value = []
    activeUploadKey.value = 'coin'

    // Also re-initialize quantityValues to 0
    for (const item of publishOptions.value.quantity_items) {
      quantityValues[item.key] = 0
    }
  }

  function normalizeOnlineTime() {
    if (form.online_start === '全天' || form.online_end === '全天') {
      form.online_start = '00:00'
      form.online_end = '23:59'
    }
  }

  async function handleResetDraft() {
    try {
      await options.confirmReset?.()
    } catch {
      return
    }
    suppressDraftSave.value = true
    clearDraftSaveTimer()
    resetDraftState()
    removePublishDraft(options.draftKey)
    options.notifySuccess('已重置')
    window.setTimeout(() => {
      suppressDraftSave.value = false
    })
  }

  function toggleSkin(skin: string) {
    selectedSkins.value = selectedSkins.value.includes(skin)
      ? selectedSkins.value.filter((item) => item !== skin)
      : [...selectedSkins.value, skin]
  }

  function toggleRegion(region: string) {
    form.common_regions = form.common_regions.includes(region)
      ? form.common_regions.filter((item) => item !== region)
      : [...form.common_regions, region]
  }

  function triggerUpload(key: ScreenshotKey) {
    activeUploadKey.value = key
    fileInput.value?.click()
  }

  async function handleScreenshotUpload(event: Event) {
    const input = event.target as HTMLInputElement
    const file = input.files?.[0]
    if (!file) return
    const key = activeUploadKey.value
    const previewURL = URL.createObjectURL(file)
    setScreenshotPreview(key, previewURL)
    uploading.value = true
    try {
      const uploaded = await uploadFile(file, 'listing')
      screenshotFiles[key] = uploaded.url
      options.notifySuccess('截图已上传')
    } catch (error) {
      revokeScreenshotPreview(key)
      options.notifyError(readError(error, '截图上传失败'))
    } finally {
      uploading.value = false
      input.value = ''
    }
  }

  function removeScreenshot(key: ScreenshotKey) {
    screenshotFiles[key] = ''
    revokeScreenshotPreview(key)
  }

  function getScreenshotPreviewURL(key: ScreenshotKey) {
    return screenshotPreviews[key] || screenshotFiles[key] || ''
  }

  function setScreenshotPreview(key: ScreenshotKey, previewURL: string) {
    revokeScreenshotPreview(key)
    screenshotPreviews[key] = previewURL
  }

  function revokeScreenshotPreview(key: ScreenshotKey) {
    const previewURL = screenshotPreviews[key]
    if (previewURL?.startsWith('blob:')) URL.revokeObjectURL(previewURL)
    delete screenshotPreviews[key]
  }

  function revokeAllScreenshotPreviews() {
    for (const key of Object.keys(screenshotPreviews)) revokeScreenshotPreview(key)
  }

  async function hydrateScreenshotPreviews() {
    for (const [key, fileURL] of Object.entries(screenshotFiles)) {
      if (!fileURL || screenshotPreviews[key] || !fileURL.startsWith('/api/files/object')) continue
      try {
        const blob = await fetchFileBlobByURL(fileURL)
        setScreenshotPreview(key, URL.createObjectURL(blob))
      } catch {
        // 草稿预览失败不影响已上传文件地址，提交时仍会带上原 URL。
      }
    }
  }

  function handleFireLevelInput(value: string | number | undefined) {
    if (value === '' || value === undefined) {
      form.fire_level = ''
      return
    }
    const level = Number(value)
    form.fire_level = Number.isFinite(level) ? Math.trunc(level) : ''
  }

  function handleAcceleratedSaleRatioInput(value: string | number | undefined) {
    if (value === '' || value === undefined) {
      form.accelerated_sale_ratio = ''
      return
    }
    const ratio = Number(value)
    form.accelerated_sale_ratio = Number.isFinite(ratio) ? ratio : ''
  }

  function syncRecommendedDeposit() {
    const recommended = pricing.recommendedDepositAmount.value
    if (recommended <= 0) return
    const current = Number(form.deposit_amount)
    if (form.deposit_amount === '' || !Number.isFinite(current) || current < recommended) {
      form.deposit_amount = recommended
    }
  }

  function useRecommendedDeposit() {
    if (pricing.recommendedDepositAmount.value > 0) {
      form.deposit_amount = pricing.recommendedDepositAmount.value
    }
  }

  function clearForbiddenQuantityItems() {
    for (const item of pricing.quantityItems.value) {
      if (!pricing.isQuantityItemDisabled(item)) continue
      quantityValues[item.key] = 0
      quantityModes[item.key] = '赠送'
    }
  }

  function setQuantityMode(item: { key: string; label: string }, mode: ChargeMode) {
    if (pricing.isQuantityItemDisabled(item)) return
    quantityModes[item.key] = mode
  }

  function clampAcceleratedSaleRatioInput() {
    if (!pricing.hasAcceleratedSaleRatioInput() || pricing.calculatedDefaultSaleRatio.value <= 0) return
    const ratio = Number(form.accelerated_sale_ratio)
    if (!Number.isFinite(ratio)) {
      form.accelerated_sale_ratio = ''
      return
    }
    form.accelerated_sale_ratio = roundRatio(
      Math.min(Math.max(ratio, pricing.calculatedDefaultSaleRatio.value), pricing.maxAcceleratedSaleRatio.value),
    )
  }

  function useReferenceSaleRatio() {
    form.accelerated_sale_ratio = ''
  }

  function useMaxAcceleratedSaleRatio() {
    if (pricing.maxAcceleratedSaleRatio.value <= 0) return
    form.accelerated_sale_ratio = pricing.maxAcceleratedSaleRatio.value
  }

  async function handleSubmit() {
    normalizeOnlineTime()
    const error = validateForm()
    if (error) {
      options.notifyWarning(error)
      return
    }
    loading.value = true
    try {
      const listing = await createListing({
        title: pricing.publishTitle.value,
        description: form.remark,
        server_region: form.server_region,
        login_platform: form.login_method,
        rank_level: form.rank_level,
        haf_coin_amount: pricing.coinMAmount.value * 1000000,
        asset_summary: buildAssetSummary(),
        screenshot_urls: pricing.screenshotUrls.value,
        price: pricing.calculatedFinalPrice.value,
        deposit_amount: Number(form.deposit_amount),
      })
      removePublishDraft(options.draftKey)
      suppressDraftSave.value = true
      clearDraftSaveTimer()
      options.notifySuccess(
        listing.status === 'published' && listing.review_status === 'approved'
          ? '发布成功，已上架'
          : '发布成功，等待后台审核',
      )
      await router.push(options.submitSuccessPath)
    } catch (error) {
      options.notifyError(readError(error, '发布失败，请确认已登录并完成实名认证'))
    } finally {
      loading.value = false
    }
  }

  function validateForm() {
    if (!form.server_region) return '请选择区服'
    if (pricing.coinMAmount.value <= 0) return '请填写哈夫币/M'
    if (!form.rank_level) return '请选择段位'
    if (!form.fire_level) return '请填写烽火等级'
    if (Number(form.fire_level) < pricing.fireLevelMin.value) return `烽火等级低于${pricing.fireLevelMin.value}级的号无法发布`
    if (!form.season_insurance) return '请选择赛季保险'
    if (!form.stamina_level) return '请选择体力等级'
    if (!form.load_level) return '请选择负重等级'
    if (!dailyLossOptions.includes(pricing.dailyLossMAmount.value)) return '请选择每日损耗'
    if (pricing.hasAcceleratedSaleRatioInput()) {
      const ratio = Number(form.accelerated_sale_ratio)
      if (!Number.isFinite(ratio) || ratio <= 0) return '加速出售比例格式不正确'
      if (pricing.calculatedDefaultSaleRatio.value > 0 && ratio < pricing.calculatedDefaultSaleRatio.value) {
        return `加速出售比例不能低于默认比例 1:${formatNumber(pricing.calculatedDefaultSaleRatio.value)}`
      }
      if (pricing.maxAcceleratedSaleRatio.value > 0 && ratio > pricing.maxAcceleratedSaleRatio.value) {
        return `加速出售比例不能超过 1:${formatNumber(pricing.maxAcceleratedSaleRatio.value)}`
      }
    }
    if (pricing.banRecordOptions.value.length && !form.ban_record) return '请选择封禁记录'
    if (form.deposit_amount === '' || Number(form.deposit_amount) < 0) return '请填写押金'
    if (!Number.isFinite(Number(form.deposit_amount))) return '押金格式不正确'
    if (pricing.recommendedDepositAmount.value > 0 && Number(form.deposit_amount) < pricing.recommendedDepositAmount.value) {
      return `押金不能低于智能推荐 ¥${pricing.recommendedDepositAmount.value}`
    }
    if (pricing.calculatedConsumablePrice.value > 0 && Number(form.deposit_amount) <= pricing.calculatedConsumablePrice.value) {
      return `押金必须大于额外消耗品总价值 ¥${pricing.calculatedConsumablePrice.value}`
    }
    if (!pricing.calculatedFinalPrice.value) return '请完善币数、保险、体力和负重后再发布'
    if (!Number.isFinite(pricing.calculatedFinalPrice.value)) return '发布价格计算异常，请检查填写内容'
    for (const item of pricing.screenshotSlots.value) {
      if (isScreenshotRequired(item) && !screenshotFiles[item.key]) return `请上传${item.label}`
    }
    for (const item of pricing.quantityItems.value) {
      if (!pricing.isQuantityItemDisabled(item)) {
        const val = quantityValues[item.key]
        if (val === undefined || val === null || (val as unknown) === '') {
          return `请填写${item.label}的数量`
        }
        if (Number(val) < 0) {
          return `${item.label}的数量不能为负数`
        }
      }
    }
    for (const item of pricing.quantityItems.value) {
      if (pricing.isQuantityItemDisabled(item) && Number(quantityValues[item.key] || 0) > 0) {
        return '赛季保险选择 3*3 时不能填写 9格体验卡'
      }
    }
    return ''
  }

  function isScreenshotRequired(item: { key: string; required: boolean }) {
    return item.required || (item.key === 'tencentSecurity' && shouldRequireBanEvidence())
  }

  function shouldRequireBanEvidence() {
    return pricing.banEvidenceOptions.value.includes(form.ban_record)
  }

  function buildAssetSummary() {
    return {
      face_owner: form.face_owner,
      secret_kd: form.secret_kd,
      fire_level: Number(form.fire_level),
      daily_loss_m: pricing.dailyLossMAmount.value,
      publish_ratio: pricing.calculatedPlatformPricing.value.buyerRatio,
      price_breakdown: {
        seller_reference_ratio: pricing.calculatedSellerReferenceRatio.value,
        seller_ratio: pricing.calculatedRatio.value,
        seller_coin_base_price: pricing.calculatedCoinBasePrice.value,
        seller_total_price: pricing.calculatedSellerPrice.value,
        consumable_price: pricing.calculatedConsumablePrice.value,
        daily_loss_ratio_adjustment: pricing.dailyLossRatioAdjustment.value,
        accelerated_sale_ratio: pricing.hasAcceleratedSaleRatioInput()
          ? Number(form.accelerated_sale_ratio)
          : pricing.calculatedDefaultSaleRatio.value,
        buyer_coin_base_price: pricing.calculatedPlatformPricing.value.buyerCoinBasePrice,
        buyer_total_price: pricing.calculatedFinalPrice.value,
        buyer_ratio: pricing.calculatedPlatformPricing.value.buyerRatio,
        platform_markup_amount: pricing.calculatedPlatformPricing.value.platformMarkupAmount,
        platform_rule_type: pricing.calculatedPlatformPricing.value.ruleType,
      },
      season_insurance: form.season_insurance,
      stamina_level: form.stamina_level,
      load_level: form.load_level,
      resources: pricing.quantityItems.value.map((item) => ({
        key: item.key,
        label: item.label,
        price: item.price,
        quantity: pricing.isQuantityItemDisabled(item) ? 0 : Number(quantityValues[item.key] || 0),
        mode: pricing.isQuantityItemDisabled(item) ? '赠送' : quantityModes[item.key] || '收费',
      })),
      skin_groups: pricing.skinGroups.value.reduce<Record<string, string[]>>((groups, group) => {
        groups[group.key] = group.options.filter((skin) => selectedSkins.value.includes(skin))
        return groups
      }, {}),
      online_time: {
        start: form.online_start,
        end: form.online_end,
      },
      ban_record: form.ban_record,
      common_regions: form.common_regions,
      remark: form.remark,
    }
  }

  return {
    ...pricing,
    dailyLossOptions,
    commonOnlineTimes,
    formatNumber,
    router,
    loading,
    uploading,
    fileInput,
    activeUploadKey,
    form,
    quantityValues,
    quantityModes,
    screenshotFiles,
    screenshotPreviews,
    selectedSkins,
    uploadedScreenshotCount,
    requiredScreenshotCount,
    loadPublishOptions,
    saveDraft,
    handleSaveDraft,
    resetDraftState,
    handleResetDraft,
    toggleSkin,
    toggleRegion,
    triggerUpload,
    handleScreenshotUpload,
    removeScreenshot,
    getScreenshotPreviewURL,
    handleFireLevelInput,
    handleAcceleratedSaleRatioInput,
    syncRecommendedDeposit,
    useRecommendedDeposit,
    clearForbiddenQuantityItems,
    setQuantityMode,
    clampAcceleratedSaleRatioInput,
    useReferenceSaleRatio,
    useMaxAcceleratedSaleRatio,
    handleSubmit,
    validateForm,
    isScreenshotRequired,
    shouldRequireBanEvidence,
    buildAssetSummary,
  }
}

function readError(error: unknown, fallback: string) {
  if (typeof error === 'object' && error && 'response' in error) {
    const response = (error as { response?: { data?: { message?: string } } }).response
    return response?.data?.message || fallback
  }
  return fallback
}
