<template>
  <q-page class="q-pa-xs pricing-page">
    <div class="top-bar row items-center justify-between q-mb-xs">
      <div class="text-subtitle1 text-weight-bold">Urun Fiyatlandirma</div>
      <div class="row items-center q-gutter-xs">
        <q-btn-dropdown color="secondary" outline icon="view_module" label="Doviz Gorunumu" :auto-close="false">
          <q-list dense class="currency-menu-list">
            <q-item clickable @click="selectAllCurrencies">
              <q-item-section>Tumunu Sec</q-item-section>
            </q-item>
            <q-item clickable @click="clearAllCurrencies">
              <q-item-section>Tumunu Temizle</q-item-section>
            </q-item>
            <q-separator />
            <q-item v-for="option in currencyOptions" :key="option.value" clickable @click="toggleCurrencyRow(option.value)">
              <q-item-section avatar>
                <q-checkbox
                  :model-value="isCurrencySelected(option.value)"
                  dense
                  @update:model-value="(val) => toggleCurrency(option.value, val)"
                  @click.stop
                />
              </q-item-section>
              <q-item-section>{{ option.label }}</q-item-section>
            </q-item>
          </q-list>
        </q-btn-dropdown>
        <q-btn
          flat
          :color="showSelectedOnly ? 'primary' : 'grey-7'"
          :icon="showSelectedOnly ? 'checklist_rtl' : 'list_alt'"
          :label="showSelectedOnly ? `Secililer (${selectedRowCount})` : 'Secili Olanlari Getir'"
          :disable="!showSelectedOnly && selectedRowCount === 0"
          @click="toggleShowSelectedOnly"
        />
        <q-btn flat color="grey-7" icon="restart_alt" label="Filtreleri Sifirla" @click="resetAll" />
        <q-btn color="primary" icon="refresh" label="Veriyi Yenile" :loading="store.loading" @click="reloadData" />
      </div>
    </div>

    <div class="table-wrap" :style="{ '--sticky-scroll-comp': `${stickyScrollComp}px` }">
      <q-table
        ref="mainTableRef"
        class="pane-table pricing-table"
        flat
        dense
        row-key="id"
        :rows="filteredRows"
        :columns="visibleColumns"
        :loading="store.loading"
        virtual-scroll
        :virtual-scroll-item-size="rowHeight"
        :virtual-scroll-sticky-size-start="headerHeight"
        :virtual-scroll-slice-size="36"
        :rows-per-page-options="[0]"
        v-model:pagination="tablePagination"
        hide-bottom
        :table-style="tableStyle"
        @virtual-scroll="onTableVirtualScroll"
      >
        <template #header="props">
          <q-tr :props="props" class="header-row-fixed">
            <q-th
              v-for="col in props.cols"
              :key="col.name"
              :props="props"
              :class="[col.headerClasses, { 'sticky-col': isStickyCol(col.name), 'sticky-boundary': isStickyBoundary(col.name) }]"
              :style="getHeaderCellStyle(col)"
            >
              <q-checkbox
                v-if="col.name === 'select'"
                size="sm"
                color="primary"
                :model-value="allSelectedVisible"
                :indeterminate="someSelectedVisible && !allSelectedVisible"
                @update:model-value="toggleSelectAllVisible"
              />
              <div v-else class="header-with-filter">
                <span>{{ col.label }}</span>
                <q-btn
                  v-if="isHeaderFilterField(col.field)"
                  dense
                  flat
                  round
                  size="8px"
                  icon="filter_alt"
                  :color="hasFilter(col.field) ? 'primary' : 'grey-7'"
                  class="header-filter-btn"
                >
                  <q-badge v-if="hasFilter(col.field)" color="primary" floating rounded>
                    {{ getFilterBadgeValue(col.field) }}
                  </q-badge>
                  <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                    <div v-if="isMultiSelectFilterField(col.field)" class="excel-filter-menu">
                      <q-input
                        v-model="columnFilterSearch[col.field]"
                        dense
                        outlined
                        clearable
                        use-input
                        class="excel-filter-select"
                        placeholder="Ara"
                      />
                      <div class="excel-filter-actions row items-center justify-between q-pt-xs">
                        <q-btn flat dense size="sm" label="Tumunu Sec" @click="selectAllColumnFilterOptions(col.field)" />
                        <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter(col.field)" />
                      </div>
                      <q-virtual-scroll
                        v-if="getFilterOptionsForField(col.field).length > 0"
                        class="excel-filter-options"
                        :items="getFilterOptionsForField(col.field)"
                        :virtual-scroll-item-size="32"
                        separator
                      >
                        <template #default="{ item: option }">
                          <q-item
                            :key="`${col.field}-${option.value}`"
                            dense
                            clickable
                            class="excel-filter-option"
                            @click="toggleColumnFilterValue(col.field, option.value)"
                          >
                            <q-item-section avatar>
                              <q-checkbox
                                dense
                                size="sm"
                                :model-value="isColumnFilterValueSelected(col.field, option.value)"
                                @update:model-value="() => toggleColumnFilterValue(col.field, option.value)"
                                @click.stop
                              />
                            </q-item-section>
                            <q-item-section>
                              <q-item-label>{{ option.label }}</q-item-label>
                            </q-item-section>
                          </q-item>
                        </template>
                      </q-virtual-scroll>
                      <div v-else class="excel-filter-empty">
                        Sonuc yok
                      </div>
                    </div>
                    <div v-else-if="isNumberRangeFilterField(col.field)" class="excel-filter-menu">
                      <div class="range-filter-grid">
                        <q-input
                          v-model="numberRangeFilters[col.field].min"
                          dense
                          outlined
                          clearable
                          label="Min"
                          inputmode="decimal"
                          class="range-filter-field"
                        />
                        <q-input
                          v-model="numberRangeFilters[col.field].max"
                          dense
                          outlined
                          clearable
                          label="Max"
                          inputmode="decimal"
                          class="range-filter-field"
                        />
                      </div>
                      <div class="row justify-end q-pt-xs">
                        <q-btn flat dense size="sm" label="Temizle" @click="clearRangeFilter(col.field)" />
                      </div>
                    </div>
                    <div v-else-if="isDateRangeFilterField(col.field)" class="excel-filter-menu">
                      <div class="range-filter-grid">
                        <q-input
                          v-model="dateRangeFilters[col.field].from"
                          dense
                          outlined
                          clearable
                          type="date"
                          label="Baslangic"
                          class="range-filter-field"
                        />
                        <q-input
                          v-model="dateRangeFilters[col.field].to"
                          dense
                          outlined
                          clearable
                          type="date"
                          label="Bitis"
                          class="range-filter-field"
                        />
                      </div>
                      <div class="row justify-end q-pt-xs">
                        <q-btn flat dense size="sm" label="Temizle" @click="clearRangeFilter(col.field)" />
                      </div>
                    </div>
                  </q-menu>
                </q-btn>
                <q-btn
                  v-else
                  dense
                  flat
                  round
                  size="8px"
                  icon="filter_alt"
                  class="header-filter-btn header-filter-ghost"
                  tabindex="-1"
                />
              </div>
            </q-th>
          </q-tr>
        </template>

        <template #body-cell-select="props">
          <q-td
            :props="props"
            class="text-center selection-col"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <q-checkbox
              size="sm"
              color="primary"
              :model-value="!!selectedMap[props.row.id]"
              @update:model-value="(val) => toggleRowSelection(props.row.id, val)"
            />
          </q-td>
        </template>

        <template #body-cell-productCode="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <span class="product-code-text" :title="String(props.value ?? '')">{{ props.value }}</span>
          </q-td>
        </template>

        <template #body-cell-stockQty="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <span class="stock-qty-text">{{ formatStock(props.value) }}</span>
          </q-td>
        </template>

        <template #body-cell-stockEntryDate="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <span class="date-cell-text">{{ formatDateDisplay(props.value) }}</span>
          </q-td>
        </template>

        <template #body-cell-lastPricingDate="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <span :class="['date-cell-text', { 'date-warning': needsRepricing(props.row) }]">
              {{ formatDateDisplay(props.value) }}
            </span>
          </q-td>
        </template>

        <template #body-cell-brandGroupSelection="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <select
              class="native-cell-select"
              :value="props.row.brandGroupSelection"
              @change="(e) => onBrandGroupSelectionChange(props.row, e.target.value)"
            >
              <option value="">Seciniz</option>
              <option v-for="opt in brandGroupOptions" :key="opt.value" :value="opt.value">
                {{ opt.label }}
              </option>
            </select>
          </q-td>
        </template>

        <template #body-cell="props">
          <q-td
            :props="props"
            :class="{ 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }"
            :style="getBodyCellStyle(props.col)"
          >
            <input
              v-if="editableColumnSet.has(props.col.name)"
              class="native-cell-input text-right"
              :value="formatPrice(props.row[props.col.field])"
              type="text"
              inputmode="decimal"
              @change="(e) => onEditableCellChange(props.row, props.col.field, e.target.value)"
            />
            <span v-else class="cell-text" :title="String(props.value ?? '')">{{ props.value }}</span>
          </q-td>
        </template>
      </q-table>
    </div>

    <q-banner v-if="store.error" class="bg-red text-white q-mt-xs">
      Hata: {{ store.error }}
    </q-banner>
  </q-page>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { useProductPricingStore } from 'src/stores/ProductPricingStore'

