<template>
  <q-page
    v-if="canReadOrder"
    class="order-page q-pa-md"
    :style="{ '--grid-header-h': gridHeaderHeight }"
  >
    <div class="sticky-stack">
      <div class="filter-bar row q-col-gutter-md q-mb-sm">
        <div
          v-for="def in filterDefs"
          :key="def.key"
          class="col-12 col-md-3"
        >
          <q-select
            v-model="filters[def.key]"
            :options="filteredOptionLists[def.key] || []"
            :label="def.label"
            :multiple="isMultiFilter(def.key)"
            :use-chips="isMultiFilter(def.key)"
            filled
            dense
            clearable
            use-input
            use-selected
            input-debounce="250"
            :disable="isFilterDisabled(def.key)"
            :loading="loadingFilterOptions"
            @update:model-value="onFilterValueChange(def.key)"
            @filter="(val, update) => filterOptions(def.key, val, update)"
            @keyup.enter="fetchStockByAttributes"
          >
            <template v-if="isMultiFilter(def.key)" #before-options>
              <q-item clickable dense v-ripple @click.stop="selectAllFilterOptions(def.key)">
                <q-item-section>Tumunu Sec</q-item-section>
              </q-item>
              <q-item clickable dense v-ripple @click.stop="clearAllFilterOptions(def.key)">
                <q-item-section>Tumunu Temizle</q-item-section>
              </q-item>
              <q-separator />
            </template>
          </q-select>
        </div>

        <div class="col-auto">
          <q-btn
            color="primary"
            icon="search"
            label="Sorgula"
            :loading="loadingStock"
            :disable="!canQuery"
            @click="fetchStockByAttributes"
          />
        </div>

        <div class="col-auto">
          <q-btn
            flat
            color="grey-8"
            icon="restart_alt"
            label="Sıfırla"
            @click="resetForm"
          />
        </div>

        <div class="col-auto">
          <q-btn
            flat
            color="primary"
            icon="unfold_more"
            :label="allDetailsExpanded ? 'Tüm Depoları Kapat' : 'Tüm Depoları Göster'"
            :disable="!level1Groups.length"
            @click="toggleAllDetails"
          />
        </div>
      </div>

      <div class="save-toolbar">
        <div class="text-subtitle2 text-weight-bold">Ürün Özelliklerinden Stok Bul</div>
      </div>

      <div
        v-if="showGridHeader"
        class="order-grid-header"
      >
        <div class="col-fixed model">MODEL</div>
        <div class="col-fixed renk">RENK</div>
        <div class="col-fixed ana">ÜRÜN ANA GRUBU</div>
        <div class="col-fixed alt">ÜRÜN ALT GRUBU</div>
        <div class="col-fixed aciklama-col">AÇIKLAMA</div>

        <div class="beden-block">
          <div class="grp-row">
            <div class="grp-title">{{ activeSchema?.title || 'BEDEN' }}</div>
            <div class="grp-body">
              <div
                v-for="v in sizeLabels"
                :key="'hdr-' + activeGrpKey + '-' + v"
                class="grp-cell hdr"
              >
                {{ v }}
              </div>
            </div>
          </div>
        </div>

        <div class="total-row">
          <div class="total-cell">ADET</div>
          <div class="total-cell">FOTO</div>
        </div>
      </div>
    </div>

    <q-banner
      v-if="errorMessage"
      class="bg-red-1 text-negative q-my-sm rounded-borders"
      dense
    >
      {{ errorMessage }}
    </q-banner>

    <q-banner
      v-else-if="!loadingStock && !level1Groups.length"
      class="bg-blue-1 text-primary q-my-sm rounded-borders"
      dense
    >
      Ürün özelliği seçip sorgulayın.
    </q-banner>

    <div class="order-scroll-y">
<div v-if="level1Groups.length" class="order-grid-body">
        <template v-for="grp1 in level1Groups" :key="grp1.key">
            <div class="summary-group open">
            <div class="order-sub-header level-1" @click="toggleOpen(grp1.key)">
              <div class="sub-col level1-merged">
                <div class="text-weight-bold">{{ grp1.productCode }}</div>
                <div class="text-caption">{{ grp1.productDesc || '-' }}</div>
              </div>

              <div class="sub-center level1-center">
                <div class="beden-row values-top">
                  <div v-for="sz in sizeLabels" :key="`v1-${grp1.key}-${sz}`" class="beden-cell">
                    {{ Number(grp1.sizeTotals[sz] || 0) > 0 ? formatNumber(grp1.sizeTotals[sz]) : '' }}
                  </div>
                </div>
                <div class="beden-row headers">
                  <div v-for="sz in sizeLabels" :key="`h1-${grp1.key}-${sz}`" class="beden-cell">
                    {{ sz }}
                  </div>
                </div>
              </div>

              <div class="sub-right level1-right">
                <div class="top-total">{{ formatNumber(grp1.totalQty) }}</div>
                <div class="bottom-row">
                  <div class="bottom-label">ADET</div>
                </div>
                <div class="icon-row">
                  <q-icon :name="isOpen(grp1.key) ? 'expand_less' : 'expand_more'" size="18px" />
                </div>
              </div>
            </div>

            <template v-if="isOpen(grp1.key)">
              <template v-for="grp2 in grp1.children" :key="grp2.key">
                <div class="order-sub-header level-2" @click="onLevel2Click(grp1.productCode, grp2)">
                  <div class="sub-col model">{{ grp1.productCode || '-' }}</div>
                  <div class="sub-col renk">
                    <div class="renk-kodu">{{ grp2.colorCode || '-' }}{{ grp2.secondColor ? '-' + grp2.secondColor : '' }}</div>
                    <div class="renk-aciklama">{{ grp2.colorDesc || '-' }}</div>
                  </div>
                  <div class="sub-col ana">{{ grp2.urunAnaGrubu || '-' }}</div>
                  <div class="sub-col alt">{{ grp2.urunAltGrubu || '-' }}</div>
                  <div class="sub-col aciklama">{{ grp2.aciklama || '-' }}</div>

                  <div class="sub-center level2-center">
                    <div class="beden-row values-top">
                      <div v-for="sz in sizeLabels" :key="`top2-${grp2.key}-${sz}`" class="beden-cell">
                        {{ Number(grp2.sizeTotals[sz] || 0) > 0 ? formatNumber(grp2.sizeTotals[sz]) : '' }}
                      </div>
                    </div>
                    <div class="beden-row headers">
                      <div v-for="sz in sizeLabels" :key="`h2-${grp2.key}-${sz}`" class="beden-cell">
                        {{ sz }}
                      </div>
                    </div>
                  </div>

                  <div class="sub-right level2-right">
                    <div class="top-total">{{ formatNumber(grp2.totalQty) }}</div>
                    <div class="bottom-row">
                      <div class="bottom-label">ADET</div>
                      <q-icon :name="isOpen(grp2.key) ? 'expand_less' : 'expand_more'" size="18px" />
                    </div>
                  </div>

                  <div class="sub-image level2-image">
                    <q-card flat bordered class="product-image-card cursor-pointer" @click.stop="openProductCard(grp1, grp2)">
                      <q-card-section class="q-pa-xs product-image-wrap">
                        <q-img
                          v-if="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
                          :src="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
                          fit="contain"
                          class="product-image"
                          loading="lazy"
                          @error="onProductImageError(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
                        />
                        <div v-else class="product-image-placeholder">
                          <q-icon name="image_not_supported" size="22px" color="grey-6" />
                        </div>
                      </q-card-section>
                    </q-card>
                    <q-btn
                      dense
                      flat
                      color="primary"
                      label="Urun Detayi Gor"
                      class="detail-open-btn"
                      @click.stop="openProductCard(grp1, grp2)"
                    />
                  </div>
                </div>

                <template v-if="isOpen(grp2.key)">
                  <div class="detail-table-wrap">
                    <div
                      v-for="row in buildLevel2Rows(grp2)"
                      :key="row.rowKey"
                      class="summary-row"
                    >
                      <div class="cell depo-merged">{{ row.depoAdi || '-' }}</div>

                      <div class="grp-area">
                        <div class="grp-row">
                          <div
                            v-for="v in sizeLabels"
                            :key="row.rowKey + '-sz-' + v"
                            class="cell beden"
                          >
                            {{ resolveBedenValue(row.bedenMap, row.grpKey, v) }}
                          </div>
                        </div>
                      </div>

                      <div class="cell adet">{{ formatNumber(row.adet) }}</div>
                      <div class="cell img-placeholder"></div>
                    </div>
                  </div>
                </template>
              </template>
            </template>
          </div>
        </template>
      </div>
    </div>

    <q-dialog v-model="productCardDialog" maximized @hide="onProductCardDialogHide">
      <q-card class="product-card-dialog">
        <q-card-section class="row items-center q-pb-sm">
          <div class="text-h6">Urun Karti</div>
          <q-space />
          <q-btn icon="close" flat round dense v-close-popup />
        </q-card-section>

        <q-separator />

        <q-card-section class="q-pt-md">
          <div class="product-card-content">
            <div class="product-card-images">
              <q-carousel
                v-if="productCardImages.length"
                v-model="productCardSlide"
                animated
                swipeable
                navigation
                arrows
                height="100%"
                class="product-card-carousel rounded-borders"
                @update:model-value="onProductCardSlideChange"
              >
                <q-carousel-slide
                  v-for="(img, idx) in productCardImages"
                  :key="'img-' + idx"
                  :name="idx"
                  class="column no-wrap flex-center"
                >
                  <div class="dialog-image-stage cursor-pointer" @click="openProductImageFullscreen(img)">
                    <q-img :src="img" fit="contain" class="dialog-image" />
                  </div>
                </q-carousel-slide>
              </q-carousel>
              <div v-else class="dialog-image-empty">
                <q-icon name="image_not_supported" size="36px" color="grey-6" />
              </div>
            </div>

            <div class="product-card-fields">
              <div class="field-row field-row-head"><span class="k">Urun</span><span class="v">{{ productCardData.productCode || '-' }} / {{ productCardData.colorCode || '-' }}{{ productCardData.secondColor ? '-' + productCardData.secondColor : '' }}</span></div>
              <div class="field-row"><span class="k">Urun Kodu</span><span class="v">{{ productCardData.productCode || '-' }}</span></div>
              <div class="field-row"><span class="k">Urun Renk</span><span class="v">{{ productCardData.colorCode || '-' }}</span></div>
              <div class="field-row"><span class="k">Urun 2.Renk</span><span class="v">{{ productCardData.secondColor || '-' }}</span></div>
              <div class="field-row"><span class="k">Kategori</span><span class="v">{{ productCardData.kategori || '-' }}</span></div>
              <div class="field-row"><span class="k">Urun Ana Grubu</span><span class="v">{{ productCardData.urunAnaGrubu || '-' }}</span></div>
              <div class="field-row"><span class="k">Urun Alt Grubu</span><span class="v">{{ productCardData.urunAltGrubu || '-' }}</span></div>
              <div class="field-row"><span class="k">Urun Icerigi</span><span class="v">{{ productCardData.urunIcerigi || '-' }}</span></div>
              <div class="field-row"><span class="k">Fit</span><span class="v">{{ productCardData.fit || '-' }}</span></div>
              <div class="field-row"><span class="k">Drop</span><span class="v">{{ productCardData.drop || '-' }}</span></div>
              <div class="field-row"><span class="k">Kumas</span><span class="v">{{ productCardData.kumas || '-' }}</span></div>
              <div class="field-row"><span class="k">Karisim</span><span class="v">{{ productCardData.karisim || '-' }}</span></div>

              <div class="product-card-stock-inline q-mt-md">
                <div class="text-subtitle2 text-weight-bold">Stok Ozet</div>
                <div class="text-caption">Toplam Stok: {{ formatNumber(productCardData.totalQty || 0) }}</div>
                <div class="stock-size-grid q-mt-sm">
                  <div v-for="sz in sizeLabels" :key="'dlg-sz-' + sz" class="stock-size-chip">
                    <span class="label">{{ sz }}</span>
                    <span class="value">{{ Number(productCardData.sizeTotals?.[sz] || 0) > 0 ? formatNumber(productCardData.sizeTotals[sz]) : '-' }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </q-card-section>
      </q-card>
    </q-dialog>

    <q-dialog v-model="productImageFullscreenDialog" maximized @hide="onFullscreenDialogHide">
      <q-card class="image-fullscreen-dialog">
        <q-card-section class="row items-center q-pb-sm">
          <div class="text-h6">Urun Fotografi</div>
          <q-space />
          <q-btn icon="close" flat round dense v-close-popup />
        </q-card-section>
        <q-separator />
        <q-card-section class="image-fullscreen-body">
          <q-carousel
            v-if="fullscreenImages.length"
            v-model="productImageFullscreenSlide"
            animated
            swipeable
            navigation
            arrows
            height="calc(100vh - 120px)"
            class="image-fullscreen-carousel"
            @update:model-value="onFullscreenSlideChange"
          >
            <q-carousel-slide
              v-for="(img, idx) in fullscreenImages"
              :key="'full-img-' + idx"
              :name="idx"
              class="column no-wrap flex-center"
            >
              <div
                class="image-fullscreen-stage"
                @wheel.prevent="onFullscreenWheel"
                @mousedown="onFullscreenMouseDown"
                @dblclick="toggleFullscreenImageZoom"
              >
                <q-img
                  :src="img"
                  fit="contain"
                  class="image-fullscreen-img"
                  :style="fullscreenImageStyle"
                />
              </div>
            </q-carousel-slide>
          </q-carousel>
        </q-card-section>
      </q-card>
    </q-dialog>
  </q-page>

  <q-page v-else class="q-pa-md flex flex-center">
    <div class="text-negative text-subtitle1">Bu modüle erişim yetkiniz yok.</div>
  </q-page>
</template>

<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useQuasar } from 'quasar'
import api from 'src/services/api'
import { usePermission } from 'src/composables/usePermission'
import { normalizeSearchText } from 'src/utils/searchText'
import {
  detectBedenGroup,
  normalizeBedenLabel,
  schemaByKey as storeSchemaByKey,
  useOrderEntryStore
} from 'src/stores/orderentryStore'