const store = useProductPricingStore()
const FETCH_LIMIT = 500
const nextCursor = ref('')
const loadingMore = ref(false)

const usdToTry = 38.25
const eurToTry = 41.6
const multipliers = [1, 1.03, 1.06, 1.09, 1.12, 1.15]
const rowHeight = 31
const headerHeight = 72

const brandGroupOptions = [
  { label: 'MARKA GRUBU A', value: 'MARKA GRUBU A' },
  { label: 'MARKA GRUBU B', value: 'MARKA GRUBU B' },
  { label: 'MARKA GRUBU C', value: 'MARKA GRUBU C' }
]

const currencyOptions = [
  { label: 'USD', value: 'USD' },
  { label: 'EUR', value: 'EUR' },
  { label: 'TRY', value: 'TRY' }
]

const multiFilterColumns = [
  { field: 'productCode', label: 'Urun Kodu' },
  { field: 'askiliYan', label: 'Askili Yan' },
  { field: 'kategori', label: 'Kategori' },
  { field: 'urunIlkGrubu', label: 'Urun Ilk Grubu' },
  { field: 'urunAnaGrubu', label: 'Urun Ana Grubu' },
  { field: 'urunAltGrubu', label: 'Urun Alt Grubu' },
  { field: 'icerik', label: 'Icerik' },
  { field: 'karisim', label: 'Karisim' }
]
const numberRangeFilterFields = ['stockQty']
const dateRangeFilterFields = ['stockEntryDate', 'lastPricingDate']
const columnFilters = ref({
  productCode: [],
  askiliYan: [],
  kategori: [],
  urunIlkGrubu: [],
  urunAnaGrubu: [],
  urunAltGrubu: [],
  icerik: [],
  karisim: []
})
const columnFilterSearch = ref({
  productCode: '',
  askiliYan: '',
  kategori: '',
  urunIlkGrubu: '',
  urunAnaGrubu: '',
  urunAltGrubu: '',
  icerik: '',
  karisim: ''
})
const numberRangeFilters = ref({
  stockQty: { min: '', max: '' }
})
const dateRangeFilters = ref({
  stockEntryDate: { from: '', to: '' },
  lastPricingDate: { from: '', to: '' }
})
const multiSelectFilterFieldSet = new Set(multiFilterColumns.map((x) => x.field))
const numberRangeFilterFieldSet = new Set(numberRangeFilterFields)
const dateRangeFilterFieldSet = new Set(dateRangeFilterFields)
const headerFilterFieldSet = new Set([
  ...multiFilterColumns.map((x) => x.field),
  ...numberRangeFilterFields,
  ...dateRangeFilterFields
])

const mainTableRef = ref(null)
const tablePagination = ref({
  page: 1,
  rowsPerPage: 0,
  sortBy: 'productCode',
  descending: false
})
const selectedMap = ref({})
const selectedCurrencies = ref(['USD', 'EUR', 'TRY'])
const showSelectedOnly = ref(false)

const editableColumns = [
  'costPrice',
  'expenseForBasePrice',
  'basePriceUsd',
  'basePriceTry',
  'usd1',
  'usd2',
  'usd3',
  'usd4',
  'usd5',
  'usd6',
  'eur1',
  'eur2',
  'eur3',
  'eur4',
  'eur5',
  'eur6',
  'try1',
  'try2',
  'try3',
  'try4',
  'try5',
  'try6'
]
const editableColumnSet = new Set(editableColumns)

function col (name, label, field, width, extra = {}) {
  return {
    name,
    label,
    field,
    align: extra.align || 'left',
    sortable: !!extra.sortable,
    style: `width:${width}px;min-width:${width}px;max-width:${width}px;`,
    headerStyle: `width:${width}px;min-width:${width}px;max-width:${width}px;`,
    classes: extra.classes || '',
    headerClasses: extra.headerClasses || extra.classes || ''
  }
}

const allColumns = [
  col('select', '', 'select', 40, { align: 'center', classes: 'text-center selection-col' }),
  col('productCode', 'URUN KODU', 'productCode', 108, { sortable: true, classes: 'ps-col product-code-col' }),
  col('stockQty', 'STOK ADET', 'stockQty', 72, { align: 'right', sortable: true, classes: 'ps-col stock-col' }),
  col('stockEntryDate', 'STOK GIRIS TARIHI', 'stockEntryDate', 92, { align: 'center', sortable: true, classes: 'ps-col date-col' }),
  col('lastPricingDate', 'SON FIYATLANDIRMA TARIHI', 'lastPricingDate', 108, { align: 'center', sortable: true, classes: 'ps-col date-col' }),
  col('askiliYan', 'ASKILI YAN', 'askiliYan', 54, { sortable: true, classes: 'ps-col' }),
  col('kategori', 'KATEGORI', 'kategori', 54, { sortable: true, classes: 'ps-col' }),
  col('urunIlkGrubu', 'URUN ILK GRUBU', 'urunIlkGrubu', 66, { sortable: true, classes: 'ps-col' }),
  col('urunAnaGrubu', 'URUN ANA GRUBU', 'urunAnaGrubu', 66, { sortable: true, classes: 'ps-col' }),
  col('urunAltGrubu', 'URUN ALT GRUBU', 'urunAltGrubu', 66, { sortable: true, classes: 'ps-col' }),
  col('icerik', 'ICERIK', 'icerik', 62, { sortable: true, classes: 'ps-col' }),
  col('karisim', 'KARISIM', 'karisim', 62, { sortable: true, classes: 'ps-col' }),
  col('marka', 'MARKA', 'marka', 54, { sortable: true, classes: 'ps-col' }),
  col('brandGroupSelection', 'MARKA GRUBU SECIMI', 'brandGroupSelection', 76),
  col('costPrice', 'MALIYET FIYATI', 'costPrice', 74, { align: 'right', sortable: true, classes: 'usd-col' }),
  col('expenseForBasePrice', 'TABAN FIYAT MASRAF', 'expenseForBasePrice', 86, { align: 'right', classes: 'usd-col' }),
  col('basePriceUsd', 'TABAN USD', 'basePriceUsd', 74, { align: 'right', classes: 'usd-col' }),
  col('basePriceTry', 'TABAN TRY', 'basePriceTry', 74, { align: 'right', classes: 'try-col' }),
  col('usd1', 'USD 1', 'usd1', 62, { align: 'right', classes: 'usd-col' }),
  col('usd2', 'USD 2', 'usd2', 62, { align: 'right', classes: 'usd-col' }),
  col('usd3', 'USD 3', 'usd3', 62, { align: 'right', classes: 'usd-col' }),
  col('usd4', 'USD 4', 'usd4', 62, { align: 'right', classes: 'usd-col' }),
  col('usd5', 'USD 5', 'usd5', 62, { align: 'right', classes: 'usd-col' }),
  col('usd6', 'USD 6', 'usd6', 62, { align: 'right', classes: 'usd-col' }),
  col('eur1', 'EUR 1', 'eur1', 62, { align: 'right', classes: 'eur-col' }),
  col('eur2', 'EUR 2', 'eur2', 62, { align: 'right', classes: 'eur-col' }),
  col('eur3', 'EUR 3', 'eur3', 62, { align: 'right', classes: 'eur-col' }),
  col('eur4', 'EUR 4', 'eur4', 62, { align: 'right', classes: 'eur-col' }),
  col('eur5', 'EUR 5', 'eur5', 62, { align: 'right', classes: 'eur-col' }),
  col('eur6', 'EUR 6', 'eur6', 62, { align: 'right', classes: 'eur-col' }),
  col('try1', 'TRY 1', 'try1', 62, { align: 'right', classes: 'try-col' }),
  col('try2', 'TRY 2', 'try2', 62, { align: 'right', classes: 'try-col' }),
  col('try3', 'TRY 3', 'try3', 62, { align: 'right', classes: 'try-col' }),
  col('try4', 'TRY 4', 'try4', 62, { align: 'right', classes: 'try-col' }),
  col('try5', 'TRY 5', 'try5', 62, { align: 'right', classes: 'try-col' }),
  col('try6', 'TRY 6', 'try6', 62, { align: 'right', classes: 'try-col' })
]