const $q = useQuasar()
const { canRead } = usePermission()
const canReadOrder = canRead('order')
const orderStore = useOrderEntryStore()

const filterDefs = [
  { key: 'kategori', label: 'Kategori' },
  { key: 'urun_ana_grubu', label: 'Urun Ana Grubu' },
  { key: 'urun_alt_grubu', label: 'Urun Alt Grubu' },
  { key: 'renk', label: 'Renk' },
  { key: 'renk2', label: '2.Renk' },
  { key: 'urun_icerigi', label: 'Urun Icerigi' },
  { key: 'fit', label: 'Fit' },
  { key: 'drop', label: 'Drop' },
  { key: 'beden', label: 'Beden' }
]
const singleSelectFilterKeys = new Set(['kategori', 'urun_ana_grubu'])
const multiSelectFilterKeys = new Set(
  filterDefs.map((def) => def.key).filter((key) => !singleSelectFilterKeys.has(key))
)
const filterValueSeparator = '\u001f'

const loadingFilterOptions = ref(false)
const loadingStock = ref(false)
const errorMessage = ref('')
const filters = ref(createEmptyFilters())
const optionLists = ref({})
const filteredOptionLists = ref({})
const filterOptionsCache = ref({})
const rawRows = ref([])
const productImageCache = ref({})
const productImageLoading = ref({})
const productImageListByCode = ref({})
const productImageListLoading = ref({})
const productImageFallbackByKey = ref({})
const productImageContentLoading = ref({})
const productImageListBlockedUntil = ref(0)
const productCardDialog = ref(false)
const productCardData = ref({})
const productCardImages = ref([])
const productCardSlide = ref(0)
const productImageFullscreenDialog = ref(false)
const productImageFullscreenSrc = ref('')
const productImageFullscreenSlide = ref(0)
const productImageFullscreenZoom = ref(1)
const productImageFullscreenOffsetX = ref(0)
const productImageFullscreenOffsetY = ref(0)
const productImageFullscreenDragging = ref(false)
const productImageFullscreenDragStartX = ref(0)
const productImageFullscreenDragStartY = ref(0)
const productImageFullscreenDragOriginX = ref(0)
const productImageFullscreenDragOriginY = ref(0)
const IMAGE_LIST_CONCURRENCY = 8
const FILTER_OPTIONS_CACHE_TTL_MS = 60 * 1000
const FILTER_OPTIONS_DEBOUNCE_MS = 250
let imageListActiveRequests = 0
let productImageBatchTimer = null
const productImageBatchQueue = new Map()
let filterOptionsDebounceTimer = null
let filterOptionsRequestSeq = 0
const imageListWaitQueue = []
const activeSchema = ref(storeSchemaByKey.tak)
const activeGrpKey = ref('tak')
const openState = ref({})
const canQuery = computed(() =>
  normalizeFilterScalar(filters.value?.kategori) !== '' &&
  normalizeFilterScalar(filters.value?.urun_ana_grubu) !== ''
)

const sizeLabels = computed(() => activeSchema.value?.values || [])
const showGridHeader = computed(() =>
  !loadingStock.value && level1Groups.value.length > 0
)
const allDetailsExpanded = computed(() => {
  const groups = level1Groups.value || []
  if (!groups.length) return false
  const detailKeys = []
  for (const g1 of groups) {
    for (const g2 of g1.children || []) {
      detailKeys.push(g2.key)
      for (const g3 of g2.children || []) detailKeys.push(g3.key)
    }
  }
  if (!detailKeys.length) return false
  return detailKeys.every((k) => openState.value[k] === true)
})
const gridHeaderHeight = computed(() =>
  showGridHeader.value ? '56px' : '0px'
)
const fullscreenImageStyle = computed(() => ({
  transform: `translate(${productImageFullscreenOffsetX.value}px, ${productImageFullscreenOffsetY.value}px) scale(${productImageFullscreenZoom.value})`,
  transformOrigin: 'center center',
  transition: productImageFullscreenDragging.value ? 'none' : 'transform 0.1s ease-out',
  cursor: productImageFullscreenZoom.value > 1 ? (productImageFullscreenDragging.value ? 'grabbing' : 'grab') : 'zoom-in'
}))

const fullscreenImages = computed(() => {
  const arr = Array.isArray(productCardImages.value) ? productCardImages.value : []
  if (arr.length) return arr
  const single = String(productImageFullscreenSrc.value || '').trim()
  return single ? [single] : []
})