const stickyColumnNames = [
  'select',
  'productCode',
  'stockQty',
  'stockEntryDate',
  'lastPricingDate',
  'askiliYan',
  'kategori',
  'urunIlkGrubu',
  'urunAnaGrubu',
  'urunAltGrubu',
  'icerik',
  'karisim',
  'marka',
  'brandGroupSelection',
  'costPrice',
  'expenseForBasePrice',
  'basePriceUsd',
  'basePriceTry'
]
const stickyBoundaryColumnName = 'basePriceTry'
const stickyColumnNameSet = new Set(stickyColumnNames)

const visibleColumns = computed(() => {
  const selected = new Set(selectedCurrencies.value)
  return allColumns.filter((c) => {
    if (c.name.startsWith('usd')) return selected.has('USD')
    if (c.name.startsWith('eur')) return selected.has('EUR')
    if (c.name.startsWith('try')) return selected.has('TRY')
    return true
  })
})

const stickyLeftMap = computed(() => {
  const map = {}
  let left = 0
  for (const colName of stickyColumnNames) {
    const c = allColumns.find((x) => x.name === colName)
    if (!c) continue
    map[colName] = left
    left += extractWidth(c.style)
  }
  return map
})
const stickyScrollComp = computed(() => {
  const boundaryCol = allColumns.find((x) => x.name === stickyBoundaryColumnName)
  return (stickyLeftMap.value[stickyBoundaryColumnName] || 0) + extractWidth(boundaryCol?.style)
})

const tableMinWidth = computed(() => visibleColumns.value.reduce((sum, c) => sum + extractWidth(c.style), 0))
const tableStyle = computed(() => ({
  width: `${tableMinWidth.value}px`,
  minWidth: `${tableMinWidth.value}px`,
  tableLayout: 'fixed'
}))

const rows = computed(() => store.rows || [])
const multiFilterOptionMap = computed(() => {
  const map = {}
  multiFilterColumns.forEach(({ field }) => {
    const uniq = new Set()
    rows.value.forEach((row) => {
      const val = String(row?.[field] ?? '').trim()
      if (val) uniq.add(val)
    })
    map[field] = Array.from(uniq)
      .sort((a, b) => a.localeCompare(b, 'tr'))
      .map((v) => ({ label: v, value: v }))
  })
  return map
})
const filteredFilterOptionMap = computed(() => {
  const map = {}
  multiFilterColumns.forEach(({ field }) => {
    const search = String(columnFilterSearch.value[field] || '').trim().toLocaleLowerCase('tr')
    const options = multiFilterOptionMap.value[field] || []
    map[field] = search
      ? options.filter((option) => option.label.toLocaleLowerCase('tr').includes(search))
      : options
  })
  return map
})

const filteredRows = computed(() => {
  return rows.value.filter((row) => {
    if (showSelectedOnly.value && !selectedMap.value[row.id]) return false
    for (const mf of multiFilterColumns) {
      const selected = columnFilters.value[mf.field] || []
      if (selected.length > 0 && !selected.includes(String(row?.[mf.field] ?? '').trim())) return false
    }
    const stockQtyMin = parseNullableNumber(numberRangeFilters.value.stockQty?.min)
    const stockQtyMax = parseNullableNumber(numberRangeFilters.value.stockQty?.max)
    const stockQty = Number(row?.stockQty ?? 0)
    if (stockQtyMin !== null && stockQty < stockQtyMin) return false
    if (stockQtyMax !== null && stockQty > stockQtyMax) return false
    if (!matchesDateRange(String(row?.stockEntryDate || '').trim(), dateRangeFilters.value.stockEntryDate)) return false
    if (!matchesDateRange(String(row?.lastPricingDate || '').trim(), dateRangeFilters.value.lastPricingDate)) return false
    return true
  })
})

const visibleRowIds = computed(() => filteredRows.value.map((row) => row.id))
const selectedRowCount = computed(() => Object.values(selectedMap.value).filter(Boolean).length)
const selectedVisibleCount = computed(() => visibleRowIds.value.filter((id) => !!selectedMap.value[id]).length)
const allSelectedVisible = computed(() => visibleRowIds.value.length > 0 && selectedVisibleCount.value === visibleRowIds.value.length)
const someSelectedVisible = computed(() => selectedVisibleCount.value > 0)
const hasMoreRows = computed(() => Boolean(store.hasMore))

function isHeaderFilterField (field) {
  return headerFilterFieldSet.has(field)
}

function isMultiSelectFilterField (field) {
  return multiSelectFilterFieldSet.has(field)
}

function isNumberRangeFilterField (field) {
  return numberRangeFilterFieldSet.has(field)
}

function isDateRangeFilterField (field) {
  return dateRangeFilterFieldSet.has(field)
}

function hasFilter (field) {
  if (isMultiSelectFilterField(field)) return (columnFilters.value[field] || []).length > 0
  if (isNumberRangeFilterField(field)) {
    const filter = numberRangeFilters.value[field]
    return !!String(filter?.min || '').trim() || !!String(filter?.max || '').trim()
  }
  if (isDateRangeFilterField(field)) {
    const filter = dateRangeFilters.value[field]
    return !!String(filter?.from || '').trim() || !!String(filter?.to || '').trim()
  }
  return false
}

function getFilterBadgeValue (field) {
  if (isMultiSelectFilterField(field)) return (columnFilters.value[field] || []).length
  if (isNumberRangeFilterField(field)) {
    const filter = numberRangeFilters.value[field]
    return [filter?.min, filter?.max].filter((x) => String(x || '').trim()).length
  }
  if (isDateRangeFilterField(field)) {
    const filter = dateRangeFilters.value[field]
    return [filter?.from, filter?.to].filter((x) => String(x || '').trim()).length
  }
  return 0
}

function clearColumnFilter (field) {
  if (!isMultiSelectFilterField(field)) return
  columnFilters.value = {
    ...columnFilters.value,
    [field]: []
  }
}

function clearRangeFilter (field) {
  if (isNumberRangeFilterField(field)) {
    numberRangeFilters.value = {
      ...numberRangeFilters.value,
      [field]: { min: '', max: '' }
    }
    return
  }
  if (isDateRangeFilterField(field)) {
    dateRangeFilters.value = {
      ...dateRangeFilters.value,
      [field]: { from: '', to: '' }
    }
  }
}

function getFilterOptionsForField (field) {
  return filteredFilterOptionMap.value[field] || []
}

function isColumnFilterValueSelected (field, value) {
  return (columnFilters.value[field] || []).includes(value)
}

function toggleColumnFilterValue (field, value) {
  const current = new Set(columnFilters.value[field] || [])
  if (current.has(value)) current.delete(value)
  else current.add(value)
  columnFilters.value = {
    ...columnFilters.value,
    [field]: Array.from(current)
  }
}

function selectAllColumnFilterOptions (field) {
  const options = getFilterOptionsForField(field)
  columnFilters.value = {
    ...columnFilters.value,
    [field]: options.map((option) => option.value)
  }
}

function extractWidth (style) {
  const m = String(style || '').match(/width:(\d+)px/)
  return m ? Number(m[1]) : 0
}