function emptySizeTotals() {
  const map = {}
  for (const s of sizeLabels.value) map[s] = 0
  return map
}

function parseNumber(value) {
  if (typeof value === 'number') return Number.isFinite(value) ? value : 0
  const text = String(value ?? '').trim()
  if (!text) return 0
  const normalized = text.replace(/\./g, '').replace(',', '.')
  const n = Number.parseFloat(normalized)
  return Number.isFinite(n) ? n : 0
}

function firstText(...values) {
  for (const value of values) {
    const s = String(value || '').trim()
    if (s) return s
  }
  return ''
}

function resolveKumasValue(item) {
  return firstText(
    item?.BIRINCI_PARCA_KUMAS,
    item?.ProductAtt26Desc,
    item?.PRODUCTATT26DESC,
    item?.ProductAtt29Desc,
    item?.PRODUCTATT29DESC
  )
}

function resolveKarisimValue(item) {
  return firstText(
    item?.BIRINCI_PARCA_KARISIM,
    item?.ProductAtt29Desc,
    item?.PRODUCTATT29DESC,
    item?.ProductAtt26Desc,
    item?.PRODUCTATT26DESC
  )
}

function sortByTotalQtyDesc(a, b) {
  const qa = Number(a?.totalQty || 0)
  const qb = Number(b?.totalQty || 0)
  if (qb !== qa) return qb - qa
  return String(a?.key || '').localeCompare(String(b?.key || ''), 'tr', { sensitivity: 'base' })
}

function buildImageKey(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
  return `${String(code || '').trim().toUpperCase()}::${String(color || '').trim().toUpperCase()}::${String(secondColor || '').trim().toUpperCase()}::${String(dim1Id || '').trim().toUpperCase()}::${String(dim3Id || '').trim().toUpperCase()}`
}

function normalizeImageDim3(value) {
  const s = String(value || '').trim().toUpperCase()
  if (!s) return ''
  if (/^\d{3}(?:_\d+)?$/.test(s)) return s
  return ''
}

function resolvePhotoDim3(item, secondColorDisplay = '') {
  return (
    normalizeImageDim3(item?.Renk2) ||
    normalizeImageDim3(item?.ItemDim3Code) ||
    normalizeImageDim3(secondColorDisplay) ||
    ''
  )
}

function resolvePhotoDim1ID(item) {
  const candidates = [
    item?.PhotoDim1ID,
    item?.photoDim1ID,
    item?.Dim1ID,
    item?.dim1ID,
    item?.ColorID,
    item?.colorID,
    item?.RenkID
  ]
  for (const value of candidates) {
    const s = String(value || '').trim()
    if (/^\d+$/.test(s)) return s
  }
  return ''
}

function resolvePhotoDim3ID(item) {
  const candidates = [
    item?.PhotoDim3ID,
    item?.photoDim3ID,
    item?.Dim3ID,
    item?.dim3ID,
    item?.SecondColorID,
    item?.secondColorID,
    item?.Renk2ID
  ]
  for (const value of candidates) {
    const s = String(value || '').trim()
    if (/^\d+$/.test(s)) return s
  }
  return ''
}

function buildDim3Candidates(secondColor) {
  const secondTrim = normalizeImageDim3(secondColor)
  if (!secondTrim) return ['']
  const set = new Set([secondTrim])
  if (/^\d{3}$/.test(secondTrim)) set.add(`${secondTrim}_1`)
  return Array.from(set)
}

async function fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IdTrim = '', dim3IdTrim = '') {
  const dim3Candidates = buildDim3Candidates(secondTrim)
  for (const dim3Candidate of dim3Candidates) {
    const params = { code: codeTrim, dim1: colorTrim }
    if (String(dim1IdTrim || '').trim()) params.dim1_id = String(dim1IdTrim || '').trim()
    if (String(dim3IdTrim || '').trim()) params.dim3_id = String(dim3IdTrim || '').trim()
    if (dim3Candidate) params.dim3 = dim3Candidate
    const res = await api.get('/product-images', { params })
    const list = Array.isArray(res?.data) ? res.data : []
    if (list.length) return list
  }
  return []
}

function normalizeUploadsPath(storagePath) {
  const raw = String(storagePath || '').trim()
  if (!raw) return ''
  const normalized = raw.replace(/\\/g, '/')
  const idx = normalized.toLowerCase().indexOf('/uploads/')
  if (idx >= 0) {
    return normalized.slice(idx)
  }
  if (normalized.toLowerCase().startsWith('uploads/')) {
    return `/${normalized}`
  }
  return ''
}

function resolveProductImageUrl(item) {
  if (!item || typeof item !== 'object') {
    return { contentUrl: '', publicUrl: '', thumbUrl: '', fullUrl: '' }
  }

  let contentUrl = ''
  const contentURL = String(item.content_url || item.ContentURL || '').trim()
  if (contentURL.startsWith('/api/')) contentUrl = contentURL
  else if (contentURL.startsWith('/')) contentUrl = `/api${contentURL}`

  const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
  let publicUrl = ''
  if (uploadsPath) {
    publicUrl = uploadsPath
  } else {
    const fileName = String(item.file_name || item.FileName || '').trim()
    if (fileName) {
      publicUrl = `/uploads/image/${fileName}`
    }
  }

  const thumbUrl = String(item.thumb_url || item.thumbUrl || '').trim()
  const fullUrl = String(item.full_url || item.fullUrl || '').trim()

  return { contentUrl, publicUrl, thumbUrl, fullUrl }
}

function sortImagesForDisplay(list) {
  // #gallery-1 mantigi icin frontend render sirasini (API'den gelen sira) koruyoruz.
  return Array.isArray(list) ? [...list] : []
}

function getHashRouteParts() {
  if (typeof window === 'undefined') return { path: '', params: new URLSearchParams() }
  const rawHash = String(window.location.hash || '')
  const hashBody = rawHash.startsWith('#') ? rawHash.slice(1) : rawHash
  const qPos = hashBody.indexOf('?')
  const path = qPos >= 0 ? hashBody.slice(0, qPos) : hashBody
  const query = qPos >= 0 ? hashBody.slice(qPos + 1) : ''
  return { path, params: new URLSearchParams(query) }
}

function replaceHashRouteQuery(key, value) {
  if (typeof window === 'undefined') return
  const { path, params } = getHashRouteParts()
  if (!path) return
  if (value === null || value === undefined || String(value).trim() === '') params.delete(key)
  else params.set(key, String(value).trim())
  const nextQuery = params.toString()
  const nextHash = `#${path}${nextQuery ? `?${nextQuery}` : ''}`
  if (window.location.hash === nextHash) return
  window.history.replaceState(null, '', `${window.location.pathname}${window.location.search}${nextHash}`)
}

function getGalleryQueryIndex() {
  const { params } = getHashRouteParts()
  const n = Number(params.get('g') || 1)
  if (!Number.isFinite(n) || n < 1) return 0
  return n - 1
}

function setGalleryQueryIndex(index) {
  replaceHashRouteQuery('g', Math.max(1, Number(index || 0) + 1))
}

function clearGalleryQueryIndex() {
  replaceHashRouteQuery('g', null)
}

async function resolveProductImageUrlForCarousel(item) {
  const resolved = resolveProductImageUrl(item)
  const contentUrl = String(resolved.contentUrl || '').trim()
  if (contentUrl) return contentUrl

  const directUrl = String(resolved.fullUrl || resolved.thumbUrl || resolved.publicUrl || '').trim()
  if (directUrl) return directUrl

  return ''
}

function getProductImageUrl(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
  const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
  const existing = productImageCache.value[key]
  if (existing !== undefined) return existing || ''
  queueProductImageBatch(code, color, secondColor, dim1Id, dim3Id)
  return ''
}

function queueProductImageBatch(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
  const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
  const codeTrim = String(code || '').trim().toUpperCase()
  if (!codeTrim || productImageCache.value[key] !== undefined || productImageLoading.value[key]) return
  productImageLoading.value[key] = true
  productImageBatchQueue.set(key, {
    key,
    code: codeTrim,
    dim1: String(dim1Id || color || '').trim().toUpperCase(),
    dim3: String(dim3Id || secondColor || '').trim().toUpperCase(),
    listKey: buildImageKey(
      codeTrim,
      String(color || '').trim().toUpperCase(),
      String(secondColor || '').trim().toUpperCase(),
      String(dim1Id || '').trim().toUpperCase(),
      String(dim3Id || '').trim().toUpperCase()
    )
  })
  if (productImageBatchTimer) window.clearTimeout(productImageBatchTimer)
  productImageBatchTimer = window.setTimeout(flushProductImageBatch, 80)
}