function isStickyCol (colName) {
  return stickyColumnNameSet.has(colName)
}

function isStickyBoundary (colName) {
  return colName === stickyBoundaryColumnName
}

function getHeaderCellStyle (col) {
  if (!isStickyCol(col.name)) return undefined
  return { left: `${stickyLeftMap.value[col.name] || 0}px`, zIndex: 22 }
}

function getBodyCellStyle (col) {
  if (!isStickyCol(col.name)) return undefined
  return { left: `${stickyLeftMap.value[col.name] || 0}px`, zIndex: 12 }
}

function round2 (value) {
  return Number(Number(value || 0).toFixed(2))
}

function parseNumber (val) {
  if (typeof val === 'number') return Number.isFinite(val) ? val : 0
  const text = String(val ?? '').trim().replace(/\s/g, '')
  if (!text) return 0

  const lastComma = text.lastIndexOf(',')
  const lastDot = text.lastIndexOf('.')
  let normalized = text

  if (lastComma >= 0 && lastDot >= 0) {
    if (lastComma > lastDot) {
      normalized = text.replace(/\./g, '').replace(',', '.')
    } else {
      normalized = text.replace(/,/g, '')
    }
  } else if (lastComma >= 0) {
    normalized = text.replace(/\./g, '').replace(',', '.')
  } else {
    normalized = text.replace(/,/g, '')
  }

  const n = Number(normalized)
  return Number.isFinite(n) ? n : 0
}

function parseNullableNumber (val) {
  const text = String(val ?? '').trim()
  if (!text) return null
  const n = parseNumber(text)
  return Number.isFinite(n) ? n : null
}

function matchesDateRange (value, filter) {
  const from = String(filter?.from || '').trim()
  const to = String(filter?.to || '').trim()
  if (!from && !to) return true
  if (!value) return false
  if (from && value < from) return false
  if (to && value > to) return false
  return true
}

function formatPrice (val) {
  const n = parseNumber(val)
  return n.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
}

function formatStock (val) {
  const n = Number(val || 0)
  if (!Number.isFinite(n)) return '0'
  const hasFraction = Math.abs(n % 1) > 0.0001
  return n.toLocaleString('tr-TR', {
    minimumFractionDigits: hasFraction ? 2 : 0,
    maximumFractionDigits: hasFraction ? 2 : 0
  })
}

function formatDateDisplay (val) {
  const text = String(val || '').trim()
  if (!text) return '-'
  const [year, month, day] = text.split('-')
  if (!year || !month || !day) return text
  return `${day}.${month}.${year}`
}

function needsRepricing (row) {
  const stockEntryDate = String(row?.stockEntryDate || '').trim()
  const lastPricingDate = String(row?.lastPricingDate || '').trim()
  if (!stockEntryDate) return false
  if (!lastPricingDate) return true
  return lastPricingDate < stockEntryDate
}

function recalcByBasePrice (row) {
  row.basePriceTry = round2((row.basePriceUsd * usdToTry) + row.expenseForBasePrice)
  multipliers.forEach((multiplier, index) => {
    row[`usd${index + 1}`] = round2(row.basePriceUsd * multiplier)
    row[`eur${index + 1}`] = round2((row.basePriceUsd * usdToTry * multiplier) / eurToTry)
    row[`try${index + 1}`] = round2(row.basePriceTry * multiplier)
  })
}

function onEditableCellChange (row, field, val) {
  const parsed = parseNumber(val)
  store.updateCell(row, field, parsed)
  if (field === 'expenseForBasePrice' || field === 'basePriceUsd') recalcByBasePrice(row)
}

function onBrandGroupSelectionChange (row, val) {
  store.updateBrandGroupSelection(row, val)
}

function toggleRowSelection (rowId, val) {
  selectedMap.value = { ...selectedMap.value, [rowId]: !!val }
}

function toggleSelectAllVisible (val) {
  const next = { ...selectedMap.value }
  visibleRowIds.value.forEach((id) => { next[id] = !!val })
  selectedMap.value = next
}

function resetAll () {
  columnFilters.value = {
    productCode: [],
    askiliYan: [],
    kategori: [],
    urunIlkGrubu: [],
    urunAnaGrubu: [],
    urunAltGrubu: [],
    icerik: [],
    karisim: []
  }
  columnFilterSearch.value = {
    productCode: '',
    askiliYan: '',
    kategori: '',
    urunIlkGrubu: '',
    urunAnaGrubu: '',
    urunAltGrubu: '',
    icerik: '',
    karisim: ''
  }
  numberRangeFilters.value = {
    stockQty: { min: '', max: '' }
  }
  dateRangeFilters.value = {
    stockEntryDate: { from: '', to: '' },
    lastPricingDate: { from: '', to: '' }
  }
  showSelectedOnly.value = false
  selectedMap.value = {}
}

function toggleShowSelectedOnly () {
  if (!showSelectedOnly.value && selectedRowCount.value === 0) return
  showSelectedOnly.value = !showSelectedOnly.value
}