async function flushProductImageBatch() {
  const batch = Array.from(productImageBatchQueue.values()).slice(0, 250)
  for (const item of batch) productImageBatchQueue.delete(item.key)
  if (!batch.length) return
  try {
    const res = await api.post('/product-images/batch', {
      items: batch.map(item => ({ key: item.key, code: item.code, dim1: item.dim1, dim3: item.dim3 }))
    }, { timeout: 30000 })
    const returned = new Set()
    for (const item of Array.isArray(res?.data) ? res.data : []) {
      const key = String(item?.key || '').trim()
      if (!key) continue
      returned.add(key)
      const queued = batch.find(entry => entry.key === key)
      const list = Array.isArray(item.images) ? item.images : []
      const first = list[0] || null
      const resolved = resolveProductImageUrl(first)
      const url = resolved.contentUrl || resolved.thumbUrl || resolved.fullUrl || resolved.publicUrl || ''
      productImageCache.value[key] = String(url || '').trim()
      productImageFallbackByKey.value[key] = resolved.thumbUrl || resolved.fullUrl || resolved.publicUrl || ''
      if (queued) productImageListByCode.value[queued.listKey] = list
      delete productImageLoading.value[key]
    }
    for (const item of batch) {
      if (!returned.has(item.key)) {
        productImageCache.value[item.key] = ''
        productImageListByCode.value[item.listKey] = []
        delete productImageLoading.value[item.key]
      }
    }
  } catch {
    for (const item of batch) {
      delete productImageLoading.value[item.key]
      void ensureProductImage(item.code, item.dim1, item.dim3)
    }
  }
}

async function onProductImageError(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
  const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
  productImageCache.value[key] = String(productImageFallbackByKey.value[key] || '').trim()
}

async function ensureProductImage(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
  const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
  const codeTrim = String(code || '').trim().toUpperCase()
  const colorTrim = String(color || '').trim().toUpperCase()
  const secondTrim = String(secondColor || '').trim().toUpperCase()
  const dim1IDTrim = String(dim1Id || '').trim().toUpperCase()
  const dim3IDTrim = String(dim3Id || '').trim().toUpperCase()
  const listKey = buildImageKey(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
  if (!codeTrim) {
    productImageCache.value[key] = ''
    return ''
  }
  if (Date.now() < Number(productImageListBlockedUntil.value || 0)) {
    productImageCache.value[key] = ''
    return ''
  }
  if (productImageCache.value[key] !== undefined) return productImageCache.value[key] || ''
  if (productImageLoading.value[key]) return ''

  productImageLoading.value[key] = true
  try {
    if (!productImageListByCode.value[listKey]) {
      if (!productImageListLoading.value[listKey]) {
        productImageListLoading.value[listKey] = true
        try {
          if (imageListActiveRequests >= IMAGE_LIST_CONCURRENCY) {
            await new Promise((resolve) => imageListWaitQueue.push(resolve))
          }
          imageListActiveRequests++
          productImageListByCode.value[listKey] = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
        } catch (err) {
          productImageListByCode.value[listKey] = []
          const status = Number(err?.response?.status || 0)
          if (status >= 500 || status === 403 || status === 0) {
            // Backend dengesizken istek firtinasini kisaca kes.
            productImageListBlockedUntil.value = Date.now() + 30 * 1000
          }
          console.warn('[ProductStockByAttributes] product image list fetch failed', { code: codeTrim, color: colorTrim, secondColor: secondTrim, err })
        } finally {
          imageListActiveRequests = Math.max(0, imageListActiveRequests - 1)
          const nextInQueue = imageListWaitQueue.shift()
          if (nextInQueue) nextInQueue()
          delete productImageListLoading.value[listKey]
        }
      } else {
        // Ayni code icin baska bir istek zaten calisiyorsa tamamlanmasini bekle.
        while (productImageListLoading.value[listKey]) {
          await new Promise((resolve) => setTimeout(resolve, 25))
        }
      }
    }
    const rawList = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
    const sortedList = sortImagesForDisplay(rawList)
    const primaryItem = sortedList[0] || null
    const secondaryItem = sortedList.length > 1 ? sortedList[sortedList.length - 1] : null

    const primaryResolved = resolveProductImageUrl(primaryItem)
    let preferredCardUrl = primaryItem ? await resolveProductImageUrlForCarousel(primaryItem) : ''
    if (!preferredCardUrl && secondaryItem) {
      preferredCardUrl = await resolveProductImageUrlForCarousel(secondaryItem)
    }
    const secondaryResolved = resolveProductImageUrl(secondaryItem)

    productImageCache.value[key] = String(
      preferredCardUrl ||
      primaryResolved.contentUrl || primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.thumbUrl ||
      secondaryResolved.contentUrl || secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.thumbUrl ||
      ''
    ).trim()
    productImageFallbackByKey.value[key] = primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.thumbUrl || secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.thumbUrl || ''
  } catch (err) {
    console.warn('[ProductStockByAttributes] product image fetch failed', { code, color, err })
    productImageCache.value[key] = ''
    productImageFallbackByKey.value[key] = ''
  } finally {
    delete productImageLoading.value[key]
  }

  return productImageCache.value[key] || ''
}

function formatNumber(v) {
  return parseNumber(v).toLocaleString('tr-TR', { minimumFractionDigits: 0, maximumFractionDigits: 2 })
}

function normalizeSize(v) {
  return normalizeBedenLabel(v)
}

function resolveBedenValue(bedenMap, grpKey, bedenLabel) {
  const map = bedenMap?.[grpKey]
  if (!map || typeof map !== 'object') return 0
  return Number(map[bedenLabel] || 0)
}

function isOpen(key) {
  return openState.value[key] !== false
}

function toggleOpen(key) {
  openState.value[key] = !isOpen(key)
}


function initOpenState(groups, expandDetails = false) {
  const next = {}
  for (const g1 of groups) {
    next[g1.key] = true
    for (const g2 of g1.children) {
      next[g2.key] = expandDetails
      for (const g3 of g2.children) {
        next[g3.key] = expandDetails
      }
    }
  }
  openState.value = next
}

function expandAllDetails() {
  initOpenState(level1Groups.value || [], true)
}

function collapseAllDetails() {
  initOpenState(level1Groups.value || [], false)
}

function toggleAllDetails() {
  if (allDetailsExpanded.value) {
    collapseAllDetails()
    return
  }
  expandAllDetails()
}

function buildLevel3Rows(grp3) {
  const byKey = new Map()
  const gk = activeGrpKey.value
  if (!gk) return []

  for (const item of grp3.items || []) {
    const model = String(item.Urun_Kodu || '').trim()
    const renk = String(item.Renk_Kodu || '').trim()
    const renk2 = String(item.Yaka || '').trim()
    const urunAnaGrubu = String(item.URUN_ANA_GRUBU || '').trim()
    const urunAltGrubu = String(item.URUN_ALT_GRUBU || '').trim()
    const aciklama = String(item.Madde_Aciklamasi || '').trim()
    const beden = normalizeSize(item.Beden || '')
    const qty = parseNumber(item.Kullanilabilir_Envanter)

    const rowKey = [model, renk, renk2, grp3.depoKodu || '', grp3.depoAdi || ''].join('|')
    if (!byKey.has(rowKey)) {
      byKey.set(rowKey, {
        rowKey,
        model,
        renk,
        renk2,
        urunAnaGrubu,
        urunAltGrubu,
        aciklama,
        grpKey: gk,
        bedenMap: { [gk]: {} },
        adet: 0,
        depoAdi: grp3.depoAdi || '-'
      })
    }

    const row = byKey.get(rowKey)
    row.bedenMap[gk][beden] = Number(row.bedenMap[gk][beden] || 0) + qty
    row.adet += qty
  }

  return Array.from(byKey.values())
}

function buildLevel2Rows(grp2) {
  const merged = []
  for (const grp3 of grp2.children || []) {
    merged.push(...buildLevel3Rows(grp3))
  }
  return merged
}

const level1Groups = computed(() => {
  const l1Map = new Map()

  for (const item of rawRows.value) {
    const productCode = String(item.Urun_Kodu || '').trim()
    const productDesc = String(item.Madde_Aciklamasi || '').trim()
    const colorCode = String(item.Renk_Kodu || '').trim()
    const colorDesc = String(item.Renk_Aciklamasi || '').trim()
    const secondColor = String(item.Yaka || '').trim()
    const photoDim3 = resolvePhotoDim3(item, secondColor)
    const photoDim1ID = resolvePhotoDim1ID(item)
    const photoDim3ID = resolvePhotoDim3ID(item)
    const depoKodu = String(item.Depo_Kodu || '').trim()
    const depoAdi = String(item.Depo_Adi || '').trim()
    const urunAnaGrubu = String(item.URUN_ANA_GRUBU || '').trim()
    const urunAltGrubu = String(item.URUN_ALT_GRUBU || '').trim()
    const urunIcerigi = String(item.URUN_ICERIGI || item.KISA_KAR || '').trim()
    const fit = String(item.BIRINCI_PARCA_FIT || '').trim()
    const drop = String(item.DR || '').trim()
    const kumas = resolveKumasValue(item)
    const karisim = resolveKarisimValue(item)
    const aciklama = String(item.Madde_Aciklamasi || '').trim()
    const beden = normalizeSize(item.Beden || '')
    const qty = parseNumber(item.Kullanilabilir_Envanter)

    if (!l1Map.has(productCode)) {
      l1Map.set(productCode, {
        key: `L1|${productCode}`,
        productCode,
        productDesc,
        sizeTotals: emptySizeTotals(),
        totalQty: 0,
        childrenMap: new Map()
      })
    }
    const l1 = l1Map.get(productCode)
    if (Object.prototype.hasOwnProperty.call(l1.sizeTotals, beden)) {
      l1.sizeTotals[beden] += qty
    }
    l1.totalQty += qty

    const l2Key = `${colorCode}|${secondColor}|${photoDim3}|${photoDim1ID}|${photoDim3ID}`
    if (!l1.childrenMap.has(l2Key)) {
        l1.childrenMap.set(l2Key, {
          key: `L2|${productCode}|${l2Key}`,
          colorCode,
          colorDesc,
          secondColor,
          photoDim3,
          photoDim1ID,
          photoDim3ID,
          urunAnaGrubu,
          urunAltGrubu,
          urunIcerigi,
          fit,
          drop,
          kumas,
          karisim,
          aciklama,
          sizeTotals: emptySizeTotals(),
          totalQty: 0,
          childrenMap: new Map()
        })
    }
    const l2 = l1.childrenMap.get(l2Key)
    if (Object.prototype.hasOwnProperty.call(l2.sizeTotals, beden)) {
      l2.sizeTotals[beden] += qty
    }
    l2.totalQty += qty

    const l3Key = `${depoKodu}|${depoAdi}`
    if (!l2.childrenMap.has(l3Key)) {
      l2.childrenMap.set(l3Key, {
        key: `L3|${productCode}|${l2Key}|${l3Key}`,
        depoKodu,
        depoAdi,
        sizeTotals: emptySizeTotals(),
        totalQty: 0,
        items: []
      })
    }
    const l3 = l2.childrenMap.get(l3Key)
    if (Object.prototype.hasOwnProperty.call(l3.sizeTotals, beden)) {
      l3.sizeTotals[beden] += qty
    }
    l3.totalQty += qty
    l3.items.push({
      ...item,
      _rowKey: `${productCode}|${colorCode}|${secondColor}|${depoKodu}|${beden}`
    })
  }

  return Array.from(l1Map.values())
    .map((l1) => ({
      ...l1,
      children: Array.from(l1.childrenMap.values())
        .map((l2) => ({
          ...l2,
          children: Array.from(l2.childrenMap.values()).sort(sortByTotalQtyDesc)
        }))
        .sort(sortByTotalQtyDesc)
    }))
    .sort(sortByTotalQtyDesc)
})

function createEmptyFilters() {
  return {
    kategori: '',
    urun_ana_grubu: '',
    urun_alt_grubu: [],
    renk: [],
    renk2: [],
    urun_icerigi: [],
    fit: [],
    drop: [],
    beden: []
  }
}

function isMultiFilter(key) {
  return multiSelectFilterKeys.has(key)
}

function normalizeFilterScalar(v) {
  return String(v ?? '').trim()
}

function normalizeFilterList(v) {
  const src = Array.isArray(v) ? v : (normalizeFilterScalar(v) ? [v] : [])
  const out = []
  const seen = new Set()
  for (const item of src) {
    const val = normalizeFilterScalar(item)
    if (!val || seen.has(val)) continue
    seen.add(val)
    out.push(val)
  }
  return out
}

function buildFilterParams(excludeKey = '') {
  const out = {}
  for (const def of filterDefs) {
    if (excludeKey && def.key === excludeKey) continue
    if (isMultiFilter(def.key)) {
      const vals = normalizeFilterList(filters.value?.[def.key])
      if (vals.length) out[def.key] = vals.join(filterValueSeparator)
      continue
    }
    const val = normalizeFilterScalar(filters.value?.[def.key])
    if (val) out[def.key] = val
  }
  return out
}

function buildFilterCacheKey(params) {
  const keys = Object.keys(params || {}).sort()
  return keys.map((k) => `${k}=${String(params[k] || '').trim()}`).join('&')
}

function isFilterDisabled(key) {
  if (key === 'kategori') return false
  if (key === 'urun_ana_grubu') {
    return normalizeFilterScalar(filters.value.kategori) === ''
  }
  return !canQuery.value
}

function onFilterValueChange(changedKey) {
  if (changedKey === 'kategori') {
    filters.value.urun_ana_grubu = ''
    filters.value.urun_alt_grubu = []
    filters.value.renk = []
    filters.value.renk2 = []
    filters.value.urun_icerigi = []
    filters.value.fit = []
    filters.value.drop = []
    filters.value.beden = []
  } else if (changedKey === 'urun_ana_grubu') {
    filters.value.urun_alt_grubu = []
    filters.value.renk = []
    filters.value.renk2 = []
    filters.value.urun_icerigi = []
    filters.value.fit = []
    filters.value.drop = []
    filters.value.beden = []
  } else if (changedKey === 'renk') {
    filters.value.renk2 = []
    filters.value.beden = []
  } else if (changedKey === 'renk2') {
    filters.value.beden = []
  }

  if (filterOptionsDebounceTimer) {
    clearTimeout(filterOptionsDebounceTimer)
  }
  const excludeKey = isMultiFilter(changedKey) ? changedKey : ''
  filterOptionsDebounceTimer = setTimeout(() => {
    void loadFilterOptions(false, excludeKey)
  }, FILTER_OPTIONS_DEBOUNCE_MS)
}

function filterOptions(field, val, update) {
  const source = Array.isArray(optionLists.value?.[field])
    ? optionLists.value[field]
    : []
  if (!val) {
    update(() => {
      filteredOptionLists.value[field] = [...source]
    })
    return
  }
  const needle = normalizeSearchText(val)
  update(() => {
    filteredOptionLists.value[field] = source.filter((opt) =>
      normalizeSearchText(opt).includes(needle)
    )
  })
}

function selectAllFilterOptions(key) {
  if (!isMultiFilter(key) || isFilterDisabled(key)) return
  const list = Array.isArray(optionLists.value?.[key]) ? optionLists.value[key] : []
  filters.value[key] = [...list]
  onFilterValueChange(key)
}

function clearAllFilterOptions(key) {
  if (!isMultiFilter(key) || isFilterDisabled(key)) return
  filters.value[key] = []
  onFilterValueChange(key)
}

async function loadFilterOptions(force = false, excludeKey = '') {
  const params = buildFilterParams(excludeKey)
  const cacheKey = buildFilterCacheKey(params)
  const now = Date.now()
  if (!force) {
    const cached = filterOptionsCache.value[cacheKey]
    if (cached && Number(cached.expiresAt || 0) > now && cached.payload) {
      optionLists.value = cached.payload.optionLists
      filteredOptionLists.value = cached.payload.filteredOptionLists
      return
    }
  }

  const reqSeq = ++filterOptionsRequestSeq
  loadingFilterOptions.value = true
  try {
    const res = await api.get('/product-stock-attribute-options', {
      params
    })
    if (reqSeq !== filterOptionsRequestSeq) return
    const payload = res?.data && typeof res.data === 'object' ? res.data : {}
    const next = {}
    const nextFiltered = {}

    for (const def of filterDefs) {
      const arr = Array.isArray(payload?.[def.key]) ? payload[def.key] : []
      const list = arr
        .map((x) => String(x || '').trim())
        .filter((x) => x.length > 0)
        .sort((a, b) => a.localeCompare(b, 'tr'))
      next[def.key] = list
      nextFiltered[def.key] = [...list]

      if (isMultiFilter(def.key)) {
        const selectedList = normalizeFilterList(filters.value?.[def.key])
        filters.value[def.key] = selectedList.filter((v) => list.includes(v))
      } else {
        const selected = normalizeFilterScalar(filters.value?.[def.key])
        if (selected && !list.includes(selected)) {
          filters.value[def.key] = ''
        }
      }
    }

    optionLists.value = next
    filteredOptionLists.value = nextFiltered
    filterOptionsCache.value[cacheKey] = {
      expiresAt: now + FILTER_OPTIONS_CACHE_TTL_MS,
      payload: {
        optionLists: next,
        filteredOptionLists: nextFiltered
      }
    }
  } catch (err) {
    if (reqSeq !== filterOptionsRequestSeq) return
    errorMessage.value = 'Urun ozellik secenekleri alinamadi.'
    console.error('loadFilterOptions error:', err)
  } finally {
    if (reqSeq === filterOptionsRequestSeq) {
      loadingFilterOptions.value = false
    }
  }
}

async function fetchStockByAttributes() {
  if (!canQuery.value) {
    $q.notify({
      type: 'warning',
      position: 'top-right',
      message: 'Kategori ve Urun Ana Grubu secimi zorunludur.'
    })
    return
  }
  const params = buildFilterParams()

  loadingStock.value = true
  errorMessage.value = ''

  try {
    if (!orderStore.schemaMap || !Object.keys(orderStore.schemaMap).length) {
      orderStore.initSchemaMap()
    }
    await orderStore.ensureProductSizeMatchRules()

    const res = await api.get('/product-stock-query-by-attributes', { params })
    const list = Array.isArray(res?.data) ? res.data : []

    if (!list.length) {
      rawRows.value = []
      openState.value = {}
      return
    }

    const first = list[0] || {}
    const grpKey = detectBedenGroup(
      list.map((x) => x?.Beden || ''),
      first?.URUN_ANA_GRUBU || '',
      first?.KATEGORI || first?.YETISKIN_GARSON || '',
      first?.YETISKIN_GARSON || '',
      first?.URUN_ALT_GRUBU || ''
    )

    const schemaMap = Object.keys(orderStore.schemaMap || {}).length
      ? orderStore.schemaMap
      : storeSchemaByKey
    if (!grpKey || !schemaMap?.[grpKey]) {
      rawRows.value = []
      openState.value = {}
      errorMessage.value = 'Beden grubu eşleşmesi bulunamadı.'
      $q.notify({
        type: 'negative',
        position: 'top-right',
        message: 'Beden grubu eşleşmesi bulunamadı (kategori/ana grup/alt grup).'
      })
      return
    }
    activeGrpKey.value = grpKey
    activeSchema.value = schemaMap[grpKey]

    rawRows.value = list
    productImageCache.value = {}
    productImageLoading.value = {}
    productImageListByCode.value = {}
    productImageListLoading.value = {}
    productImageFallbackByKey.value = {}
    productImageContentLoading.value = {}
    productImageListBlockedUntil.value = 0
    initOpenState(level1Groups.value)
  } catch (err) {
    console.error('fetchStockByAttributes error:', err)
    rawRows.value = []
    openState.value = {}
    errorMessage.value = 'Stok sorgulama sirasinda hata olustu.'
    $q.notify({
      type: 'negative',
      position: 'top-right',
      message: 'Stok sorgusu basarisiz.'
    })
  } finally {
    loadingStock.value = false
  }
}

function onLevel2Click(productCode, grp2) {
  toggleOpen(grp2.key)
  if (isOpen(grp2.key)) {
    void ensureProductImage(productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')
  }
}

async function openProductCard(grp1, grp2) {
  const productCode = String(grp1?.productCode || '').trim()
  const colorCode = String(grp2?.colorCode || '').trim()
  const secondColor = String(grp2?.secondColor || '').trim()
  const photoDim3 = String(grp2?.photoDim3 || secondColor).trim()
  const photoDim1ID = String(grp2?.photoDim1ID || '').trim()
  const photoDim3ID = String(grp2?.photoDim3ID || '').trim()
  const listKey = buildImageKey(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
  const codeTrim = String(productCode || '').trim().toUpperCase()
  const colorTrim = String(colorCode || '').trim().toUpperCase()
  const secondTrim = String(photoDim3 || '').trim().toUpperCase()
  const dim1IDTrim = String(photoDim1ID || '').trim().toUpperCase()
  const dim3IDTrim = String(photoDim3ID || '').trim().toUpperCase()

  await ensureProductImage(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
  let list = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
  console.info('[ProductStockByAttributes][openProductCard] request', {
    productCode,
    colorCode,
    secondColor,
    dim1ID: dim1IDTrim,
    dim3ID: dim3IDTrim,
    listKey,
    cachedListCount: list.length
  })
  if (!list.length && codeTrim) {
    try {
      list = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
      productImageListByCode.value[listKey] = list
      console.info('[ProductStockByAttributes][openProductCard] refetch', {
        productCode: codeTrim,
        dim1: colorTrim,
        dim1ID: dim1IDTrim,
        dim3: secondTrim,
        dim3ID: dim3IDTrim,
        fetchedCount: list.length,
        fileNames: list.map((x) => String(x?.file_name || x?.FileName || '').trim()).filter(Boolean)
      })
    } catch (err) {
      console.warn('[ProductStockByAttributes] product card image list refetch failed', {
        code: codeTrim,
        color: colorTrim,
        secondColor: secondTrim,
        err
      })
    }
  }

  const sortedList = sortImagesForDisplay(list)
  const imageCandidates = await Promise.all(
    sortedList.map((item) => resolveProductImageUrlForCarousel(item))
  )
  const images = imageCandidates.filter((x) => String(x || '').trim() !== '')
  console.info('[ProductStockByAttributes][openProductCard] render', {
    productCode,
    colorCode,
    secondColor,
    candidateCount: imageCandidates.length,
    imageCount: images.length,
    firstImages: images.slice(0, 3)
  })
  const uniqueImages = Array.from(new Set(images))

  if (!uniqueImages.length) {
    const single = getProductImageUrl(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
    if (single) uniqueImages.push(single)
  }

  productCardImages.value = uniqueImages
  productCardSlide.value = Math.min(Math.max(getGalleryQueryIndex(), 0), Math.max(uniqueImages.length - 1, 0))
  setGalleryQueryIndex(productCardSlide.value)
  productCardData.value = {
    productCode,
    colorCode,
    secondColor,
    kategori: String(filters.value?.kategori || '').trim(),
    urunAnaGrubu: String(grp2?.urunAnaGrubu || '').trim(),
    urunAltGrubu: String(grp2?.urunAltGrubu || '').trim(),
    urunIcerigi: String(grp2?.urunIcerigi || '').trim(),
    fit: String(grp2?.fit || '').trim(),
    drop: String(grp2?.drop || '').trim(),
    kumas: String(grp2?.kumas || '').trim(),
    karisim: String(grp2?.karisim || '').trim(),
    sizeTotals: grp2?.sizeTotals || {},
    totalQty: Number(grp2?.totalQty || 0)
  }
  productCardDialog.value = true
}

function openProductImageFullscreen(src) {
  const value = String(src || '').trim()
  if (!value) return
  productImageFullscreenSrc.value = value
  const idx = Math.max(0, fullscreenImages.value.findIndex((x) => String(x || '').trim() === value))
  productImageFullscreenSlide.value = idx
  setGalleryQueryIndex(idx)
  productImageFullscreenZoom.value = 1
  productImageFullscreenOffsetX.value = 0
  productImageFullscreenOffsetY.value = 0
  productImageFullscreenDragging.value = false
  productImageFullscreenDialog.value = true
}

function toggleFullscreenImageZoom() {
  const current = Number(productImageFullscreenZoom.value || 1)
  if (current < 1.5) productImageFullscreenZoom.value = 1.8
  else if (current < 2.3) productImageFullscreenZoom.value = 2.6
  else if (current < 3.2) productImageFullscreenZoom.value = 3.2
  else productImageFullscreenZoom.value = 1
  if (productImageFullscreenZoom.value <= 1) {
    productImageFullscreenOffsetX.value = 0
    productImageFullscreenOffsetY.value = 0
  }
}

function onFullscreenWheel(evt) {
  if (!evt) return
  evt.preventDefault()
  const delta = Number(evt.deltaY || 0)
  if (productImageFullscreenZoom.value > 1.01 && !evt.ctrlKey) {
    productImageFullscreenOffsetY.value -= delta * 0.45
    return
  }
  const current = Number(productImageFullscreenZoom.value || 1)
  const next = delta < 0 ? current + 0.2 : current - 0.2
  productImageFullscreenZoom.value = Math.min(4, Math.max(1, Number(next.toFixed(2))))
  if (productImageFullscreenZoom.value <= 1) {
    productImageFullscreenOffsetX.value = 0
    productImageFullscreenOffsetY.value = 0
  }
}

function onFullscreenMouseDown(evt) {
  if (productImageFullscreenZoom.value <= 1) return
  productImageFullscreenDragging.value = true
  productImageFullscreenDragStartX.value = Number(evt?.clientX || 0)
  productImageFullscreenDragStartY.value = Number(evt?.clientY || 0)
  productImageFullscreenDragOriginX.value = Number(productImageFullscreenOffsetX.value || 0)
  productImageFullscreenDragOriginY.value = Number(productImageFullscreenOffsetY.value || 0)
}

function onFullscreenMouseMove(evt) {
  if (!productImageFullscreenDragging.value) return
  const dx = Number(evt?.clientX || 0) - productImageFullscreenDragStartX.value
  const dy = Number(evt?.clientY || 0) - productImageFullscreenDragStartY.value
  productImageFullscreenOffsetX.value = productImageFullscreenDragOriginX.value + dx
  productImageFullscreenOffsetY.value = productImageFullscreenDragOriginY.value + dy
}

function onFullscreenMouseUp() {
  productImageFullscreenDragging.value = false
}

function onFullscreenSlideChange() {
  setGalleryQueryIndex(productImageFullscreenSlide.value)
  productImageFullscreenZoom.value = 1
  productImageFullscreenOffsetX.value = 0
  productImageFullscreenOffsetY.value = 0
  productImageFullscreenDragging.value = false
}

function onProductCardSlideChange() {
  setGalleryQueryIndex(productCardSlide.value)
}

function onProductCardDialogHide() {
  productImageFullscreenDialog.value = false
  clearGalleryQueryIndex()
}

function onFullscreenDialogHide() {
  onFullscreenMouseUp()
}

function resetForm() {
  filters.value = createEmptyFilters()
  rawRows.value = []
  errorMessage.value = ''
  openState.value = {}
  activeSchema.value = storeSchemaByKey.tak
  productImageCache.value = {}
  productImageLoading.value = {}
  productImageListByCode.value = {}
  productImageListLoading.value = {}
  productImageFallbackByKey.value = {}
  productImageContentLoading.value = {}
  productImageListBlockedUntil.value = 0
  productCardDialog.value = false
  productCardData.value = {}
  productCardImages.value = []
  productCardSlide.value = 0
  productImageFullscreenDialog.value = false
  productImageFullscreenSrc.value = ''
  productImageFullscreenSlide.value = 0
  productImageFullscreenZoom.value = 1
  productImageFullscreenOffsetX.value = 0
  productImageFullscreenOffsetY.value = 0
  productImageFullscreenDragging.value = false
  filterOptionsCache.value = {}
  void loadFilterOptions(true)
}

onMounted(async () => {
  await orderStore.ensureProductSizeMatchRules()
  void loadFilterOptions(true)
  window.addEventListener('mousemove', onFullscreenMouseMove)
  window.addEventListener('mouseup', onFullscreenMouseUp)
})

onUnmounted(() => {
  window.removeEventListener('mousemove', onFullscreenMouseMove)
  window.removeEventListener('mouseup', onFullscreenMouseUp)
  if (filterOptionsDebounceTimer) {
    clearTimeout(filterOptionsDebounceTimer)
    filterOptionsDebounceTimer = null
  }
})

</script>

<style scoped>
.order-page {
  --psq-sticky-offset: 12px;
  --grp-title-w: 44px;
  --psq-header-h: 56px;
  --psq-col-adet: calc(var(--col-adet) + var(--beden-w));
  --psq-col-img: 190px;
  --psq-l1-lift: 42px;
}

.order-grid-header {
  top: calc(var(--header-h) + var(--filter-h) + var(--save-h) + var(--psq-sticky-offset)) !important;
  grid-template-columns:
    var(--col-model)
    var(--col-renk)
    var(--col-ana)
    var(--col-alt)
    var(--col-aciklama)
    calc(var(--grp-title-w) + var(--grp-title-gap) + (var(--beden-w)*var(--beden-count)))
    var(--psq-col-adet)
    var(--psq-col-img) !important;
}

.order-grid-header .col-fixed,
.order-grid-header .total-cell {
  writing-mode: horizontal-tb !important;
  transform: none !important;
  height: var(--psq-header-h) !important;
  font-size: 10px !important;
  line-height: 1 !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 4px !important;
}

.order-grid-header .beden-block {
  height: var(--psq-header-h) !important;
}

.order-grid-header .grp-row {
  height: var(--psq-header-h) !important;
  align-items: center;
}

.order-grid-header .grp-title {
  width: var(--grp-title-w) !important;
  text-align: center !important;
  padding-right: 0 !important;
  font-size: 10px !important;
}

.order-grid-header .grp-cell.hdr {
  height: var(--psq-header-h) !important;
  font-size: 10px !important;
}

.order-grid-header .total-row {
  grid-column: 7 / 9 !important;
}

.order-grid-header .total-cell {
  width: var(--psq-col-adet) !important;
}

.order-grid-header .total-cell:last-child {
  width: var(--psq-col-img) !important;
}

.order-sub-header {
  grid-template-columns:
    var(--col-model)
    var(--col-renk)
    var(--col-ana)
    var(--col-alt)
    var(--col-aciklama)
    calc(var(--grp-title-w) + var(--grp-title-gap) + (var(--beden-w)*var(--beden-count)))
    var(--psq-col-adet)
    var(--psq-col-img) !important;
  top: calc(
    var(--header-h)
    + var(--filter-h)
    + var(--save-h)
    + var(--grid-header-h)
    + var(--psq-sticky-offset)
  ) !important;
}

.order-sub-header.level-2 {
  min-height: 252px !important;
  height: 252px !important;
  background: #fff9c4 !important;
  border-top: 1px solid #d4c79f !important;
  border-bottom: 1px solid #d4c79f !important;
}

.order-sub-header.level-1 {
  min-height: 84px !important;
  height: 84px !important;
  top: calc(
    var(--header-h)
    + var(--filter-h)
    + var(--save-h)
    + var(--grid-header-h)
    + var(--psq-sticky-offset)
    - var(--psq-l1-lift)
  ) !important;
  background: var(--q-primary, #1976d2) !important;
  border-top: 1px solid #145ea8 !important;
  border-bottom: 1px solid #145ea8 !important;
  color: #fff !important;
}

.order-sub-header.level-1 .sub-col.level1-merged {
  grid-column: 1 / 6;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: 0 10px;
  border-right: 1px solid rgba(255, 255, 255, 0.45);
  min-width: 0;
}

.order-sub-header.level-1 .sub-col.level1-merged .text-caption {
  color: #fff !important;
  opacity: 0.95;
}

.order-sub-header.level-1 .sub-center.level1-center {
  grid-column: 6;
  display: grid;
  grid-template-rows: 42px 42px;
  align-items: stretch;
  height: 100%;
  overflow: hidden;
  padding-left: calc(var(--grp-title-w) + var(--grp-title-gap));
  margin-left: 0;
}

.order-sub-header.level-1 .beden-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--beden-w);
  height: 42px;
  min-height: 42px;
}

.order-sub-header.level-1 .beden-row .beden-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 42px;
  min-height: 42px;
  background: var(--q-primary, #1976d2) !important;
  color: #fff !important;
  border-right: 1px solid rgba(255, 255, 255, 0.45);
  border-bottom: 1px solid rgba(255, 255, 255, 0.45);
  border-top: none;
  border-left: none;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
}

.order-sub-header.level-1 .beden-row.values-top .beden-cell {
  background: #fff9c4 !important;
  color: var(--q-primary, #1976d2) !important;
  font-weight: 700;
}

.order-sub-header.level-1 .beden-row.headers .beden-cell {
  font-weight: 500;
  color: #fff !important;
}

.order-sub-header.level-1 .sub-right.level1-right {
  grid-column: 7 / 8;
  display: grid;
  grid-template-columns: var(--psq-col-adet);
  grid-template-rows: 30px 30px 24px;
  align-items: stretch;
  justify-items: stretch;
  height: 100%;
  overflow: hidden;
  padding: 0 8px 0 6px;
  border-left: 1px solid rgba(255, 255, 255, 0.45);
  color: #fff;
}

.order-sub-header.level-1 .sub-right .top-total {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
  background: #fff9c4 !important;
  color: var(--q-primary, #1976d2) !important;
  padding: 0 6px;
  border-radius: 4px;
}

.order-sub-header.level-1 .sub-right .bottom-label {
  font-size: 12px;
  font-weight: 700;
}

.order-sub-header.level-1 .sub-right .bottom-row {
  grid-column: 1;
  grid-row: 2;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  white-space: nowrap;
  overflow: hidden;
}

.order-sub-header.level-1 .sub-right .icon-row {
  grid-column: 1;
  grid-row: 3;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.order-sub-header.level-2 .sub-col {
  display: flex;
  align-items: center;
  padding: 0 8px;
  font-size: 12px;
  font-weight: 500;
  color: #111;
  min-width: 0;
  border-right: 1px solid #d4c79f;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  line-height: 1.2;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.order-sub-header.level-2 .sub-col.model { grid-column: 1; }
.order-sub-header.level-2 .sub-col.renk { grid-column: 2; }
.order-sub-header.level-2 .sub-col.ana { grid-column: 3; }
.order-sub-header.level-2 .sub-col.alt { grid-column: 4; }
.order-sub-header.level-2 .sub-col.aciklama { grid-column: 5; }

.order-sub-header.level-2 .sub-col.model,
.order-sub-header.level-2 .sub-col.renk,
.order-sub-header.level-2 .sub-col.ana,
.order-sub-header.level-2 .sub-col.alt {
  justify-content: center;
  text-align: center;
}

.order-sub-header.level-2 .sub-col.renk {
  flex-direction: column;
  gap: 2px;
  line-height: 1.1;
}

.order-sub-header.level-2 .sub-col.renk .renk-kodu {
  font-weight: 700;
}

.order-sub-header.level-2 .sub-col.renk .renk-aciklama {
  font-size: 11px;
  opacity: 0.9;
}

.order-sub-header.level-2 .sub-col.aciklama {
  justify-content: flex-start;
  text-align: left;
}

.order-sub-header.level-2 .sub-center.level2-center {
  grid-column: 6;
  display: grid;
  grid-template-rows: 1fr 1fr;
  align-items: stretch;
  height: 100%;
  padding-left: var(--grp-title-w);
  margin-left: var(--grp-title-gap);
}

.order-sub-header.level-2 .beden-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--beden-w);
}

.order-sub-header.level-2 .beden-row.values-top .beden-cell {
  border-right: 1px solid #d4c79f;
  background: transparent;
  font-size: 13px;
  font-weight: 600;
  color: #1f1f1f;
  line-height: 1;
}

.order-sub-header.level-2 .beden-row.headers .beden-cell {
  border-top: 1px solid #d4c79f;
  border-right: 1px solid #d4c79f;
  border-bottom: none;
  background: var(--q-primary, #1976d2);
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  line-height: 1;
}

.order-sub-header.level-2 .sub-right.level2-right {
  grid-column: 7 / 8;
  display: grid;
  grid-template-columns: var(--psq-col-adet);
  grid-template-rows: 1fr 1fr;
  align-items: center;
  justify-items: start;
  padding-left: 8px;
  padding-right: 0;
  transform: none !important;
  border-left: 1px solid #d4c79f;
}

.order-sub-header.level-2 .sub-image.level2-image {
  grid-column: 8 / 9;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-left: 1px solid #d4c79f;
  gap: 8px;
  padding: 8px 10px;
  background: #fffef7;
}

.product-image-card {
  width: 162px;
  height: 216px;
  border-radius: 8px;
}

.product-image-wrap {
  width: 100%;
  height: 100%;
}

.product-image {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  background: #fff;
}

.product-image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f5f5;
  border-radius: 6px;
}

.detail-open-btn {
  margin-top: 4px;
  font-size: 11px;
}

.product-card-dialog {
  --pc-media-h: calc(100vh - 180px);
  --pc-media-w: min(74vw, 1220px);
  background: #f9f8f5;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

:deep(.product-card-dialog > .q-card__section:last-child) {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.product-card-stock {
  background: linear-gradient(180deg, #f9f6ef 0%, #fffdf9 100%);
  border: 1px solid #e4dac7;
  border-radius: 12px;
  padding: 14px;
}

.stock-size-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 8px;
}

.stock-size-chip {
  border: 1px solid #e6dccb;
  border-radius: 10px;
  background: #ffffff;
  padding: 6px 8px;
  display: flex;
  justify-content: space-between;
  font-size: 12px;
}

.stock-size-chip .label {
  font-weight: 700;
}

.product-card-content {
  display: grid;
  grid-template-columns: minmax(360px, 420px) minmax(760px, 1fr);
  gap: 14px;
  align-items: stretch;
  justify-content: start;
  height: 100%;
}

.product-card-images {
  grid-column: 2;
  grid-row: 1;
  height: var(--pc-media-h);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}

.product-card-carousel {
  width: var(--pc-media-w);
  height: 100%;
  max-width: 100%;
  background: linear-gradient(180deg, #f6f1e6 0%, #efe6d3 100%);
  border: 1px solid #e4dac7;
}

:deep(.product-card-carousel .q-carousel__navigation) {
  bottom: 10px;
}

:deep(.product-card-carousel .q-carousel__navigation .q-btn) {
  color: var(--q-secondary, #26a69a);
  opacity: 0.7;
  transform: scale(1);
  transition: transform 0.14s ease, opacity 0.14s ease, color 0.14s ease;
}

:deep(.product-card-carousel .q-carousel__navigation .q-btn--active) {
  color: var(--q-primary, #1976d2);
  opacity: 1;
  transform: scale(1.22);
}

.dialog-image {
  width: 100%;
  height: 100%;
}

.dialog-image-stage {
  width: var(--pc-media-w);
  max-width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 10px;
  background: linear-gradient(180deg, #f6f1e6 0%, #efe6d3 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}

.dialog-image-empty {
  width: var(--pc-media-w);
  max-width: 100%;
  height: var(--pc-media-h);
  border: 1px dashed #c5b28d;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #faf6ee;
}

.image-fullscreen-dialog {
  background: #f4f0e2;
}

.image-fullscreen-body {
  height: calc(100vh - 72px);
  display: flex;
  align-items: center;
  justify-content: center;
}

.image-fullscreen-carousel {
  width: min(98vw, 1500px);
}

:deep(.image-fullscreen-carousel .q-carousel__slide) {
  background: linear-gradient(180deg, #f7f2e7 0%, #efe5d2 100%);
}

:deep(.image-fullscreen-carousel .q-carousel__navigation) {
  bottom: 12px;
}

:deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn) {
  color: var(--q-secondary, #26a69a);
  opacity: 0.72;
  transform: scale(1);
  transition: transform 0.14s ease, color 0.14s ease;
}

:deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn--active) {
  color: var(--q-primary, #1976d2);
  opacity: 1;
  transform: scale(1.28);
  text-shadow: 0 0 0.5px currentColor;
  filter: drop-shadow(0 0 2px rgba(38, 166, 154, 0.45));
}

:deep(.image-fullscreen-carousel .q-carousel__arrow .q-btn) {
  color: var(--q-primary, #1976d2);
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid #d7e2f3;
}

:deep(.image-fullscreen-carousel .q-carousel__arrow .q-btn:hover) {
  color: var(--q-secondary, #26a69a);
  border-color: rgba(38, 166, 154, 0.45);
  background: rgba(255, 255, 255, 0.98);
}

.image-fullscreen-stage {
  width: min(96vw, 1400px);
  height: calc(100vh - 120px);
  border-radius: 10px;
  background: linear-gradient(180deg, #f1e7d3 0%, #e9dcc4 100%);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.image-fullscreen-img {
  width: 100%;
  height: 100%;
}

.product-card-fields {
  grid-column: 1;
  grid-row: 1;
  border: 1px solid #e4dac7;
  border-radius: 12px;
  background: linear-gradient(180deg, #ffffff 0%, #fdfaf4 100%);
  padding: 12px;
  height: var(--pc-media-h);
  overflow: auto;
}

.field-row {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid #efe5d5;
  font-size: 13px;
}

.field-row.field-row-head {
  background: #f8f3e9;
  border: 1px solid #e6dccb;
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 8px;
}

.field-row:last-child {
  border-bottom: none;
}

.field-row .k {
  color: #6b5a33;
  font-weight: 700;
}

.field-row .v {
  color: #1f1f1f;
  word-break: break-word;
}

.product-card-stock-inline {
  border-top: 1px solid #e6dccb;
  padding-top: 10px;
}

.q-btn,
.q-icon,
.product-image-card,
.cursor-pointer {
  cursor: pointer !important;
}

@media (max-width: 1024px) {
  .product-card-content {
    grid-template-columns: 1fr;
  }

  .product-card-images,
  .product-card-fields {
    grid-column: auto;
    grid-row: auto;
  }

  .product-card-fields {
    height: auto;
  }

  .product-card-dialog {
    --pc-media-h: calc(100vh - 220px);
    --pc-media-w: min(96vw, 900px);
  }
}

.order-sub-header.level-2 .sub-right .top-total {
  grid-column: 1 / 2;
  grid-row: 1;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  justify-self: start;
  text-align: left;
}

.order-sub-header.level-2 .sub-right .bottom-label {
  font-size: 12px;
  font-weight: 700;
}

.order-sub-header.level-2 .sub-right .bottom-row {
  grid-column: 1;
  grid-row: 2;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
}

.order-grid-body .summary-row {
  display: grid !important;
  grid-template-columns:
    var(--col-model)
    var(--col-renk)
    var(--col-ana)
    var(--col-alt)
    var(--col-aciklama)
    calc(var(--grp-title-w) + var(--grp-title-gap) + (var(--beden-w) * var(--beden-count)))
    var(--psq-col-adet)
    var(--psq-col-img) !important;
  min-height: 56px;
  height: 56px;
  background: #fff;
  border-top: 1px solid #d4c79f;
  border-bottom: 1px solid #d4c79f;
  align-items: stretch;
}

.order-grid-body .summary-row .cell {
  min-height: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-right: 1px solid #d4c79f;
  font-size: 12px;
  overflow: hidden !important;
}

.order-grid-body .summary-row .cell:last-child {
  border-right: none;
}

.order-grid-body .summary-row .grp-area {
  display: grid !important;
  grid-template-columns: var(--grp-title-w) var(--grp-title-gap) 1fr;
  width: 100% !important;
  height: 56px;
  padding-left: 0 !important;
  transform: none !important;
  border-right: 1px solid #d4c79f;
}

.order-grid-body .summary-row .grp-row {
  grid-column: 3;
  width: 100%;
  height: 56px;
  margin-left: 0 !important;
  justify-content: start !important;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--beden-w);
}

.order-grid-body .summary-row .grp-row .cell.beden {
  width: var(--beden-w);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
  margin: 0 !important;
  border-right: 1px solid #d4c79f;
  border-left: none !important;
  border-top: none !important;
  border-bottom: none !important;
  min-height: 56px;
  height: 56px;
  box-sizing: border-box;
}

.order-grid-body .summary-row .grp-row .cell.beden:first-child {
  border-left: 1px solid #d4c79f !important;
}

.order-grid-body .summary-row .cell.model,
.order-grid-body .summary-row .cell.renk,
.order-grid-body .summary-row .cell.ana,
.order-grid-body .summary-row .cell.alt {
  justify-content: center;
  text-align: center;
}

.order-grid-body .summary-row .cell.aciklama {
  grid-column: 5 / 6 !important;
  position: static !important;
  width: var(--col-aciklama) !important;
  margin-right: 0 !important;
  min-height: 56px !important;
  z-index: auto !important;
  background: #fff !important;
  box-sizing: border-box !important;
  border-right: 1px solid #d4c79f !important;
  justify-content: flex-start !important;
  text-align: left !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  line-height: 1 !important;
  padding-left: 6px !important;
  padding-right: 6px !important;
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
}

.order-grid-body .summary-row .cell.depo-merged {
  grid-column: 1 / 6 !important;
  justify-content: center !important;
  text-align: center !important;
  font-weight: 600;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

.order-grid-body .summary-row .cell.adet,
.order-grid-body .summary-row .cell.termin {
  justify-content: flex-end;
  text-align: right;
  padding-right: 10px !important;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.order-grid-body .summary-row .cell.img-placeholder {
  grid-column: 8 / 9;
  border-right: none !important;
  background: #fffef7;
}

.order-grid-body {
  margin-top: 0 !important;
  padding-top: 0 !important;
}

.order-grid-body > .summary-group,
.order-grid-body > .summary-group:first-child {
  margin-top: 0 !important;
  padding-top: 0 !important;
}


.detail-table-wrap {
  padding: 8px 0 12px 0;
  background: #fff;
}

.detail-table :deep(th),
.detail-table :deep(td) {
  white-space: nowrap;
}
</style>