function isCurrencySelected (code) {
  return selectedCurrencies.value.includes(code)
}

function toggleCurrency (code, checked) {
  const set = new Set(selectedCurrencies.value)
  if (checked) set.add(code)
  else set.delete(code)
  selectedCurrencies.value = currencyOptions.map((x) => x.value).filter((x) => set.has(x))
}

function toggleCurrencyRow (code) {
  toggleCurrency(code, !isCurrencySelected(code))
}

function selectAllCurrencies () {
  selectedCurrencies.value = currencyOptions.map((x) => x.value)
}

function clearAllCurrencies () {
  selectedCurrencies.value = []
}

async function fetchChunk ({ reset = false } = {}) {
  const afterProductCode = reset ? '' : nextCursor.value
  const result = await store.fetchRows({
    limit: FETCH_LIMIT,
    afterProductCode,
    append: !reset
  })
  const fetched = Number(result?.fetched) || 0
  nextCursor.value = String(result?.nextCursor || '')
  return fetched
}

async function loadMoreRows () {
  if (loadingMore.value || store.loading || !hasMoreRows.value) return
  loadingMore.value = true
  try {
    await fetchChunk({ reset: false })
  } finally {
    loadingMore.value = false
  }
}

function onTableVirtualScroll (details) {
  const to = Number(details?.to || 0)
  if (!Number.isFinite(to)) return
  if (to >= filteredRows.value.length - 25) {
    void loadMoreRows()
  }
}

async function ensureEnoughVisibleRows (minRows = 80, maxBatches = 4) {
  let guard = 0
  while (hasMoreRows.value && filteredRows.value.length < minRows && guard < maxBatches) {
    await loadMoreRows()
    guard++
  }
}

async function reloadData () {
  const startedAt = Date.now()
  console.info('[product-pricing][ui] reload:start', {
    at: new Date(startedAt).toISOString()
  })
  try {
    nextCursor.value = ''
    await fetchChunk({ reset: true })
    await ensureEnoughVisibleRows(120, 6)
  } catch (err) {
    console.error('[product-pricing][ui] reload:error', {
      duration_ms: Date.now() - startedAt,
      message: String(err?.message || err || 'reload failed')
    })
  }
  console.info('[product-pricing][ui] reload:done', {
    duration_ms: Date.now() - startedAt,
    row_count: Array.isArray(store.rows) ? store.rows.length : 0,
    has_error: Boolean(store.error)
  })
  selectedMap.value = {}
}

onMounted(async () => {
  await reloadData()
})

watch(
  [
    columnFilters,
    numberRangeFilters,
    dateRangeFilters,
    showSelectedOnly,
    () => tablePagination.value.sortBy,
    () => tablePagination.value.descending
  ],
  () => { void ensureEnoughVisibleRows(80, 4) },
  { deep: true }
)
</script>

<style scoped>
.pricing-page {
  --pricing-row-height: 31px;
  --pricing-header-height: 72px;
  --pricing-table-height: calc(100vh - 210px);

  height: calc(100vh - 120px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.currency-menu-list {
  min-width: 170px;
}

.table-wrap {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  border: 1px solid rgba(0, 0, 0, 0.12);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
}

.pane-table {
  height: 100%;
  width: 100%;
}

.pricing-table :deep(.q-table__middle) {
  height: var(--pricing-table-height);
  min-height: var(--pricing-table-height);
  max-height: var(--pricing-table-height);
  overflow: auto !important;
  scrollbar-gutter: stable both-edges;
  overscroll-behavior: contain;
}

.pricing-table :deep(.q-table) {
  width: max-content;
  min-width: 100%;
  table-layout: fixed;
  font-size: 11px;
  border-collapse: separate;
  border-spacing: 0;
  margin-right: var(--sticky-scroll-comp, 0px);
}

.pricing-table :deep(.q-table__container) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
  height: 100% !important;
}

.pricing-table :deep(th),
.pricing-table :deep(td) {
  box-sizing: border-box;
  padding: 0 4px;
  overflow: hidden;
  vertical-align: middle;
}

.pricing-table :deep(td),
.pricing-table :deep(.q-table tbody tr) {
  height: var(--pricing-row-height) !important;
  min-height: var(--pricing-row-height) !important;
  max-height: var(--pricing-row-height) !important;
  line-height: var(--pricing-row-height);
  padding: 0 !important;
  border-bottom: 1px solid rgba(0, 0, 0, 0.08) !important;
}

.pricing-table :deep(td > div),
.pricing-table :deep(td > .q-td) {
  height: 100% !important;
  display: flex !important;
  align-items: center !important;
  padding: 0 4px !important;
}

.pricing-table :deep(th),
.pricing-table :deep(.q-table thead tr),
.pricing-table :deep(.q-table thead tr.header-row-fixed),
.pricing-table :deep(.q-table thead th),
.pricing-table :deep(.q-table thead tr.header-row-fixed > th) {
  height: var(--pricing-header-height) !important;
  min-height: var(--pricing-header-height) !important;
  max-height: var(--pricing-header-height) !important;
}

.pricing-table :deep(th) {
  padding-top: 0;
  padding-bottom: 0;
  white-space: nowrap;
  word-break: normal;
  text-overflow: ellipsis;
  text-align: center;
  font-size: 10px;
  font-weight: 800;
  line-height: 1.15;
}

.pricing-table :deep(.q-table thead th) {
  position: sticky;
  top: 0;
  z-index: 30;
  background: #fff;
  vertical-align: middle !important;
}

.pricing-table :deep(.sticky-col) {
  position: sticky !important;
  background-clip: padding-box;
}

.pricing-table :deep(thead .sticky-col) {
  z-index: 35 !important;
}

.pricing-table :deep(tbody .sticky-col) {
  z-index: 12 !important;
}

.pricing-table :deep(.sticky-boundary) {
  border-right: 2px solid rgba(25, 118, 210, 0.18) !important;
  box-shadow: 8px 0 12px -10px rgba(15, 23, 42, 0.55);
}

.header-with-filter {
  display: grid;
  grid-template-columns: 1fr 20px;
  align-items: center;
  column-gap: 4px;
  height: 100%;
  line-height: 1.25;
  overflow: hidden;
}

.header-with-filter > span {
  min-width: 0;
  width: 100%;
  overflow: hidden;
  text-align: center;
  text-overflow: ellipsis;
  white-space: normal;
  font-weight: 800;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.header-filter-btn {
  width: 20px;
  height: 20px;
  min-width: 20px;
  justify-self: end;
}

.header-filter-ghost {
  opacity: 0;
  pointer-events: none;
}

.excel-filter-menu {
  min-width: 230px;
  padding: 8px;
}

.range-filter-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.range-filter-field {
  min-width: 0;
}

.excel-filter-select :deep(.q-field__control) {
  min-height: 30px;
}

.excel-filter-select :deep(.q-field__native),
.excel-filter-select :deep(.q-field__input) {
  font-weight: 700;
}

.excel-filter-actions {
  gap: 4px;
}

.excel-filter-options {
  max-height: 220px;
  margin-top: 8px;
  overflow: auto;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 4px;
}

.excel-filter-option {
  min-height: 32px;
}

.excel-filter-empty {
  padding: 10px 8px;
  color: #607d8b;
  font-size: 11px;
}

.pricing-table :deep(th.ps-col),
.pricing-table :deep(td.ps-col) {
  background: #fff;
  color: var(--q-primary);
  font-weight: 700;
}

.pricing-table :deep(td.ps-col .cell-text),
.pricing-table :deep(td.ps-col .product-code-text),
.pricing-table :deep(td.ps-col .stock-qty-text) {
  font-size: 11px;
  line-height: 1.1;
  white-space: normal;
  word-break: break-word;
}

.stock-qty-text {
  display: block;
  width: 100%;
  text-align: center;
  font-weight: 700;
  padding: 0 4px;
}

.date-cell-text {
  display: block;
  width: 100%;
  text-align: center;
  font-weight: 700;
  padding: 0 4px;
}

.date-warning {
  color: #c62828;
}

.pricing-table :deep(th.selection-col),
.pricing-table :deep(td.selection-col) {
  background: #fff;
  color: var(--q-primary);
  padding-left: 0 !important;
  padding-right: 0 !important;
}

.pricing-table :deep(th.selection-col) {
  text-align: center !important;
}

.pricing-table :deep(.selection-col .q-checkbox__inner) {
  color: var(--q-primary);
  font-size: 16px;
}

.pricing-table :deep(th.selection-col .q-checkbox),
.pricing-table :deep(td.selection-col .q-checkbox) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.pricing-table :deep(.selection-col .q-checkbox__bg) {
  background: #fff;
  border-color: var(--q-primary);
}

.pricing-table :deep(th.usd-col),
.pricing-table :deep(td.usd-col) {
  background: #ecf9f0;
  color: #178a3e;
  font-weight: 700;
}

.pricing-table :deep(th.eur-col),
.pricing-table :deep(td.eur-col) {
  background: #fdeeee;
  color: #c62828;
  font-weight: 700;
}

.pricing-table :deep(th.try-col),
.pricing-table :deep(td.try-col) {
  background: #edf4ff;
  color: #1e63c6;
  font-weight: 700;
}

.cell-text {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  line-height: 1.1;
  padding-top: 0;
}

.product-code-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
  font-weight: 700;
  letter-spacing: 0;
}

.native-cell-input,
.native-cell-select {
  width: 100%;
  height: 22px;
  box-sizing: border-box;
  padding: 1px 3px;
  border: 1px solid #cfd8dc;
  border-radius: 4px;
  background: #fff;
  font-size: 11px;
  margin: 0;
}

.native-cell-input:focus,
.native-cell-select:focus {
  outline: none;
  border-color: #1976d2;
}
</style>
