﻿<template>
  <q-page class="product-performance-page q-pa-sm">
    <q-inner-loading :showing="pageBusy">
      <q-spinner-gears size="52px" color="primary" />
    </q-inner-loading>
    <teleport to="body">
      <div
        v-if="pageBusy"
        class="page-busy-overlay"
        @click.stop
        @mousedown.stop
        @mouseup.stop
        @touchstart.stop
        @wheel.stop
      >
        <q-spinner-gears size="56px" color="primary" />
        <div class="page-busy-label">Yükleniyor...</div>
      </div>
    </teleport>
    <div class="row items-center justify-between q-col-gutter-sm q-mb-sm">
      <div class="col-12 col-md">
        <div class="text-h6">Ürün Performans ve Karlılık Analizi</div>
        <div class="text-caption text-grey-7">
          Ürün, renk, yaka, piyasa ve müşteri segmenti bazında satış, stok dönüşü ve karlılık KPI'ları.
        </div>
      </div>
      <div class="col-12 col-md-auto row items-center q-gutter-sm">
        <q-option-group
          v-model="selectedPeriods"
          :options="periodOptions"
          type="checkbox"
          inline
          dense
          :disable="pageBusy"
          class="period-selector bg-white q-px-sm q-py-xs"
        />
        <q-btn-dropdown
          dense
          outline
          color="primary"
          :icon="allProductGroupsExpanded ? 'unfold_less' : 'unfold_more'"
          :label="allProductGroupsExpanded ? 'Detayları Kapat' : 'Tüm Detayları Aç'"
          :disable="pageBusy"
          @click="toggleAllProductGroups"
        >
          <div class="detail-level-menu">
            <q-option-group
              v-model="activeSelectedExpandLevelKeys"
              :options="expandLevelOptions"
              type="checkbox"
              dense
            />
            <q-separator class="q-my-sm" />
            <div class="row items-center justify-end q-gutter-xs">
              <q-btn dense flat color="grey-7" label="Kapat" :disable="pageBusy" @click="collapseAllProductGroups" />
              <q-btn dense color="primary" label="Seçileni Aç" :disable="pageBusy" @click="expandSelectedProductGroups" />
            </div>
          </div>
        </q-btn-dropdown>
        <q-btn outline color="secondary" icon="refresh" label="Yenile" :loading="loading" :disable="pageBusy" @click="reload" />
      </div>
    </div>

    <div class="row q-col-gutter-sm q-mb-sm">
      <div v-for="card in summaryCards" :key="card.key" class="col-6 col-md-2">
        <q-card flat bordered class="metric-card">
          <q-card-section>
            <div class="text-caption text-grey-7">{{ card.label }}</div>
            <div class="metric-value">{{ card.value }}</div>
          </q-card-section>
        </q-card>
      </div>
    </div>

    <div class="performance-tab-grid q-mb-sm">
      <button
        v-for="tab in performanceTabs"
        :key="tab.name"
        type="button"
        :class="['performance-tab-button', { active: activeTab === tab.name }]"
        :disabled="pageBusy"
        @click="switchPerformanceTab(tab.name)"
      >
        <q-icon :name="tab.icon" size="16px" />
        <span>{{ tab.label }}</span>
      </button>
    </div>

    <q-table
      v-if="activeTab === 'general'"
      flat
      bordered
      row-key="row_key"
      class="performance-table sticky-dim-table sticky-dim-7 bg-white"
      :rows="filteredGeneralRows"
      :columns="generalColumns"
      :loading="loading"
      :pagination="{ rowsPerPage: 100, sortBy: 'performance_score', descending: true }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('general', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('general', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('general', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('general', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('general', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('general', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('general', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('general', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('general', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('general', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('general', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-image="props">
        <q-td :props="props" class="product-image-cell">
          <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
            <img
              v-if="getCachedProductImageUrl(props.row)"
              :src="getCachedProductImageUrl(props.row)"
              class="product-thumb"
              loading="lazy"
              decoding="async"
              alt=""
            />
            <div v-else class="product-thumb-placeholder">
              <q-icon name="image" size="22px" />
            </div>
            <q-tooltip>Foto</q-tooltip>
          </button>
        </q-td>
      </template>
      <template #body-cell-performance_bucket="props">
        <q-td :props="props">
          <q-badge :color="bucketColor(props.row.performance_bucket)">
            {{ bucketLabel(props.row.performance_bucket) }}
          </q-badge>
        </q-td>
      </template>
    </q-table>

    <q-table
      v-else-if="activeTab === 'order_product_customers'"
      flat
      bordered
      row-key="row_key"
      class="performance-table sticky-dim-table sticky-dim-10 bg-white"
      :rows="displayOrderProductCustomerTableRows"
      :columns="orderProductCustomerColumns"
      :loading="loading || backendGroupedLoading"
      :pagination="{ rowsPerPage: 100, sortBy: 'order_usd', descending: true }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('order_product_customers', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('order_product_customers', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('order_product_customers', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('order_product_customers', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('order_product_customers', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('order_product_customers', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('order_product_customers', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('order_product_customers', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('order_product_customers', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('order_product_customers', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('order_product_customers', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-image="props">
        <q-td :props="props" class="product-image-cell">
          <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
            <img
              v-if="getCachedProductImageUrl(props.row)"
              :src="getCachedProductImageUrl(props.row)"
              class="product-thumb"
              loading="lazy"
              decoding="async"
              alt=""
            />
            <div v-else class="product-thumb-placeholder">
              <q-icon name="image" size="22px" />
            </div>
            <q-tooltip>Foto</q-tooltip>
          </button>
        </q-td>
      </template>
      <template #body-cell-performance_bucket="props">
        <q-td :props="props">
          <q-badge :color="bucketColor(props.row.performance_bucket)">
            {{ bucketLabel(props.row.performance_bucket) }}
          </q-badge>
        </q-td>
      </template>
      <template #body-cell-net_stock_after_order="props">
        <q-td :props="props" class="text-right" :class="Number(props.row.net_stock_after_order || 0) < 0 ? 'text-negative text-weight-bold' : ''">
          {{ formatNumber(props.row.net_stock_after_order, 0) }}
        </q-td>
      </template>
      <template #body-cell-expected_profit_cost_usd="props">
        <q-td :props="props" class="text-right" :class="Number(props.row.expected_profit_cost_usd || 0) < 0 ? 'text-negative text-weight-bold' : 'text-positive'">
          {{ formatMoney(props.row.expected_profit_cost_usd, 'USD') }}
        </q-td>
      </template>
      <template #body="props">
        <q-tr
          v-if="props.row.__group"
          :props="props"
          :class="['group-row', `group-row-level-${Math.min(Number(props.row.level || 0), 5)}`]"
        >
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <template v-if="col.name === 'image' && groupShowsImage(props.row)">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <div
              v-else-if="col.name === groupLabelColumnName(props.row)"
              class="group-cell-label"
              :style="{ paddingLeft: `${props.row.level * 18}px` }"
            >
              <q-btn
                flat
                dense
                round
                size="sm"
                :icon="isGroupExpanded(props.row.key) ? 'expand_more' : 'chevron_right'"
                @click.stop="toggleGroup(props.row.key)"
              />
              <span class="group-title">{{ props.row.label }}</span>
            </div>
            <span v-else>{{ formatGroupCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
        <q-tr v-else :props="props" class="cursor-pointer" @click="openPerformanceDialog(props.row)">
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <template v-if="col.name === 'image'">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <q-badge v-else-if="col.name === 'performance_bucket'" :color="bucketColor(props.row.performance_bucket)">
              {{ bucketLabel(props.row.performance_bucket) }}
            </q-badge>
            <span v-else>{{ formatTableCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
      </template>
    </q-table>

    <q-table
      v-else-if="activeTab === 'order_market_details'"
      flat
      bordered
      row-key="row_key"
      class="performance-table sticky-dim-table sticky-dim-10 bg-white"
      :rows="displayOrderMarketDetailTableRows"
      :columns="orderMarketDetailColumns"
      :loading="loading || backendGroupedLoading"
      :pagination="{ rowsPerPage: 100, sortBy: 'order_date', descending: true }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('order_market_details', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('order_market_details', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('order_market_details', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('order_market_details', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('order_market_details', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('order_market_details', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('order_market_details', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('order_market_details', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('order_market_details', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('order_market_details', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('order_market_details', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-performance_bucket="props">
        <q-td :props="props">
          <q-badge :color="bucketColor(props.row.performance_bucket)">
            {{ bucketLabel(props.row.performance_bucket) }}
          </q-badge>
        </q-td>
      </template>
      <template #body-cell-net_stock_after_order="props">
        <q-td :props="props" class="text-right" :class="Number(props.row.net_stock_after_order || 0) < 0 ? 'text-negative text-weight-bold' : ''">
          {{ formatNumber(props.row.net_stock_after_order, 0) }}
        </q-td>
      </template>
      <template #body-cell-expected_profit_cost_usd="props">
        <q-td :props="props" class="text-right" :class="Number(props.row.expected_profit_cost_usd || 0) < 0 ? 'text-negative text-weight-bold' : 'text-positive'">
          {{ formatMoney(props.row.expected_profit_cost_usd, 'USD') }}
        </q-td>
      </template>
      <template #body="props">
        <q-tr
          v-if="props.row.__group"
          :props="props"
          :class="['group-row', `group-row-level-${Math.min(Number(props.row.level || 0), 5)}`]"
        >
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <div
              v-if="col.name === groupLabelColumnName(props.row)"
              class="group-cell-label"
              :style="{ paddingLeft: `${props.row.level * 18}px` }"
            >
              <q-btn
                flat
                dense
                round
                size="sm"
                :icon="isGroupExpanded(props.row.key) ? 'expand_more' : 'chevron_right'"
                @click.stop="toggleGroup(props.row.key)"
              />
              <span class="group-title">{{ props.row.label }}</span>
            </div>
            <span v-else>{{ formatGroupCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
        <q-tr v-else :props="props" class="cursor-pointer" @click="openPerformanceDialog(props.row)">
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <q-badge v-if="col.name === 'performance_bucket'" :color="bucketColor(props.row.performance_bucket)">
              {{ bucketLabel(props.row.performance_bucket) }}
            </q-badge>
            <span v-else>{{ formatTableCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
      </template>
    </q-table>

    <q-table
      v-else-if="activeTab === 'products'"
      flat
      bordered
      row-key="row_key"
      class="performance-table product-breakdown-table bg-white"
      :rows="displayProductTableRows"
      :columns="productColumns"
      :loading="loading || backendGroupedLoading"
      :pagination="pagination"
      virtual-scroll
      :virtual-scroll-item-size="64"
      @request="onRequest"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('products', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('products', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('products', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('products', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('products', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('products', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('products', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('products', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('products', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('products', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('products', props.col.name, 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">Sonuç yok</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>
      </template>

      <template #body="props">
        <q-tr
          v-if="props.row.__group"
          :props="props"
          :class="['group-row', `group-row-level-${Math.min(Number(props.row.level || 0), 5)}`]"
        >
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <template v-if="col.name === 'image' && groupShowsImage(props.row)">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <div
              v-else-if="col.name === groupLabelColumnName(props.row)"
              class="group-cell-label"
              :style="{ paddingLeft: `${props.row.level * 18}px` }"
            >
              <q-btn
                flat
                dense
                round
                size="sm"
                :icon="isGroupExpanded(props.row.key) ? 'expand_more' : 'chevron_right'"
                @click.stop="toggleGroup(props.row.key)"
              />
              <span class="group-title">{{ props.row.label }}</span>
            </div>
            <span v-else>{{ formatGroupCell(props.row, col.name) }}</span>
          </q-td>
        </q-tr>
        <q-tr v-else :props="props" class="cursor-pointer" @click="openPerformanceDialog(props.row)">
          <q-td v-for="col in props.cols" :key="col.name" :props="props">
            <template v-if="col.name === 'image'">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <q-badge v-else-if="col.name === 'performance_bucket'" :color="bucketColor(props.row.performance_bucket)">
              {{ bucketLabel(props.row.performance_bucket) }}
            </q-badge>
            <span v-else>{{ formatProductCell(props.row, col.name) }}</span>
          </q-td>
        </q-tr>
      </template>
    </q-table>

    <q-table
      v-else-if="activeTab === 'idle'"
      flat
      bordered
      row-key="row_key"
      class="performance-table sticky-dim-table sticky-dim-6 bg-white"
      :rows="displayIdleTableRows"
      :columns="idleColumns"
      :loading="loading || backendGroupedLoading"
      :pagination="{ rowsPerPage: 100 }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('idle', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('idle', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('idle', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('idle', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('idle', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('idle', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('idle', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('idle', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('idle', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('idle', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('idle', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-image="props">
        <q-td :props="props" class="product-image-cell">
          <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
            <img
              v-if="getCachedProductImageUrl(props.row)"
              :src="getCachedProductImageUrl(props.row)"
              class="product-thumb"
              loading="lazy"
              decoding="async"
              alt=""
            />
            <div v-else class="product-thumb-placeholder">
              <q-icon name="image" size="22px" />
            </div>
            <q-tooltip>Foto</q-tooltip>
          </button>
        </q-td>
      </template>

      <template #body-cell-idle_cost_usd="props">
        <q-td :props="props" class="text-right text-weight-bold">
          {{ formatMoney(props.row.idle_cost_usd, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-performance_bucket="props">
        <q-td :props="props">
          <q-badge :color="bucketColor(props.row.performance_bucket)">
            {{ bucketLabel(props.row.performance_bucket) }}
          </q-badge>
        </q-td>
      </template>
      <template #body="props">
        <q-tr
          v-if="props.row.__group"
          :props="props"
          :class="['group-row', `group-row-level-${Math.min(Number(props.row.level || 0), 5)}`]"
        >
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <template v-if="col.name === 'image' && groupShowsImage(props.row)">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <div
              v-else-if="col.name === groupLabelColumnName(props.row)"
              class="group-cell-label"
              :style="{ paddingLeft: `${props.row.level * 18}px` }"
            >
              <q-btn
                flat
                dense
                round
                size="sm"
                :icon="isGroupExpanded(props.row.key) ? 'expand_more' : 'chevron_right'"
                @click.stop="toggleGroup(props.row.key)"
              />
              <span class="group-title">{{ props.row.label }}</span>
            </div>
            <span v-else>{{ formatGroupCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
        <q-tr v-else :props="props" class="cursor-pointer" @click="openPerformanceDialog(props.row)">
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <template v-if="col.name === 'image'">
              <button type="button" class="product-thumb-button" @click.stop="openProductImageDialog(props.row)">
                <img
                  v-if="getCachedProductImageUrl(props.row)"
                  :src="getCachedProductImageUrl(props.row)"
                  class="product-thumb"
                  loading="lazy"
                  decoding="async"
                  alt=""
                />
                <div v-else class="product-thumb-placeholder">
                  <q-icon name="image" size="22px" />
                </div>
                <q-tooltip>Foto</q-tooltip>
              </button>
            </template>
            <q-badge v-else-if="col.name === 'performance_bucket'" :color="bucketColor(props.row.performance_bucket)">
              {{ bucketLabel(props.row.performance_bucket) }}
            </q-badge>
            <span v-else>{{ formatTableCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
      </template>
    </q-table>

    <q-table
      v-else-if="activeTab === 'markets'"
      flat
      bordered
      row-key="market_key"
      class="performance-table sticky-dim-table sticky-dim-9 bg-white"
      :rows="filteredMarketRows"
      :columns="marketColumns"
      :loading="loading"
      :pagination="{ rowsPerPage: 100 }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('markets', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('markets', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('markets', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('markets', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('markets', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('markets', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('markets', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('markets', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('markets', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('markets', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('markets', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-stock_cost_value_usd="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.stock_cost_value_usd, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-risk_stock_cost_value_usd="props">
        <q-td :props="props" class="text-right text-negative text-weight-bold">
          {{ formatMoney(props.row.risk_stock_cost_value_usd, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-avg_gross_margin_90d="props">
        <q-td :props="props" class="text-right">
          {{ formatPercent(props.row.avg_gross_margin_90d) }}
        </q-td>
      </template>
    </q-table>

    <q-table
      v-else-if="salesBreakdownTabKeys.includes(activeTab)"
      flat
      bordered
      row-key="row_key"
      class="performance-table sticky-dim-table sticky-dim-9 bg-white"
      :rows="displayActiveSalesBreakdownTableRows"
      :columns="visibleSalesBreakdownColumns"
      :loading="loading || backendGroupedLoading"
      :pagination="{ rowsPerPage: 100, sortBy: 'performance_score', descending: true }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter(activeTab, props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter(activeTab, props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue(activeTab, props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey(activeTab, props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions(activeTab, props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter(activeTab, props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions(activeTab, props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions(activeTab, props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue(activeTab, props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected(activeTab, props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue(activeTab, props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-sales_usd_90d="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.sales_usd_90d, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-sales_usd_365d="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.sales_usd_365d, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-avg_price_usd_90d="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.avg_price_usd_90d, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-performance_bucket="props">
        <q-td :props="props">
          <q-badge :color="bucketColor(props.row.performance_bucket)">
            {{ bucketLabel(props.row.performance_bucket) }}
          </q-badge>
        </q-td>
      </template>
      <template #body="props">
        <q-tr
          v-if="props.row.__group"
          :props="props"
          :class="['group-row', `group-row-level-${Math.min(Number(props.row.level || 0), 5)}`]"
        >
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <div
              v-if="col.name === groupLabelColumnName(props.row)"
              class="group-cell-label"
              :style="{ paddingLeft: `${props.row.level * 18}px` }"
            >
              <q-btn
                flat
                dense
                round
                size="sm"
                :icon="isGroupExpanded(props.row.key) ? 'expand_more' : 'chevron_right'"
                @click.stop="toggleGroup(props.row.key)"
              />
              <span class="group-title">{{ props.row.label }}</span>
            </div>
            <span v-else>{{ formatGroupCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
        <q-tr v-else :props="props" class="cursor-pointer" @click="openPerformanceDialog(props.row)">
          <q-td v-for="col in props.cols" :key="col.name" :props="props" :class="groupCellClass(col.name)">
            <q-badge v-if="col.name === 'performance_bucket'" :color="bucketColor(props.row.performance_bucket)">
              {{ bucketLabel(props.row.performance_bucket) }}
            </q-badge>
            <span v-else>{{ formatTableCell(props.row, col) }}</span>
          </q-td>
        </q-tr>
      </template>
    </q-table>

    <div v-else-if="activeTab === 'customers'">
      <q-card flat bordered class="q-mb-sm">
        <q-card-section class="row q-col-gutter-sm items-center">
          <div class="col-12 col-md-4">
            <q-select
              v-model="customerBreakdown"
              dense
              outlined
              emit-value
              map-options
              label="Kırılım"
              :options="customerBreakdownOptions"
              @update:model-value="reload"
            />
          </div>
        </q-card-section>
      </q-card>
      <q-table
        flat
        bordered
        row-key="customer_key"
        class="performance-table sticky-dim-table sticky-dim-5 bg-white"
        :rows="filteredCustomerRows"
        :columns="customerColumns"
        :loading="loading"
        :pagination="{ rowsPerPage: 100 }"
        virtual-scroll
        :virtual-scroll-item-size="64"
      >
        <template #header-cell="props">
          <q-th :props="props" class="filterable-header-cell">
            <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('customers', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('customers', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('customers', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('customers', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('customers', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('customers', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('customers', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('customers', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('customers', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('customers', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('customers', props.col.name, 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">Sonuç yok</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>
        </template>
        <template #body-cell-sales_usd_90d="props">
          <q-td :props="props" class="text-right">
            {{ formatMoney(props.row.sales_usd_90d, 'USD') }}
          </q-td>
        </template>
        <template #body-cell-avg_price_usd_90d="props">
          <q-td :props="props" class="text-right">
            {{ formatMoney(props.row.avg_price_usd_90d, 'USD') }}
          </q-td>
        </template>
        <template #body-cell-sales_usd_365d="props">
          <q-td :props="props" class="text-right">
            {{ formatMoney(props.row.sales_usd_365d, 'USD') }}
          </q-td>
        </template>
      </q-table>
    </div>

    <q-table
      v-else
      flat
      bordered
      row-key="country_key"
      class="performance-table sticky-dim-table sticky-dim-3 bg-white"
      :rows="filteredCountryRows"
      :columns="countryColumns"
      :loading="loading"
      :pagination="{ rowsPerPage: 100 }"
      virtual-scroll
      :virtual-scroll-item-size="64"
    >
      <template #header-cell="props">
        <q-th :props="props" class="filterable-header-cell">
          <div class="header-with-filter">
            <span class="header-label" :title="props.col.label">{{ props.col.label }}</span>
            <q-btn
              v-if="isColumnFilterable(props.col.name)"
              dense
              flat
              round
              size="8px"
              icon="filter_alt"
              :color="hasColumnFilter('countries', props.col.name) ? 'primary' : 'grey-7'"
              class="header-filter-btn"
              @click.stop
            >
              <q-badge v-if="hasColumnFilter('countries', props.col.name)" color="primary" floating rounded>
                {{ getColumnFilterBadgeValue('countries', props.col.name) }}
              </q-badge>
              <q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
                <div class="excel-filter-menu">
                  <q-input
                    v-model="columnFilterSearch[filterKey('countries', props.col.name)]"
                    dense
                    outlined
                    clearable
                    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="Tümünü Seç" @click="selectAllColumnFilterOptions('countries', props.col.name)" />
                    <q-btn flat dense size="sm" label="Temizle" @click="clearColumnFilter('countries', props.col.name)" />
                  </div>
                  <q-virtual-scroll
                    v-if="columnFilterOptions('countries', props.col.name).length > 0"
                    class="excel-filter-options"
                    :items="columnFilterOptions('countries', props.col.name)"
                    :virtual-scroll-item-size="32"
                    separator
                  >
                    <template #default="{ item: option }">
                      <q-item
                        :key="`${props.col.name}-${option.value}`"
                        dense
                        clickable
                        class="excel-filter-option"
                        @click="toggleColumnFilterValue('countries', props.col.name, option.value)"
                      >
                        <q-item-section avatar>
                          <q-checkbox
                            dense
                            size="sm"
                            :model-value="isColumnFilterValueSelected('countries', props.col.name, option.value)"
                            @update:model-value="() => toggleColumnFilterValue('countries', props.col.name, 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">Sonuç yok</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>
      </template>
      <template #body-cell-sales_usd_90d="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.sales_usd_90d, 'USD') }}
        </q-td>
      </template>
      <template #body-cell-avg_price_usd_90d="props">
        <q-td :props="props" class="text-right">
          {{ formatMoney(props.row.avg_price_usd_90d, 'USD') }}
        </q-td>
      </template>
    </q-table>

    <q-dialog v-model="imageDialog" maximized>
      <q-card class="product-image-dialog">
        <q-card-section class="row items-center q-pb-sm">
          <div>
            <div class="text-h6">{{ imageDialogTitle }}</div>
            <div class="text-caption text-grey-7">{{ imageDialogSubtitle }}</div>
          </div>
          <q-space />
          <q-btn v-close-popup flat round dense icon="close" />
        </q-card-section>
        <q-separator />
        <q-card-section class="product-image-dialog-body">
          <div class="performance-image-layout">
            <aside class="image-product-fields">
              <div class="image-section-title">Ürün Bilgileri</div>
              <div v-for="item in imageDialogInfoRows" :key="item.key" class="image-field-row">
                <span class="k">{{ item.label }}</span>
                <span class="v">{{ item.value }}</span>
              </div>

              <div class="image-product-section">
                <div class="image-section-title">Beden Stokları</div>
                <q-inner-loading :showing="detailLoading">
                  <q-spinner size="24px" color="primary" />
                </q-inner-loading>
                <div v-if="detailStockSizes.length" class="image-size-stock-grid">
                  <div v-for="item in detailStockSizes" :key="item.size_code" class="image-size-stock-cell">
                    <span class="image-size-label">{{ item.size_code || '-' }}</span>
                    <span class="image-size-qty">{{ formatNumber(item.stock_qty, 0) }}</span>
                  </div>
                </div>
                <div v-else-if="!detailLoading" class="image-empty-text">Beden stoku bulunamadi</div>
              </div>
            </aside>

            <section class="image-media-panel">
              <q-carousel
                v-if="imageDialogUrls.length"
                v-model="imageSlide"
                animated
                arrows
                navigation
                infinite
                swipeable
                class="product-image-carousel"
              >
                <q-carousel-slide
                  v-for="(url, idx) in imageDialogUrls"
                  :key="`${url}-${idx}`"
                  :name="idx"
                  class="column no-wrap flex-center"
                >
                  <q-img :src="url" fit="contain" class="product-image-large" />
                </q-carousel-slide>
              </q-carousel>
              <div v-else class="product-image-empty">
                <q-icon name="image_not_supported" size="48px" />
                <div class="text-subtitle2 q-mt-sm">Foto bulunamadi</div>
              </div>
            </section>

            <section class="image-sales-panel">
              <div class="row q-col-gutter-xs q-mb-sm">
                <div v-for="card in imageDialogPerformanceCards" :key="card.key" class="col-6 col-md-3 col-lg-4">
                  <q-card flat bordered class="metric-card image-metric-card">
                    <q-card-section>
                      <div class="text-caption text-grey-7">{{ card.label }}</div>
                      <div class="metric-value">{{ card.value }}</div>
                    </q-card-section>
                  </q-card>
                </div>
              </div>
              <q-table
                flat
                bordered
                dense
                title="Satış / Müşteri Özeti"
                row-key="detail_key"
                :rows="detailSalesRows"
                :columns="detailSalesColumns"
                :loading="detailLoading"
                :pagination="{ rowsPerPage: 50 }"
              />
            </section>
          </div>
        </q-card-section>
      </q-card>
    </q-dialog>

    <q-dialog v-model="performanceDialog" maximized>
      <q-card class="product-performance-dialog">
        <q-card-section class="row items-center q-pb-sm">
          <div>
            <div class="text-h6">{{ performanceDialogTitle }}</div>
            <div class="text-caption text-grey-7">{{ performanceDialogSubtitle }}</div>
          </div>
          <q-space />
          <q-btn v-close-popup flat round dense icon="close" />
        </q-card-section>
        <q-separator />
        <q-card-section class="q-pa-sm">
          <div class="row q-col-gutter-sm q-mb-sm">
            <div v-for="card in performanceCards" :key="card.key" class="col-6 col-md-2">
              <q-card flat bordered class="metric-card">
                <q-card-section>
                  <div class="text-caption text-grey-7">{{ card.label }}</div>
                  <div class="metric-value">{{ card.value }}</div>
                </q-card-section>
              </q-card>
            </div>
          </div>
          <div class="row q-col-gutter-sm">
            <div class="col-12 col-md-4">
              <q-table
                flat
                bordered
                dense
                title="Beden Stok"
                row-key="size_code"
                :rows="detailStockSizes"
                :columns="detailStockColumns"
                :loading="detailLoading"
                :pagination="{ rowsPerPage: 50 }"
                virtual-scroll
                :virtual-scroll-item-size="48"
              />
            </div>
            <div class="col-12 col-md-8">
              <q-table
                flat
                bordered
                dense
                title="Satış / Müşteri Özeti"
                row-key="detail_key"
                :rows="detailSalesRows"
                :columns="detailSalesColumns"
                :loading="detailLoading"
                :pagination="{ rowsPerPage: 50 }"
                virtual-scroll
                :virtual-scroll-item-size="48"
              />
            </div>
          </div>
        </q-card-section>
      </q-card>
    </q-dialog>
  </q-page>
</template>

<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { Notify } from 'quasar'
import api from 'src/services/api'
import { useProductPerformanceStore } from 'src/stores/productPerformanceStore'
import { formatMoney, formatNumber, formatPercent } from 'src/utils/formatters'

const performanceStore = useProductPerformanceStore()

const loading = ref(false)
const rows = ref([])
const generalRows = ref([])
const orderAnalysisRows = ref([])
const orderMarketRows = ref([])
const orderCustomerRows = ref([])
const orderProductCustomerRows = ref([])
const orderMarketDetailRows = ref([])
const orderAnalysisLoaded = ref(false)
const orderProductCustomersLoaded = ref(false)
const orderMarketDetailsLoaded = ref(false)
const orderAnalysisMode = ref('product')
const marketRows = ref([])
const countryRows = ref([])
const customerRows = ref([])
const salesBreakdownRows = reactive({
  sales_color_yaka_market_customer: [],
  sales_product_country_segment_market_customer: [],
  sales_market_customer_product: [],
  sales_country_segment_market_customer_product: []
})
const summary = ref({})
const activeTab = ref('products')
const customerBreakdown = ref('market_customer')
const selectedPeriods = ref(['90', '180', '360', 'total'])
const imageUrlByKey = ref({})
const imageListByKey = ref({})
const imageDialog = ref(false)
const imageDialogUrls = ref([])
const imageDialogTitle = ref('')
const imageDialogSubtitle = ref('')
const imageSlide = ref(0)
const imageDialogRow = ref(null)
const performanceDialog = ref(false)
const performanceDialogRow = ref(null)
const performanceDialogTitle = ref('')
const performanceDialogSubtitle = ref('')
const detailLoading = ref(false)
const detailSalesRows = ref([])
const detailStockSizes = ref([])
const backendGroupedRows = ref({})
const backendGroupedLoading = ref(false)
const imagePrimeLoading = ref(false)
const filterBusy = ref(false)
let backendGroupedTimer = null
let imagePrimeActiveRequests = 0

const columnFilters = reactive({})
const columnFilterSearch = reactive({})
const expandedGroups = ref({})
const selectedExpandLevelKeysByTab = reactive({
  products: ['kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'market_key'],
  sales_color_yaka_market_customer: ['color_code', 'yaka_kodu', 'market_key', 'customer_code'],
  idle: ['kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code'],
  sales_product_country_segment_market_customer: ['product_code', 'country', 'customer_segment', 'market_key', 'customer_code'],
  sales_market_customer_product: ['market_key', 'customer_code', 'product_code', 'color_code', 'yaka_kodu'],
  sales_country_segment_market_customer_product: ['country', 'customer_segment', 'market_key', 'customer_code', 'product_code', 'color_code', 'yaka_kodu'],
  order_product_customers: ['product_code', 'market_key', 'customer_code'],
  order_market_details: ['market_key', 'customer_code', 'product_code', 'color_code', 'yaka_kodu']
})
const productKpiFetchLimit = 50000
const performanceTabs = [
  { name: 'products', icon: 'inventory_2', label: 'Ürün KPI' },
  { name: 'sales_color_yaka_market_customer', icon: 'palette', label: 'Renk > Yaka > Piyasa > Müşteri' },
  { name: 'idle', icon: 'warning', label: 'Atıl Stok / Maliyet' },
  { name: 'sales_product_country_segment_market_customer', icon: 'account_tree', label: 'Ürün > Ülke > Segment > Piyasa > Müşteri' },
  { name: 'sales_market_customer_product', icon: 'groups', label: 'Piyasa > Müşteri > Ürün Satış KPI' },
  { name: 'sales_country_segment_market_customer_product', icon: 'public', label: 'Ülke > Segment > Piyasa > Müşteri > Ürün Satış KPI' },
  { name: 'order_product_customers', icon: 'assignment_ind', label: 'Ürün > Piyasa > Müşteri Sipariş' },
  { name: 'order_market_details', icon: 'receipt_long', label: 'Piyasa > Müşteri > Ürün Sipariş' }
]
const pageBusy = computed(() => loading.value || backendGroupedLoading.value || imagePrimeLoading.value || filterBusy.value)

const pagination = ref({
  page: 1,
  rowsPerPage: 100,
  rowsNumber: 0,
  sortBy: 'performance_score',
  descending: true
})

const bucketOptions = [
  { label: 'Yıldız Ürün', value: 'YILDIZ_URUN' },
  { label: 'Stoksuz Talep', value: 'STOKSUZ_TALEP' },
  { label: 'Stok Riski', value: 'STOK_RISKI' },
  { label: 'Fiyat Baskısı', value: 'FIYAT_BASKISI' },
  { label: 'Fiyat Fırsatı', value: 'FIYAT_FIRSATI' },
  { label: 'Maliyet Yok', value: 'MALIYET_YOK' },
  { label: 'Takip', value: 'TAKIP' }
]

const periodOptions = [
  { label: '90G', value: '90' },
  { label: '180G', value: '180' },
  { label: '360G', value: '360' },
  { label: 'Genel', value: 'total' }
]

const customerBreakdownOptions = [
  { label: 'Piyasa > Müşteri', value: 'market_customer' },
  { label: 'Ülke > Müşteri', value: 'country_customer' },
  { label: 'Piyasa > Ülke > Müşteri', value: 'market_country_customer' }
]

const salesBreakdownModes = {
  sales_color_yaka_market_customer: 'color_yaka_market_customer',
  sales_product_country_segment_market_customer: 'product_country_segment_market_customer',
  sales_market_customer_product: 'market_customer_product',
  sales_country_segment_market_customer_product: 'country_segment_market_customer_product'
}

const salesBreakdownTabKeys = Object.keys(salesBreakdownModes)

const detailStockColumns = [
  { name: 'size_code', label: 'Beden', field: 'size_code', align: 'left', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true }
]

const detailSalesColumns = [
  { name: 'sales_date', label: 'Tarih', field: 'sales_date', align: 'left', sortable: true },
  { name: 'ref_number', label: 'Ref', field: 'ref_number', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'country', label: 'Ülke', field: 'country', align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'sales_qty', label: 'Adet', field: row => formatNumber(row.sales_qty, 0), align: 'right', sortable: true },
  { name: 'sales_usd', label: 'USD', field: row => formatMoney(row.sales_usd, 'USD'), align: 'right', sortable: true },
  { name: 'avg_price_usd', label: 'Ort. USD', field: row => formatMoney(row.avg_price_usd, 'USD'), align: 'right', sortable: true }
]

const columns = [
  { name: 'image', label: 'Foto', field: 'image', align: 'center' },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left' },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left' },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left' },
  { name: 'kategori', label: 'Kategori', field: 'kategori', align: 'left' },
  { name: 'askili_yan', label: 'Askılı/Yan', field: 'askili_yan', align: 'left' },
  { name: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', field: row => row.urun_ilk_grubu || row.yas_grubu || '', align: 'left' },
  { name: 'urun_ana_grubu', label: 'Ürün Ana Grubu', field: row => row.urun_ana_grubu || row.seri || '', align: 'left' },
  { name: 'urun_alt_grubu', label: 'Ürün Alt Grubu', field: 'urun_alt_grubu', align: 'left' },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Satış', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_180d', label: '180G Satış', field: row => formatNumber(row.sales_qty_180d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_365d', label: '360G Satış', field: row => formatNumber(row.sales_qty_365d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_total', label: 'Genel Satış', field: row => formatNumber(row.sales_qty_total, 0), align: 'right', sortable: true },
  { name: 'sales_usd_90d', label: '90G USD', field: 'sales_usd_90d', align: 'right', sortable: true },
  { name: 'sales_usd_180d', label: '180G USD', field: 'sales_usd_180d', align: 'right', sortable: true },
  { name: 'sales_usd_365d', label: '360G USD', field: 'sales_usd_365d', align: 'right', sortable: true },
  { name: 'sales_usd_total', label: 'Genel USD', field: 'sales_usd_total', align: 'right', sortable: true },
  { name: 'stock_days_90d', label: 'Stok Gün', field: row => formatNumber(row.stock_days_90d, 1), align: 'right', sortable: true },
  { name: 'stock_days_180d', label: '180G Stok Gün', field: row => formatNumber(row.stock_days_180d, 1), align: 'right', sortable: true },
  { name: 'stock_days_total', label: 'Genel Stok Gün', field: row => formatNumber(row.stock_days_total, 1), align: 'right', sortable: true },
  { name: 'stock_turnover_90d', label: '90G Stok Devir', field: row => formatNumber(row.stock_turnover_90d, 2), align: 'right', sortable: true },
  { name: 'stock_turnover_180d', label: '180G Stok Devir', field: row => formatNumber(row.stock_turnover_180d, 2), align: 'right', sortable: true },
  { name: 'stock_turnover_365d', label: '360G Stok Devir', field: row => formatNumber(row.stock_turnover_365d, 2), align: 'right', sortable: true },
  { name: 'stock_turnover_total', label: 'Genel Stok Devir', field: row => formatNumber(row.stock_turnover_total, 2), align: 'right', sortable: true },
  { name: 'avg_price_usd_90d', label: 'Ort. USD', field: row => formatMoney(row.avg_price_usd_90d, 'USD'), align: 'right' },
  { name: 'avg_price_usd_180d', label: '180G Ort. USD', field: row => formatMoney(row.avg_price_usd_180d, 'USD'), align: 'right' },
  { name: 'avg_price_usd_365d', label: '360G Ort. USD', field: row => formatMoney(row.avg_price_usd_365d, 'USD'), align: 'right' },
  { name: 'avg_price_usd_total', label: 'Genel Ort. USD', field: row => formatMoney(row.avg_price_usd_total, 'USD'), align: 'right' },
  { name: 'base_price_usd', label: 'Ort. USD Taban Maliyeti', field: row => formatMoney(row.base_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd', label: 'Ort. USD Çıplak Maliyeti', field: row => formatMoney(row.cost_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_base_90d', label: '90G P.Başı Taban K/Z', field: row => formatMoney(row.unit_profit_base_90d, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_cost_90d', label: '90G P.Başı Çıplak K/Z', field: row => formatMoney(row.unit_profit_cost_90d, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_base_180d', label: '180G P.Başı Taban K/Z', field: row => formatMoney(row.unit_profit_base_180d, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_cost_180d', label: '180G P.Başı Çıplak K/Z', field: row => formatMoney(row.unit_profit_cost_180d, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_base_total', label: 'Genel P.Başı Taban K/Z', field: row => formatMoney(row.unit_profit_base_total, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_cost_total', label: 'Genel P.Başı Çıplak K/Z', field: row => formatMoney(row.unit_profit_cost_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_usd_90d', label: '90G Toplam K/Z', field: row => formatMoney(row.gross_profit_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_usd_180d', label: '180G Toplam K/Z', field: row => formatMoney(row.gross_profit_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_usd_total', label: 'Genel Toplam K/Z', field: row => formatMoney(row.gross_profit_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_90d', label: '90G Taban Marj', field: row => formatPercent(row.gross_margin_base_90d), align: 'right', sortable: true },
  { name: 'gross_margin_cost_90d', label: '90G Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_90d), align: 'right', sortable: true },
  { name: 'gross_margin_base_180d', label: '180G Taban Marj', field: row => formatPercent(row.gross_margin_base_180d), align: 'right', sortable: true },
  { name: 'gross_margin_cost_180d', label: '180G Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_180d), align: 'right', sortable: true },
  { name: 'gross_margin_base_total', label: 'Genel Taban Marj', field: row => formatPercent(row.gross_margin_base_total), align: 'right', sortable: true },
  { name: 'gross_margin_cost_total', label: 'Genel Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_total), align: 'right', sortable: true },
  { name: 'market_count_90d', label: '90G Piyasa', field: row => formatNumber(row.market_count_90d, 0), align: 'right', sortable: true },
  { name: 'customer_count_90d', label: '90G Müşteri', field: row => formatNumber(row.customer_count_90d, 0), align: 'right', sortable: true },
  { name: 'market_count_total', label: 'Genel Piyasa', field: row => formatNumber(row.market_count_total, 0), align: 'right', sortable: true },
  { name: 'customer_count_total', label: 'Genel Müşteri', field: row => formatNumber(row.customer_count_total, 0), align: 'right', sortable: true },
  { name: 'sales_index_90d', label: 'Piyasa End.', field: row => formatNumber(row.sales_index_90d, 2), align: 'right', sortable: true },
  { name: 'sales_index_total', label: 'Genel Endeks', field: row => formatNumber(row.sales_index_total, 2), align: 'right', sortable: true },
  { name: 'performance_score', label: 'Skor', field: row => formatNumber(row.performance_score, 1), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left' },
  { name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' }
]

const periodColumnRules = [
  { period: '90', match: name => name.includes('_90d') },
  { period: '180', match: name => name.includes('_180d') },
  { period: '360', match: name => name.includes('_365d') },
  { period: 'total', match: name => name.includes('_total') }
]

const selectedPeriodSet = computed(() => new Set(selectedPeriods.value))

function columnPeriod (name) {
  return periodColumnRules.find(rule => rule.match(name))?.period || ''
}

function visiblePeriodColumn (col) {
  const period = columnPeriod(col.name)
  return !period || selectedPeriodSet.value.has(period)
}

const productColumns = computed(() => columns.filter(visiblePeriodColumn))

const generalColumns = [
  { name: 'image', label: 'Foto', field: 'image', align: 'center' },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left', sortable: true },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left', sortable: true },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left', sortable: true },
  { name: 'kategori', label: 'Kategori', field: 'kategori', align: 'left', sortable: true },
  { name: 'askili_yan', label: 'Askılı/Yan', field: 'askili_yan', align: 'left', sortable: true },
  { name: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', field: row => row.urun_ilk_grubu || row.yas_grubu || '', align: 'left', sortable: true },
  { name: 'urun_ana_grubu', label: 'Ürün Ana Grubu', field: row => row.urun_ana_grubu || row.seri || '', align: 'left', sortable: true },
  { name: 'urun_alt_grubu', label: 'Ürün Alt Grubu', field: 'urun_alt_grubu', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'period_start', label: 'Başlangıç', field: 'period_start', align: 'left', sortable: true },
  { name: 'period_end', label: 'Bitiş', field: 'period_end', align: 'left', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'sales_qty_total', label: 'Toplam Satış', field: row => formatNumber(row.sales_qty_total, 0), align: 'right', sortable: true },
  { name: 'sales_usd_total', label: 'Toplam USD', field: row => formatMoney(row.sales_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'avg_daily_sales_total', label: 'Günlük Ort.', field: row => formatNumber(row.avg_daily_sales_total, 3), align: 'right', sortable: true },
  { name: 'stock_days_total', label: 'Genel Stok Gün', field: row => formatNumber(row.stock_days_total, 1), align: 'right', sortable: true },
  { name: 'avg_price_usd_total', label: 'Genel Ort. USD', field: row => formatMoney(row.avg_price_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'base_price_usd', label: 'USD Taban Maliyeti', field: row => formatMoney(row.base_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd', label: 'USD Çıplak Maliyeti', field: row => formatMoney(row.cost_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_base_total', label: 'P.Başı Taban K/Z', field: row => formatMoney(row.unit_profit_base_total, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_cost_total', label: 'P.Başı Çıplak K/Z', field: row => formatMoney(row.unit_profit_cost_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_usd_total', label: 'Toplam K/Z', field: row => formatMoney(row.gross_profit_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_total', label: 'Genel Taban Marj', field: row => formatPercent(row.gross_margin_base_total), align: 'right', sortable: true },
  { name: 'gross_margin_cost_total', label: 'Genel Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_total), align: 'right', sortable: true },
  { name: 'market_count_total', label: 'Toplam Piyasa', field: row => formatNumber(row.market_count_total, 0), align: 'right', sortable: true },
  { name: 'customer_count_total', label: 'Toplam Müşteri', field: row => formatNumber(row.customer_count_total, 0), align: 'right', sortable: true },
  { name: 'invoice_count_total', label: 'Fatura', field: row => formatNumber(row.invoice_count_total, 0), align: 'right', sortable: true },
  { name: 'sales_index_total', label: 'Genel Endeks', field: row => formatNumber(row.sales_index_total, 2), align: 'right', sortable: true },
  { name: 'performance_score', label: 'Genel Skor', field: row => formatNumber(row.performance_score, 1), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'first_sale_date', label: 'İlk Satış', field: 'first_sale_date', align: 'left', sortable: true },
  { name: 'last_sale_date', label: 'Son Satış', field: 'last_sale_date', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' }
]

const orderAnalysisColumns = [
  { name: 'image', label: 'Foto', field: 'image', align: 'center' },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left', sortable: true },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left', sortable: true },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left', sortable: true },
  { name: 'kategori', label: 'Kategori', field: 'kategori', align: 'left', sortable: true },
  { name: 'askili_yan', label: 'Askılı/Yan', field: 'askili_yan', align: 'left', sortable: true },
  { name: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', field: row => row.urun_ilk_grubu || row.yas_grubu || '', align: 'left', sortable: true },
  { name: 'urun_ana_grubu', label: 'Ürün Ana Grubu', field: row => row.urun_ana_grubu || row.seri || '', align: 'left', sortable: true },
  { name: 'urun_alt_grubu', label: 'Ürün Alt Grubu', field: 'urun_alt_grubu', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'order_qty', label: 'Açık Sipariş', field: row => formatNumber(row.order_qty, 0), align: 'right', sortable: true },
  { name: 'order_usd', label: 'Sipariş USD', field: row => formatMoney(row.order_usd, 'USD'), align: 'right', sortable: true },
  { name: 'avg_order_price_usd', label: 'Ort. Sipariş USD', field: row => formatMoney(row.avg_order_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'net_stock_after_order', label: 'Stok - Sipariş', field: 'net_stock_after_order', align: 'right', sortable: true },
  { name: 'base_price_usd', label: 'USD Taban Maliyeti', field: row => formatMoney(row.base_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd', label: 'USD Çıplak Maliyeti', field: row => formatMoney(row.cost_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_base_usd', label: 'P.Başı Taban K/Z', field: row => formatMoney(row.unit_profit_base_usd, 'USD'), align: 'right', sortable: true },
  { name: 'unit_profit_cost_usd', label: 'P.Başı Çıplak K/Z', field: row => formatMoney(row.unit_profit_cost_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_base_usd', label: 'Taban Toplam K/Z', field: row => formatMoney(row.expected_profit_base_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_cost_usd', label: 'Çıplak Toplam K/Z', field: 'expected_profit_cost_usd', align: 'right', sortable: true },
  { name: 'expected_margin_cost', label: 'Beklenen Marj', field: row => formatPercent(row.expected_margin_cost), align: 'right', sortable: true },
  { name: 'market_count', label: 'Piyasa', field: row => formatNumber(row.market_count, 0), align: 'right', sortable: true },
  { name: 'customer_count', label: 'Müşteri', field: row => formatNumber(row.customer_count, 0), align: 'right', sortable: true },
  { name: 'order_count', label: 'Sipariş', field: row => formatNumber(row.order_count, 0), align: 'right', sortable: true },
  { name: 'line_count', label: 'Satır', field: row => formatNumber(row.line_count, 0), align: 'right', sortable: true },
  { name: 'earliest_due_date', label: 'İlk Termin', field: 'earliest_due_date', align: 'left', sortable: true },
  { name: 'overdue_qty', label: 'Geciken Adet', field: row => formatNumber(row.overdue_qty, 0), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Yorum', field: 'recommendation', align: 'left' }
]

const orderGroupColumns = [
  { name: 'group_key', label: 'Kırılım', field: row => orderGroupLabel(row), align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'product_count', label: 'Ürün', field: row => formatNumber(row.product_count, 0), align: 'right', sortable: true },
  { name: 'order_qty', label: 'Açık Sipariş', field: row => formatNumber(row.order_qty, 0), align: 'right', sortable: true },
  { name: 'order_usd', label: 'Sipariş USD', field: row => formatMoney(row.order_usd, 'USD'), align: 'right', sortable: true },
  { name: 'avg_order_price_usd', label: 'Ort. USD', field: row => formatMoney(row.avg_order_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'base_cost_usd', label: 'Taban Maliyet USD', field: row => formatMoney(row.base_cost_usd, 'USD'), align: 'right', sortable: true },
  { name: 'cost_amount_usd', label: 'Çıplak Maliyet USD', field: row => formatMoney(row.cost_amount_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_base_usd', label: 'Brüt K/Z', field: row => formatMoney(row.expected_profit_base_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_cost_usd', label: 'Yakl. Net K/Z', field: 'expected_profit_cost_usd', align: 'right', sortable: true },
  { name: 'expected_margin_base', label: 'Brüt Marj', field: row => formatPercent(row.expected_margin_base), align: 'right', sortable: true },
  { name: 'expected_margin_cost', label: 'Yakl. Net Marj', field: row => formatPercent(row.expected_margin_cost), align: 'right', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'net_stock_after_order', label: 'Stok - Sipariş', field: 'net_stock_after_order', align: 'right', sortable: true },
  { name: 'market_count', label: 'Piyasa', field: row => formatNumber(row.market_count, 0), align: 'right', sortable: true },
  { name: 'customer_count', label: 'Müşteri', field: row => formatNumber(row.customer_count, 0), align: 'right', sortable: true },
  { name: 'order_count', label: 'Sipariş', field: row => formatNumber(row.order_count, 0), align: 'right', sortable: true },
  { name: 'line_count', label: 'Satır', field: row => formatNumber(row.line_count, 0), align: 'right', sortable: true },
  { name: 'overdue_qty', label: 'Geciken Adet', field: row => formatNumber(row.overdue_qty, 0), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Yorum', field: 'recommendation', align: 'left' }
]

const orderProductCustomerColumns = [
  { name: 'image', label: 'Foto', field: 'image', align: 'center' },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left', sortable: true },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left', sortable: true },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'order_qty', label: 'Açık Sipariş', field: row => formatNumber(row.order_qty, 0), align: 'right', sortable: true },
  { name: 'order_usd', label: 'Sipariş USD', field: row => formatMoney(row.order_usd, 'USD'), align: 'right', sortable: true },
  { name: 'avg_order_price_usd', label: 'Ort. USD', field: row => formatMoney(row.avg_order_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'net_stock_after_order', label: 'Stok - Sipariş', field: 'net_stock_after_order', align: 'right', sortable: true },
  { name: 'base_price_usd', label: 'Taban USD', field: row => formatMoney(row.base_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd', label: 'Çıplak USD', field: row => formatMoney(row.cost_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_base_usd', label: 'Brüt K/Z', field: row => formatMoney(row.expected_profit_base_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_cost_usd', label: 'Yakl. Net K/Z', field: 'expected_profit_cost_usd', align: 'right', sortable: true },
  { name: 'expected_margin_base', label: 'Brüt Marj', field: row => formatPercent(row.expected_margin_base), align: 'right', sortable: true },
  { name: 'expected_margin_cost', label: 'Yakl. Net Marj', field: row => formatPercent(row.expected_margin_cost), align: 'right', sortable: true },
  { name: 'order_count', label: 'Sipariş', field: row => formatNumber(row.order_count, 0), align: 'right', sortable: true },
  { name: 'line_count', label: 'Satır', field: row => formatNumber(row.line_count, 0), align: 'right', sortable: true },
  { name: 'overdue_qty', label: 'Geciken Adet', field: row => formatNumber(row.overdue_qty, 0), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Yorum', field: 'recommendation', align: 'left' }
]

const orderMarketDetailColumns = [
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'order_number', label: 'Sipariş No', field: 'order_number', align: 'left', sortable: true },
  { name: 'order_date', label: 'Sipariş Tarihi', field: 'order_date', align: 'left', sortable: true },
  { name: 'due_date', label: 'Termin', field: 'due_date', align: 'left', sortable: true },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left', sortable: true },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left', sortable: true },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left', sortable: true },
  { name: 'order_qty', label: 'Adet', field: row => formatNumber(row.order_qty, 0), align: 'right', sortable: true },
  { name: 'order_usd', label: 'USD', field: row => formatMoney(row.order_usd, 'USD'), align: 'right', sortable: true },
  { name: 'avg_order_price_usd', label: 'Ort. USD', field: row => formatMoney(row.avg_order_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'net_stock_after_order', label: 'Stok - Sipariş', field: 'net_stock_after_order', align: 'right', sortable: true },
  { name: 'expected_profit_base_usd', label: 'Brüt K/Z', field: row => formatMoney(row.expected_profit_base_usd, 'USD'), align: 'right', sortable: true },
  { name: 'expected_profit_cost_usd', label: 'Yakl. Net K/Z', field: 'expected_profit_cost_usd', align: 'right', sortable: true },
  { name: 'expected_margin_base', label: 'Brüt Marj', field: row => formatPercent(row.expected_margin_base), align: 'right', sortable: true },
  { name: 'expected_margin_cost', label: 'Yakl. Net Marj', field: row => formatPercent(row.expected_margin_cost), align: 'right', sortable: true },
  { name: 'is_overdue', label: 'Gecikti', field: row => row.is_overdue ? 'Evet' : 'Hayır', align: 'left', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Yorum', field: 'recommendation', align: 'left' }
]

const idleColumns = [
  { name: 'image', label: 'Foto', field: 'image', align: 'center' },
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left' },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left' },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left' },
  { name: 'kategori', label: 'Kategori', field: 'kategori', align: 'left' },
  { name: 'askili_yan', label: 'Askılı/Yan', field: 'askili_yan', align: 'left' },
  { name: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', field: row => row.urun_ilk_grubu || row.yas_grubu || '', align: 'left' },
  { name: 'urun_ana_grubu', label: 'Ürün Ana Grubu', field: row => row.urun_ana_grubu || row.seri || '', align: 'left' },
  { name: 'urun_alt_grubu', label: 'Ürün Alt Grubu', field: 'urun_alt_grubu', align: 'left' },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'cost_price_usd', label: 'Maliyet USD', field: row => formatMoney(row.cost_price_usd, 'USD'), align: 'right', sortable: true },
  { name: 'idle_cost_usd', label: 'Stok Maliyeti USD', field: 'idle_cost_usd', align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Satış', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'stock_days_90d', label: 'Stok Gün', field: row => formatNumber(row.stock_days_90d, 1), align: 'right', sortable: true },
  { name: 'stock_turnover_90d', label: '90G Stok Devir', field: row => formatNumber(row.stock_turnover_90d, 2), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left' },
  { name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' }
]

const marketColumns = [
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'kategori', label: 'Kategori', field: 'kategori', align: 'left' },
  { name: 'askili_yan', label: 'Askılı/Yan', field: 'askili_yan', align: 'left' },
  { name: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', field: row => row.urun_ilk_grubu || row.yas_grubu || '', align: 'left' },
  { name: 'urun_ana_grubu', label: 'Ürün Ana Grubu', field: row => row.urun_ana_grubu || row.seri || '', align: 'left' },
  { name: 'urun_alt_grubu', label: 'Ürün Alt Grubu', field: 'urun_alt_grubu', align: 'left' },
  { name: 'product_count', label: 'Ürün', field: row => formatNumber(row.product_count, 0), align: 'right', sortable: true },
  { name: 'star_count', label: 'Yıldız', field: row => formatNumber(row.star_count, 0), align: 'right', sortable: true },
  { name: 'stock_risk_count', label: 'Risk', field: row => formatNumber(row.stock_risk_count, 0), align: 'right', sortable: true },
  { name: 'stock_qty', label: 'Stok', field: row => formatNumber(row.stock_qty, 0), align: 'right', sortable: true },
  { name: 'stock_cost_value_usd', label: 'Stok Maliyeti', field: 'stock_cost_value_usd', align: 'right', sortable: true },
  { name: 'risk_stock_cost_value_usd', label: 'Risk Maliyeti', field: 'risk_stock_cost_value_usd', align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Satış', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_90d', label: '90G USD', field: row => formatMoney(row.sales_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'avg_gross_margin_90d', label: 'Ort. Marj', field: 'avg_gross_margin_90d', align: 'right', sortable: true },
  { name: 'avg_stock_days_90d', label: 'Ort. Stok Gün', field: row => formatNumber(row.avg_stock_days_90d, 1), align: 'right', sortable: true }
]

const countryColumns = [
  { name: 'country', label: 'Ülke', field: 'country', align: 'left', sortable: true },
  { name: 'customer_segment', label: 'Müşteri Segmenti', field: 'customer_segment', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left' },
  { name: 'product_count', label: 'Ürün', field: row => formatNumber(row.product_count, 0), align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Adet', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_90d', label: '90G USD', field: row => formatMoney(row.sales_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'avg_price_usd_90d', label: 'Ort. USD', field: row => formatMoney(row.avg_price_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'customer_count_90d', label: 'Müşteri', field: row => formatNumber(row.customer_count_90d, 0), align: 'right', sortable: true },
  { name: 'invoice_count_90d', label: 'Fatura', field: row => formatNumber(row.invoice_count_90d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_365d', label: '360G Adet', field: row => formatNumber(row.sales_qty_365d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_365d', label: '360G USD', field: row => formatMoney(row.sales_usd_365d, 'USD'), align: 'right', sortable: true }
]

const customerColumns = [
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'country', label: 'Ülke', field: 'country', align: 'left', sortable: true },
  { name: 'customer_segment', label: 'Segment', field: 'customer_segment', align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'product_count', label: 'Ürün', field: row => formatNumber(row.product_count, 0), align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Adet', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_90d', label: '90G USD', field: 'sales_usd_90d', align: 'right', sortable: true },
  { name: 'avg_price_usd_90d', label: 'Ort. USD', field: 'avg_price_usd_90d', align: 'right', sortable: true },
  { name: 'base_price_usd_90d', label: '90G Taban', field: row => formatMoney(row.base_price_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd_90d', label: '90G Çıplak', field: row => formatMoney(row.cost_price_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_base_usd_90d', label: '90G Taban K/Z', field: row => formatMoney(row.gross_profit_base_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_cost_usd_90d', label: '90G Çıplak K/Z', field: row => formatMoney(row.gross_profit_cost_usd_90d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_90d', label: '90G Taban Marj', field: row => formatPercent(row.gross_margin_base_90d), align: 'right', sortable: true },
  { name: 'gross_margin_cost_90d', label: '90G Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_90d), align: 'right', sortable: true },
  { name: 'invoice_count_90d', label: 'Fatura', field: row => formatNumber(row.invoice_count_90d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_365d', label: '360G Adet', field: row => formatNumber(row.sales_qty_365d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_365d', label: '360G USD', field: 'sales_usd_365d', align: 'right', sortable: true },
  { name: 'last_sale_date', label: 'Son Satış', field: 'last_sale_date', align: 'left', sortable: true }
]

const salesBreakdownColumns = [
  { name: 'product_code', label: 'Ürün', field: 'product_code', align: 'left', sortable: true },
  { name: 'color_code', label: 'Renk', field: 'color_code', align: 'left', sortable: true },
  { name: 'yaka_kodu', label: 'Yaka', field: 'yaka_kodu', align: 'left', sortable: true },
  { name: 'item_description', label: 'Açıklama', field: 'item_description', align: 'left', sortable: true },
  { name: 'country', label: 'Ülke', field: 'country', align: 'left', sortable: true },
  { name: 'customer_segment', label: 'Segment', field: 'customer_segment', align: 'left', sortable: true },
  { name: 'market_key', label: 'Piyasa', field: row => displayMarketName(row.market_key), align: 'left', sortable: true },
  { name: 'customer_code', label: 'Müşteri Kodu', field: 'customer_code', align: 'left', sortable: true },
  { name: 'customer_name', label: 'Müşteri', field: 'customer_name', align: 'left', sortable: true },
  { name: 'product_count', label: 'Ürün Sayısı', field: row => formatNumber(row.product_count, 0), align: 'right', sortable: true },
  { name: 'customer_count_90d', label: '90G Müşteri', field: row => formatNumber(row.customer_count_90d, 0), align: 'right', sortable: true },
  { name: 'invoice_count_90d', label: '90G Fatura', field: row => formatNumber(row.invoice_count_90d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_90d', label: '90G Adet', field: row => formatNumber(row.sales_qty_90d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_90d', label: '90G USD', field: 'sales_usd_90d', align: 'right', sortable: true },
  { name: 'avg_price_usd_90d', label: 'Ort. USD', field: 'avg_price_usd_90d', align: 'right', sortable: true },
  { name: 'customer_count_180d', label: '180G Müşteri', field: row => formatNumber(row.customer_count_180d, 0), align: 'right', sortable: true },
  { name: 'invoice_count_180d', label: '180G Fatura', field: row => formatNumber(row.invoice_count_180d, 0), align: 'right', sortable: true },
  { name: 'sales_qty_180d', label: '180G Adet', field: row => formatNumber(row.sales_qty_180d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_180d', label: '180G USD', field: row => formatMoney(row.sales_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'avg_price_usd_180d', label: '180G Ort. USD', field: row => formatMoney(row.avg_price_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'base_price_usd_180d', label: '180G Taban', field: row => formatMoney(row.base_price_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd_180d', label: '180G Çıplak', field: row => formatMoney(row.cost_price_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_base_usd_180d', label: '180G Taban K/Z', field: row => formatMoney(row.gross_profit_base_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_cost_usd_180d', label: '180G Çıplak K/Z', field: row => formatMoney(row.gross_profit_cost_usd_180d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_180d', label: '180G Taban Marj', field: row => formatPercent(row.gross_margin_base_180d), align: 'right', sortable: true },
  { name: 'gross_margin_cost_180d', label: '180G Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_180d), align: 'right', sortable: true },
  { name: 'sales_qty_365d', label: '360G Adet', field: row => formatNumber(row.sales_qty_365d, 0), align: 'right', sortable: true },
  { name: 'sales_usd_365d', label: '360G USD', field: row => formatMoney(row.sales_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'avg_price_usd_365d', label: '360G Ort. USD', field: row => formatMoney(row.avg_price_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'base_price_usd_365d', label: '360G Taban', field: row => formatMoney(row.base_price_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd_365d', label: '360G Çıplak', field: row => formatMoney(row.cost_price_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_base_usd_365d', label: '360G Taban K/Z', field: row => formatMoney(row.gross_profit_base_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_cost_usd_365d', label: '360G Çıplak K/Z', field: row => formatMoney(row.gross_profit_cost_usd_365d, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_365d', label: '360G Taban Marj', field: row => formatPercent(row.gross_margin_base_365d), align: 'right', sortable: true },
  { name: 'gross_margin_cost_365d', label: '360G Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_365d), align: 'right', sortable: true },
  { name: 'customer_count_total', label: 'Genel Müşteri', field: row => formatNumber(row.customer_count_total, 0), align: 'right', sortable: true },
  { name: 'invoice_count_total', label: 'Genel Fatura', field: row => formatNumber(row.invoice_count_total, 0), align: 'right', sortable: true },
  { name: 'sales_qty_total', label: 'Genel Adet', field: row => formatNumber(row.sales_qty_total, 0), align: 'right', sortable: true },
  { name: 'sales_usd_total', label: 'Genel USD', field: row => formatMoney(row.sales_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'avg_price_usd_total', label: 'Genel Ort. USD', field: row => formatMoney(row.avg_price_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'base_price_usd_total', label: 'Genel Taban', field: row => formatMoney(row.base_price_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'cost_price_usd_total', label: 'Genel Çıplak', field: row => formatMoney(row.cost_price_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_base_usd_total', label: 'Genel Taban K/Z', field: row => formatMoney(row.gross_profit_base_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_profit_cost_usd_total', label: 'Genel Çıplak K/Z', field: row => formatMoney(row.gross_profit_cost_usd_total, 'USD'), align: 'right', sortable: true },
  { name: 'gross_margin_base_total', label: 'Genel Taban Marj', field: row => formatPercent(row.gross_margin_base_total), align: 'right', sortable: true },
  { name: 'gross_margin_cost_total', label: 'Genel Çıplak Marj', field: row => formatPercent(row.gross_margin_cost_total), align: 'right', sortable: true },
  { name: 'sales_index_90d', label: 'Endeks', field: row => formatNumber(row.sales_index_90d, 2), align: 'right', sortable: true },
  { name: 'performance_score', label: 'Skor', field: row => formatNumber(row.performance_score, 1), align: 'right', sortable: true },
  { name: 'performance_bucket', label: 'Durum', field: 'performance_bucket', align: 'left', sortable: true },
  { name: 'last_sale_date', label: 'Son Satış', field: 'last_sale_date', align: 'left', sortable: true },
  { name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' }
]

const visibleSalesBreakdownColumns = computed(() => salesBreakdownColumns.filter(visiblePeriodColumn))

const summaryCards = computed(() => [
  { key: 'date', label: 'KPI Tarihi', value: summary.value.kpi_date || '-' },
  { key: 'rows', label: 'Satır', value: formatNumber(summary.value.total_rows, 0) },
  { key: 'star', label: 'Yıldız', value: formatNumber(summary.value.star_count, 0) },
  { key: 'risk', label: 'Stok Riski', value: formatNumber(summary.value.stock_risk, 0) },
  { key: 'markets', label: '90G Piyasa', value: formatNumber(summary.value.market_count_90d, 0) },
  { key: 'customers', label: '90G Müşteri', value: formatNumber(summary.value.customer_count_90d, 0) },
  { key: 'stock_cost', label: 'Stok Maliyeti', value: formatMoney(summary.value.stock_cost_usd, 'USD') },
  { key: 'risk_cost', label: 'Risk Maliyeti', value: formatMoney(summary.value.risk_cost_usd, 'USD') }
])

const idleRows = computed(() => {
  const variants = new Map()
  for (const row of rows.value) {
    const key = `${row.product_code || ''}|${row.color_code || ''}|${row.yaka_kodu || ''}`
    const current = variants.get(key)
    if (!current) {
      variants.set(key, {
        ...row,
        market_key: row.market_key && row.market_key !== 'STOK' ? row.market_key : '',
        sales_qty_90d: Number(row.sales_qty_90d || 0),
        sales_usd_90d: Number(row.sales_usd_90d || 0),
        gross_profit_usd_90d: Number(row.gross_profit_usd_90d || 0),
        customer_count_90d: Number(row.customer_count_90d || 0),
        market_count_90d: row.market_key && row.market_key !== 'STOK' ? 1 : 0,
        has_stock_risk: row.performance_bucket === 'STOK_RISKI'
      })
      continue
    }
    current.market_key = distinctTextSummary(current.market_key, row.market_key)
    current.sales_qty_90d += Number(row.sales_qty_90d || 0)
    current.sales_usd_90d += Number(row.sales_usd_90d || 0)
    current.gross_profit_usd_90d += Number(row.gross_profit_usd_90d || 0)
    current.customer_count_90d += Number(row.customer_count_90d || 0)
    current.market_count_90d += row.market_key && row.market_key !== 'STOK' ? 1 : 0
    current.has_stock_risk = current.has_stock_risk || row.performance_bucket === 'STOK_RISKI'
  }

  return Array.from(variants.values())
    .map(row => {
      const stockQty = Number(row.stock_qty || 0)
      const salesQty90 = Number(row.sales_qty_90d || 0)
      const stockDays90 = salesQty90 > 0 ? stockQty / (salesQty90 / 90) : 0
      return {
        ...row,
        stock_days_90d: stockDays90,
        idle_cost_usd: stockQty * Number(row.cost_price_usd || 0),
        performance_bucket: row.has_stock_risk ? 'STOK_RISKI' : row.performance_bucket
      }
    })
    .filter(row => Number(row.stock_qty || 0) > 0 && (
      row.performance_bucket === 'STOK_RISKI' ||
      Number(row.sales_qty_90d || 0) === 0 ||
      Number(row.stock_days_90d || 0) > 180
    ))
    .sort((a, b) => Number(b.idle_cost_usd || 0) - Number(a.idle_cost_usd || 0))
})

const visibleOrderAnalysisRows = computed(() => {
  if (orderAnalysisMode.value === 'market') return orderMarketRows.value
  if (orderAnalysisMode.value === 'customer') return orderCustomerRows.value
  return orderAnalysisRows.value
})

const visibleOrderAnalysisColumns = computed(() => {
  if (orderAnalysisMode.value === 'market' || orderAnalysisMode.value === 'customer') return orderGroupColumns
  return orderAnalysisColumns
})

function performanceCardsForRow (row) {
  const source = row || {}
  return [
    { key: 'score', label: 'Skor', value: formatNumber(source.performance_score, 1) },
    { key: 'stock', label: 'Stok', value: formatNumber(source.stock_qty, 0) },
    { key: 'sales90', label: '90G Satış', value: formatNumber(source.sales_qty_90d, 0) },
    { key: 'sales180', label: '180G Satış', value: formatNumber(source.sales_qty_180d, 0) },
    { key: 'markets', label: '90G Piyasa', value: formatNumber(source.market_count_90d, 0) },
    { key: 'customers', label: '90G Müşteri', value: formatNumber(source.customer_count_90d, 0) },
    { key: 'avg', label: 'Ort. USD Satış', value: formatMoney(source.avg_price_usd_90d, 'USD') },
    { key: 'base', label: 'Taban Maliyet', value: formatMoney(source.base_price_usd, 'USD') },
    { key: 'cost', label: 'Çıplak Maliyet', value: formatMoney(source.cost_price_usd, 'USD') },
    { key: 'profitBase', label: 'P.Başı Taban K/Z', value: formatMoney(source.unit_profit_base_90d, 'USD') },
    { key: 'profitCost', label: 'P.Başı Çıplak K/Z', value: formatMoney(source.unit_profit_cost_90d, 'USD') },
    { key: 'marginBase', label: '90G Taban Marj', value: formatPercent(source.gross_margin_base_90d) },
    { key: 'marginCost', label: '90G Çıplak Marj', value: formatPercent(source.gross_margin_cost_90d) },
    { key: 'bucket', label: 'Durum', value: bucketLabel(source.performance_bucket) }
  ]
}

const performanceCards = computed(() => performanceCardsForRow(performanceDialogRow.value))
const imageDialogPerformanceCards = computed(() => performanceCardsForRow(imageDialogRow.value))

const imageDialogInfoRows = computed(() => {
  const row = imageDialogRow.value || {}
  const productCode = row.image_product_code || row.product_code
  const colorCode = row.image_color_code || row.color_code
  const yakaCode = row.image_yaka_kodu || row.yaka_kodu
  return [
    { key: 'product', label: 'Ürün', value: productCode || '-' },
    { key: 'color', label: 'Renk', value: colorCode || '-' },
    { key: 'yaka', label: 'Yaka', value: yakaCode || '-' },
    { key: 'desc', label: 'Açıklama', value: row.item_description || '-' },
    { key: 'category', label: 'Kategori', value: row.kategori || '-' },
    { key: 'hanger', label: 'Askılı/Yan', value: row.askili_yan || '-' },
    { key: 'first', label: 'İlk Grup', value: row.urun_ilk_grubu || row.yas_grubu || '-' },
    { key: 'main', label: 'Ana Grup', value: row.urun_ana_grubu || row.seri || '-' },
    { key: 'sub', label: 'Alt Grup', value: row.urun_alt_grubu || '-' },
    { key: 'market', label: 'Piyasa', value: row.market_key || '-' },
    { key: 'stock', label: 'Toplam Stok', value: formatNumber(row.stock_qty, 0) },
    { key: 'base', label: 'Taban Maliyet', value: formatMoney(row.base_price_usd, 'USD') },
    { key: 'cost', label: 'Çıplak Maliyet', value: formatMoney(row.cost_price_usd, 'USD') }
  ]
})

const groupLevels = [
  { key: 'kategori', label: 'Kategori' },
  { key: 'askili_yan', label: 'Askılı/Yan' },
  { key: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', fallback: 'yas_grubu' },
  { key: 'urun_ana_grubu', label: 'Ürün Ana Grubu', fallback: 'seri' },
  { key: 'urun_alt_grubu', label: 'Ürün Alt Grubu' },
  { key: 'market_key', label: 'Piyasa' },
  { key: 'product_code', label: 'Ürün Kodu' }
]

const tabGroupLevels = {
  products: groupLevels,
  sales_color_yaka_market_customer: [
    { key: 'color_code', label: 'Renk' },
    { key: 'yaka_kodu', label: 'Yaka' },
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' }
  ],
  idle: [
    { key: 'kategori', label: 'Kategori' },
    { key: 'askili_yan', label: 'Askılı/Yan' },
    { key: 'urun_ilk_grubu', label: 'Ürün İlk Grubu', fallback: 'yas_grubu' },
    { key: 'urun_ana_grubu', label: 'Ürün Ana Grubu', fallback: 'seri' },
    { key: 'urun_alt_grubu', label: 'Ürün Alt Grubu' },
    { key: 'product_code', label: 'Ürün Kodu' }
  ],
  sales_product_country_segment_market_customer: [
    { key: 'product_code', label: 'Ürün Kodu' },
    { key: 'country', label: 'Ülke' },
    { key: 'customer_segment', label: 'Segment' },
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' }
  ],
  sales_market_customer_product: [
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' },
    { key: 'product_code', label: 'Ürün Kodu' },
    { key: 'color_code', label: 'Renk' },
    { key: 'yaka_kodu', label: 'Yaka' }
  ],
  sales_country_segment_market_customer_product: [
    { key: 'country', label: 'Ülke' },
    { key: 'customer_segment', label: 'Segment' },
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' },
    { key: 'product_code', label: 'Ürün Kodu' },
    { key: 'color_code', label: 'Renk' },
    { key: 'yaka_kodu', label: 'Yaka' }
  ],
  order_product_customers: [
    { key: 'product_code', label: 'Ürün Kodu' },
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' }
  ],
  order_market_details: [
    { key: 'market_key', label: 'Piyasa' },
    { key: 'customer_code', label: 'Müşteri' },
    { key: 'product_code', label: 'Ürün Kodu' },
    { key: 'color_code', label: 'Renk' },
    { key: 'yaka_kodu', label: 'Yaka' }
  ]
}

const activeGroupLevels = computed(() => tabGroupLevels[activeTab.value] || groupLevels)

const activeSelectedExpandLevelKeys = computed({
  get: () => selectedExpandLevelKeysByTab[activeTab.value] || [],
  set: value => {
    selectedExpandLevelKeysByTab[activeTab.value] = Array.isArray(value) ? value : []
  }
})

const expandLevelOptions = computed(() => activeGroupLevels.value.map(level => ({
  label: level.label,
  value: level.key
})))

const selectedExpandThroughLevel = computed(() => {
  const selected = new Set(activeSelectedExpandLevelKeys.value)
  const indexes = activeGroupLevels.value
    .map((level, index) => selected.has(level.key) ? index : -1)
    .filter(index => index >= 0)
  return indexes.length ? Math.max(...indexes) : -1
})

const autoExpandThroughLevel = computed(() => {
  const selectedLevel = selectedExpandThroughLevel.value
  return selectedLevel >= 0 ? selectedLevel : activeGroupLevels.value.length - 1
})

const tableFilterSourceMap = computed(() => ({
  products: { rows: rows.value, columns: productColumns.value },
  general: { rows: generalRows.value, columns: generalColumns },
  order_product_customers: { rows: orderProductCustomerRows.value, columns: orderProductCustomerColumns },
  order_market_details: { rows: orderMarketDetailRows.value, columns: orderMarketDetailColumns },
  idle: { rows: idleRows.value, columns: idleColumns },
  markets: { rows: marketRows.value, columns: marketColumns },
  countries: { rows: countryRows.value, columns: countryColumns },
  customers: { rows: customerRows.value, columns: customerColumns },
  sales_color_yaka_market_customer: { rows: salesBreakdownRows.sales_color_yaka_market_customer, columns: visibleSalesBreakdownColumns.value },
  sales_product_country_segment_market_customer: { rows: salesBreakdownRows.sales_product_country_segment_market_customer, columns: visibleSalesBreakdownColumns.value },
  sales_market_customer_product: { rows: salesBreakdownRows.sales_market_customer_product, columns: visibleSalesBreakdownColumns.value },
  sales_country_segment_market_customer_product: { rows: salesBreakdownRows.sales_country_segment_market_customer_product, columns: visibleSalesBreakdownColumns.value }
}))

const filteredProductRows = computed(() => filterRowsForTable('products', rows.value, productColumns.value))
const filteredGeneralRows = computed(() => filterRowsForTable('general', generalRows.value, generalColumns))
const filteredOrderProductCustomerRows = computed(() => filterRowsForTable('order_product_customers', orderProductCustomerRows.value, orderProductCustomerColumns))
const filteredOrderMarketDetailRows = computed(() => filterRowsForTable('order_market_details', orderMarketDetailRows.value, orderMarketDetailColumns))
const filteredIdleRows = computed(() => filterRowsForTable('idle', idleRows.value, idleColumns))
const filteredMarketRows = computed(() => filterRowsForTable('markets', marketRows.value, marketColumns))
const filteredCountryRows = computed(() => filterRowsForTable('countries', countryRows.value, countryColumns))
const filteredCustomerRows = computed(() => filterRowsForTable('customers', customerRows.value, customerColumns))
const filteredActiveSalesBreakdownRows = computed(() => filterRowsForTable(activeTab.value, salesBreakdownRows[activeTab.value] || [], visibleSalesBreakdownColumns.value))
const activeGroupSourceRows = computed(() => {
  if (activeTab.value === 'products') return filteredProductRows.value
  if (activeTab.value === 'idle') return filteredIdleRows.value
  if (activeTab.value === 'order_product_customers') return filteredOrderProductCustomerRows.value
  if (activeTab.value === 'order_market_details') return filteredOrderMarketDetailRows.value
  if (salesBreakdownTabKeys.includes(activeTab.value)) return filteredActiveSalesBreakdownRows.value
  return []
})

const columnFilterOptionMap = computed(() => {
  const out = {}
  for (const [tableKey, source] of Object.entries(tableFilterSourceMap.value)) {
    out[tableKey] = {}
    for (const col of source.columns) {
      if (!isColumnFilterable(col.name)) continue
      const seen = new Map()
      for (const row of source.rows) {
        const value = columnFilterValue(row, col)
        if (!value) continue
        if (!seen.has(value)) {
          seen.set(value, {
            label: columnFilterLabel(row, col),
            value
          })
        }
      }
      out[tableKey][col.name] = Array.from(seen.values())
        .sort((a, b) => String(a.label).localeCompare(String(b.label), 'tr', { numeric: true }))
    }
  }
  return out
})

const productTableRows = computed(() => {
  const out = []
  appendGroupRows(out, filteredProductRows.value, 0, ['tab:products'], groupLevels)
  return out
})

const idleTableRows = computed(() => buildGroupedTableRows('idle', filteredIdleRows.value))
const orderProductCustomerTableRows = computed(() => buildGroupedTableRows('order_product_customers', filteredOrderProductCustomerRows.value))
const orderMarketDetailTableRows = computed(() => buildGroupedTableRows('order_market_details', filteredOrderMarketDetailRows.value))
const activeSalesBreakdownTableRows = computed(() => buildGroupedTableRows(activeTab.value, filteredActiveSalesBreakdownRows.value))
const displayProductTableRows = computed(() => backendRowsForTab('products', productTableRows.value))
const displayIdleTableRows = computed(() => backendRowsForTab('idle', idleTableRows.value))
const displayOrderProductCustomerTableRows = computed(() => backendRowsForTab('order_product_customers', orderProductCustomerTableRows.value))
const displayOrderMarketDetailTableRows = computed(() => backendRowsForTab('order_market_details', orderMarketDetailTableRows.value))
const displayActiveSalesBreakdownTableRows = computed(() => backendRowsForTab(activeTab.value, activeSalesBreakdownTableRows.value))

const productGroupKeys = computed(() => {
  const keys = []
  collectGroupKeys(keys, filteredProductRows.value, 0, ['tab:products'], groupLevels)
  return keys
})

const productAutoExpandKeys = computed(() => {
  const keys = []
  collectGroupKeys(keys, activeGroupSourceRows.value, 0, [`tab:${activeTab.value}`], activeGroupLevels.value, autoExpandThroughLevel.value)
  return keys
})

const allProductGroupsExpanded = computed(() => {
  const keys = productAutoExpandKeys.value
  return keys.length > 0 && keys.every(key => expandedGroups.value[key] === true)
})

function appendGroupRows (out, sourceRows, level, parentKeys, levels = groupLevels) {
  if (level >= levels.length) {
    out.push(...sortProductLeafRows(sourceRows))
    return
  }

  const groupDef = levels[level]
  const grouped = new Map()
  for (const row of sourceRows) {
    const value = normalizeGroupValue(rawProductCellValue(row, groupDef.key) || row[groupDef.fallback])
    if (!grouped.has(value)) grouped.set(value, [])
    grouped.get(value).push(row)
  }

  Array.from(grouped.entries())
    .sort((a, b) => a[0].localeCompare(b[0], 'tr'))
    .forEach(([value, groupRows]) => {
      const key = [...parentKeys, `${groupDef.key}:${value}`].join('|')
      out.push(makeGroupRow(key, level, groupDef, value, groupRows))
      if (isGroupExpanded(key)) {
        appendGroupRows(out, groupRows, level + 1, [...parentKeys, `${groupDef.key}:${value}`], levels)
      }
    })
}

function buildGroupedTableRows (tableKey, sourceRows) {
  const levels = tabGroupLevels[tableKey] || groupLevels
  const out = []
  appendGroupRows(out, sourceRows, 0, [`tab:${tableKey}`], levels)
  return out
}

function backendRowsForTab (tabKey, fallbackRows) {
  const rows = backendGroupedRows.value[tabKey]
  return Array.isArray(rows) && rows.length ? rows : fallbackRows
}

function collectGroupKeys (out, sourceRows, level, parentKeys, levels = groupLevels, maxLevel = levels.length - 1) {
  if (level >= levels.length) return

  const groupDef = levels[level]
  const grouped = new Map()
  for (const row of sourceRows) {
    const value = normalizeGroupValue(rawProductCellValue(row, groupDef.key) || row[groupDef.fallback])
    if (!grouped.has(value)) grouped.set(value, [])
    grouped.get(value).push(row)
  }

  Array.from(grouped.entries())
    .sort((a, b) => a[0].localeCompare(b[0], 'tr'))
    .forEach(([value, groupRows]) => {
      const key = [...parentKeys, `${groupDef.key}:${value}`].join('|')
      out.push(key)
      if (level < maxLevel) {
        collectGroupKeys(out, groupRows, level + 1, [...parentKeys, `${groupDef.key}:${value}`], levels, maxLevel)
      }
    })
}

function sortProductLeafRows (sourceRows) {
  return [...sourceRows].sort((a, b) => {
    const colorCmp = String(a?.color_code || '').localeCompare(String(b?.color_code || ''), 'tr', { numeric: true })
    if (colorCmp !== 0) return colorCmp
    const yakaCmp = String(a?.yaka_kodu || '').localeCompare(String(b?.yaka_kodu || ''), 'tr', { numeric: true })
    if (yakaCmp !== 0) return yakaCmp
    return String(a?.item_description || '').localeCompare(String(b?.item_description || ''), 'tr', { numeric: true })
  })
}

function makeGroupRow (key, level, groupDef, value, groupRows) {
  const imageSource = groupRows.find(row => row?.product_code) || {}
  return {
    __group: true,
    row_key: `group|${key}`,
    key,
    level,
    group_field: groupDef.key,
    group_value: value,
    label: value,
    count: groupRows.length,
    image_product_code: imageSource.product_code || '',
    image_color_code: imageSource.color_code || '',
    image_yaka_kodu: imageSource.yaka_kodu || '',
    product_code: groupDef.key === 'product_code' ? value : distinctSummary(groupRows, 'product_code'),
    color_code: groupDef.key === 'color_code' ? value : distinctSummary(groupRows, 'color_code'),
    yaka_kodu: groupDef.key === 'yaka_kodu' ? value : distinctSummary(groupRows, 'yaka_kodu'),
    item_description: distinctSummary(groupRows, 'item_description'),
    kategori: groupDef.key === 'kategori' ? value : distinctSummary(groupRows, 'kategori'),
    urun_ilk_grubu: groupDef.key === 'urun_ilk_grubu' ? value : distinctSummary(groupRows, 'urun_ilk_grubu', 'yas_grubu'),
    askili_yan: groupDef.key === 'askili_yan' ? value : distinctSummary(groupRows, 'askili_yan'),
    urun_ana_grubu: groupDef.key === 'urun_ana_grubu' ? value : distinctSummary(groupRows, 'urun_ana_grubu', 'seri'),
    urun_alt_grubu: groupDef.key === 'urun_alt_grubu' ? value : distinctSummary(groupRows, 'urun_alt_grubu'),
    market_key: groupDef.key === 'market_key' ? value : distinctSummary(groupRows, 'market_key'),
    stock_qty: sumRows(groupRows, 'stock_qty'),
    sales_qty_90d: sumRows(groupRows, 'sales_qty_90d'),
    sales_qty_180d: sumRows(groupRows, 'sales_qty_180d'),
    sales_qty_365d: sumRows(groupRows, 'sales_qty_365d'),
    sales_qty_total: sumRows(groupRows, 'sales_qty_total'),
    sales_usd_90d: sumRows(groupRows, 'sales_usd_90d'),
    sales_usd_180d: sumRows(groupRows, 'sales_usd_180d'),
    sales_usd_365d: sumRows(groupRows, 'sales_usd_365d'),
    sales_usd_total: sumRows(groupRows, 'sales_usd_total'),
    gross_profit_usd_90d: sumRows(groupRows, 'gross_profit_usd_90d'),
    gross_profit_usd_180d: sumRows(groupRows, 'gross_profit_usd_180d'),
    gross_profit_usd_total: sumRows(groupRows, 'gross_profit_usd_total'),
    market_count_90d: distinctCount(groupRows, 'market_key'),
    customer_count_90d: sumRows(groupRows, 'customer_count_90d'),
    market_count_total: sumRows(groupRows, 'market_count_total'),
    customer_count_total: sumRows(groupRows, 'customer_count_total'),
    avg_price_usd_90d: weightedAverage(groupRows, 'sales_usd_90d', 'sales_qty_90d'),
    avg_price_usd_180d: weightedAverage(groupRows, 'sales_usd_180d', 'sales_qty_180d'),
    avg_price_usd_365d: weightedAverage(groupRows, 'sales_usd_365d', 'sales_qty_365d'),
    avg_price_usd_total: weightedAverage(groupRows, 'sales_usd_total', 'sales_qty_total'),
    base_price_usd: weightedAverageOrAverage(groupRows, 'base_price_usd', 'sales_qty_90d'),
    cost_price_usd: weightedAverageOrAverage(groupRows, 'cost_price_usd', 'sales_qty_90d'),
    unit_profit_base_90d: weightedAverageOrAverage(groupRows, 'unit_profit_base_90d', 'sales_qty_90d'),
    unit_profit_cost_90d: weightedAverageOrAverage(groupRows, 'unit_profit_cost_90d', 'sales_qty_90d'),
    unit_profit_base_180d: weightedAverageOrAverage(groupRows, 'unit_profit_base_180d', 'sales_qty_180d'),
    unit_profit_cost_180d: weightedAverageOrAverage(groupRows, 'unit_profit_cost_180d', 'sales_qty_180d'),
    unit_profit_base_total: weightedAverageOrAverage(groupRows, 'unit_profit_base_total', 'sales_qty_total'),
    unit_profit_cost_total: weightedAverageOrAverage(groupRows, 'unit_profit_cost_total', 'sales_qty_total'),
    gross_margin_base_90d: marginFromRows(groupRows, 'sales_usd_90d', 'sales_qty_90d', 'base_price_usd'),
    gross_margin_cost_90d: marginFromRows(groupRows, 'sales_usd_90d', 'sales_qty_90d', 'cost_price_usd'),
    gross_margin_base_180d: marginFromRows(groupRows, 'sales_usd_180d', 'sales_qty_180d', 'base_price_usd'),
    gross_margin_cost_180d: marginFromRows(groupRows, 'sales_usd_180d', 'sales_qty_180d', 'cost_price_usd'),
    gross_margin_base_total: marginFromRows(groupRows, 'sales_usd_total', 'sales_qty_total', 'base_price_usd'),
    gross_margin_cost_total: marginFromRows(groupRows, 'sales_usd_total', 'sales_qty_total', 'cost_price_usd'),
    gross_margin_90d: ratio(sumRows(groupRows, 'gross_profit_usd_90d'), sumRows(groupRows, 'sales_usd_90d')),
    gross_margin_180d: ratio(sumRows(groupRows, 'gross_profit_usd_180d'), sumRows(groupRows, 'sales_usd_180d')),
    stock_days_90d: weightedAverageOrAverage(groupRows, 'stock_days_90d', 'stock_qty'),
    stock_days_180d: weightedAverageOrAverage(groupRows, 'stock_days_180d', 'stock_qty'),
    stock_days_total: weightedAverageOrAverage(groupRows, 'stock_days_total', 'stock_qty'),
    sales_index_90d: averageRows(groupRows, 'sales_index_90d'),
    sales_index_total: averageRows(groupRows, 'sales_index_total'),
    performance_score: weightedAverageOrAverage(groupRows, 'performance_score', 'sales_qty_90d'),
    performance_bucket: dominantValue(groupRows, 'performance_bucket'),
    ...aggregateGroupFields(groupRows),
    recommendation: `${formatNumber(groupRows.length, 0)} satır`
  }
}

function aggregateGroupFields (sourceRows) {
  const out = {}
  const fields = new Set()
  for (const row of sourceRows) {
    Object.keys(row || {}).forEach(key => fields.add(key))
  }

  for (const field of fields) {
    if (field === 'row_key' || field === 'key') continue
    if (shouldSumField(field)) {
      out[field] = sumRows(sourceRows, field)
    } else if (shouldAverageField(field)) {
      out[field] = weightedAverageOrAverage(sourceRows, field, weightFieldForMetric(field))
    }
  }

  applyDerivedGroupMetrics(out, sourceRows)
  return out
}

function shouldSumField (field) {
  return /(_qty|_usd|_count|_value_usd|line_count|invoice_count|order_count|product_count|market_count|customer_count|overdue_qty|stock_qty|net_stock_after_order|idle_cost_usd)$/i.test(field)
}

function shouldAverageField (field) {
  return /^(avg_|unit_|base_price|cost_price|gross_margin|expected_margin|sales_index|performance_score|stock_days|stock_turnover)/i.test(field) ||
    /(_price_usd|_margin|_index|_days)$/i.test(field)
}

function weightFieldForMetric (field) {
  if (field.includes('_180d')) return 'sales_qty_180d'
  if (field.includes('_365d')) return 'sales_qty_365d'
  if (field.includes('_total')) return 'sales_qty_total'
  if (field.includes('order') || field.includes('expected_')) return 'order_qty'
  if (field.includes('stock')) return 'stock_qty'
  return 'sales_qty_90d'
}

function applyDerivedGroupMetrics (out, sourceRows) {
  for (const suffix of ['90d', '180d', '365d', 'total']) {
    const sales = Number(out[`sales_usd_${suffix}`] || 0)
    const qty = Number(out[`sales_qty_${suffix}`] || 0)
    if (qty > 0) out[`avg_price_usd_${suffix}`] = sales / qty
    if (sales > 0) {
      if (out[`gross_profit_base_usd_${suffix}`] !== undefined) {
        out[`gross_margin_base_${suffix}`] = Number(out[`gross_profit_base_usd_${suffix}`] || 0) / sales
      }
      if (out[`gross_profit_cost_usd_${suffix}`] !== undefined) {
        out[`gross_margin_cost_${suffix}`] = Number(out[`gross_profit_cost_usd_${suffix}`] || 0) / sales
      }
      if (out[`gross_profit_usd_${suffix}`] !== undefined) {
        out[`gross_margin_${suffix}`] = Number(out[`gross_profit_usd_${suffix}`] || 0) / sales
      }
    }
  }

  const orderUsd = Number(out.order_usd || 0)
  if (orderUsd > 0) {
    if (out.expected_profit_base_usd !== undefined) out.expected_margin_base = Number(out.expected_profit_base_usd || 0) / orderUsd
    if (out.expected_profit_cost_usd !== undefined) out.expected_margin_cost = Number(out.expected_profit_cost_usd || 0) / orderUsd
  }

  const orderQty = Number(out.order_qty || 0)
  if (orderQty > 0) out.avg_order_price_usd = Number(out.order_usd || 0) / orderQty

  if (sourceRows.some(row => row.performance_bucket)) {
    out.performance_bucket = dominantValue(sourceRows, 'performance_bucket')
  }
}

function sumRows (sourceRows, field) {
  return sourceRows.reduce((sum, row) => sum + Number(row[field] || 0), 0)
}

function distinctCount (sourceRows, field) {
  const values = new Set()
  for (const row of sourceRows) {
    const value = String(row[field] || '').trim()
    if (value && value !== '-') values.add(value)
  }
  return values.size
}

function distinctSummary (sourceRows, field, fallbackField) {
  const values = new Set()
  for (const row of sourceRows) {
    const value = String(row[field] || (fallbackField ? row[fallbackField] : '') || '').trim()
    if (value && value !== '-') values.add(value)
    if (values.size > 1) return `${values.size} farklı`
  }
  return Array.from(values)[0] || ''
}

function distinctTextSummary (current, next) {
  const left = String(current || '').trim()
  const right = String(next || '').trim()
  if (!right || right === 'STOK') return left
  if (!left) return right
  if (left === right || left === 'Çoklu') return left
  return 'Çoklu'
}

function dominantValue (sourceRows, field) {
  const counts = new Map()
  for (const row of sourceRows) {
    const value = String(row[field] || '').trim()
    if (!value) continue
    counts.set(value, (counts.get(value) || 0) + 1)
  }
  return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0] || ''
}

function ratio (amount, base) {
  const divisor = Number(base || 0)
  if (!divisor) return 0
  return Number(amount || 0) / divisor
}

function averageRows (sourceRows, field) {
  const values = sourceRows.map(row => Number(row[field] || 0)).filter(value => Number.isFinite(value) && value !== 0)
  if (!values.length) return 0
  return values.reduce((sum, value) => sum + value, 0) / values.length
}

function weightedAverage (sourceRows, amountField, qtyField) {
  const qty = sumRows(sourceRows, qtyField)
  if (!qty) return 0
  return sumRows(sourceRows, amountField) / qty
}

function weightedAverageOrAverage (sourceRows, valueField, qtyField) {
  const weightedRows = sourceRows
    .map(row => ({
      value: Number(row[valueField] || 0),
      qty: Number(row[qtyField] || 0)
    }))
    .filter(row => Number.isFinite(row.value) && Number.isFinite(row.qty) && row.qty > 0)
  const qty = weightedRows.reduce((sum, row) => sum + row.qty, 0)
  if (qty > 0) {
    return weightedRows.reduce((sum, row) => sum + row.value * row.qty, 0) / qty
  }
  return averageRows(sourceRows, valueField)
}

function marginFromSalesCost (salesUSD, qty, unitCost) {
  const sales = Number(salesUSD || 0)
  if (!sales) return 0
  return (sales - (Number(qty || 0) * Number(unitCost || 0))) / sales
}

function marginFromRows (sourceRows, salesField, qtyField, unitCostField) {
  const sales = sumRows(sourceRows, salesField)
  if (!sales) return 0
  const costAmount = sourceRows.reduce((sum, row) => {
    return sum + Number(row[qtyField] || 0) * Number(row[unitCostField] || 0)
  }, 0)
  return (sales - costAmount) / sales
}

function normalizeGroupValue (value) {
  const text = String(value || '').trim()
  return text || '-'
}

function isGroupExpanded (key) {
  return expandedGroups.value[key] === true
}

function toggleGroup (key) {
  expandedGroups.value = {
    ...expandedGroups.value,
    [key]: !isGroupExpanded(key)
  }
  scheduleLoadBackendGroupedRows()
}

function toggleAllProductGroups () {
  const keys = productAutoExpandKeys.value
  if (allProductGroupsExpanded.value) {
    collapseAllProductGroups()
    return
  }
  expandSelectedProductGroups()
}

function collapseAllProductGroups () {
  expandedGroups.value = {}
  scheduleLoadBackendGroupedRows()
}

function expandSelectedProductGroups () {
  const keys = productAutoExpandKeys.value
  const next = { ...expandedGroups.value }
  for (const key of keys) next[key] = true
  expandedGroups.value = next
  scheduleLoadBackendGroupedRows()
}

function groupLabelColumnName (row) {
  return row?.group_field || 'product_code'
}

function groupShowsImage (row) {
  return Number(row?.level ?? 0) < autoExpandThroughLevel.value
}

function groupCellClass (colOrName) {
  const name = colOrName?.name || colOrName
  if (name === 'image') return 'product-image-cell'
  if (colOrName?.align === 'right') return 'text-right'
  return ['stock_qty', 'sales_qty_90d', 'sales_qty_180d', 'sales_qty_365d', 'sales_qty_total', 'sales_usd_90d', 'sales_usd_180d', 'sales_usd_365d', 'sales_usd_total', 'stock_days_90d', 'stock_days_180d', 'stock_days_total', 'stock_turnover_90d', 'stock_turnover_180d', 'stock_turnover_365d', 'stock_turnover_total', 'avg_price_usd_90d', 'avg_price_usd_180d', 'avg_price_usd_365d', 'avg_price_usd_total', 'base_price_usd', 'cost_price_usd', 'unit_profit_base_90d', 'unit_profit_cost_90d', 'unit_profit_base_180d', 'unit_profit_cost_180d', 'unit_profit_base_total', 'unit_profit_cost_total', 'gross_profit_usd_90d', 'gross_profit_usd_180d', 'gross_profit_usd_total', 'gross_margin_base_90d', 'gross_margin_cost_90d', 'gross_margin_base_180d', 'gross_margin_cost_180d', 'gross_margin_base_total', 'gross_margin_cost_total', 'gross_margin_90d', 'gross_margin_180d', 'market_count_90d', 'customer_count_90d', 'market_count_total', 'customer_count_total', 'sales_index_90d', 'sales_index_total', 'performance_score'].includes(name)
    ? 'text-right'
    : ''
}

function formatGroupCell (row, colOrName) {
  const name = colOrName?.name || colOrName
  if (name === 'image') return ''
  if (name === 'recommendation') return row.recommendation || ''
  return formatTableCell(row, colOrName)
}

function withProductMargins (row) {
  return {
    ...row,
    avg_price_usd_365d: Number(row?.sales_qty_365d || 0) > 0 ? Number(row?.sales_usd_365d || 0) / Number(row?.sales_qty_365d || 0) : 0,
    stock_turnover_90d: stockTurnover(row?.sales_qty_90d, row?.stock_qty),
    stock_turnover_180d: stockTurnover(row?.sales_qty_180d, row?.stock_qty),
    stock_turnover_365d: stockTurnover(row?.sales_qty_365d, row?.stock_qty),
    gross_margin_base_90d: marginFromSalesCost(row?.sales_usd_90d, row?.sales_qty_90d, row?.base_price_usd),
    gross_margin_cost_90d: marginFromSalesCost(row?.sales_usd_90d, row?.sales_qty_90d, row?.cost_price_usd),
    gross_margin_base_180d: marginFromSalesCost(row?.sales_usd_180d, row?.sales_qty_180d, row?.base_price_usd),
    gross_margin_cost_180d: marginFromSalesCost(row?.sales_usd_180d, row?.sales_qty_180d, row?.cost_price_usd)
  }
}

function withGeneralMargins (row) {
  return {
    ...row,
    stock_turnover_total: stockTurnover(row?.sales_qty_total, row?.stock_qty),
    gross_margin_base_total: marginFromSalesCost(row?.sales_usd_total, row?.sales_qty_total, row?.base_price_usd),
    gross_margin_cost_total: marginFromSalesCost(row?.sales_usd_total, row?.sales_qty_total, row?.cost_price_usd)
  }
}

function stockTurnover (salesQty, stockQty) {
  const stock = Number(stockQty || 0)
  if (stock <= 0) return 0
  return Number(salesQty || 0) / stock
}

function filterKey (tableKey, name) {
  return `${tableKey}:${name}`
}

function isColumnFilterable (name) {
  return name !== 'image'
}

function columnFilterOptions (tableKey, name) {
  const options = columnFilterOptionMap.value[tableKey]?.[name] || []
  const search = String(columnFilterSearch[filterKey(tableKey, name)] || '').trim().toLocaleLowerCase('tr')
  if (!search) return options
  return options.filter(option => String(option.label || '').toLocaleLowerCase('tr').includes(search))
}

function hasColumnFilter (tableKey, name) {
  return selectedColumnFilters(tableKey, name).length > 0
}

function getColumnFilterBadgeValue (tableKey, name) {
  return selectedColumnFilters(tableKey, name).length
}

function selectedColumnFilters (tableKey, name) {
  const selected = columnFilters[filterKey(tableKey, name)]
  return Array.isArray(selected) ? selected : []
}

function isColumnFilterValueSelected (tableKey, name, value) {
  return selectedColumnFilters(tableKey, name).includes(value)
}

function toggleColumnFilterValue (tableKey, name, value) {
  runWithFilterBusy(() => {
    const key = filterKey(tableKey, name)
    const selected = selectedColumnFilters(tableKey, name)
    columnFilters[key] = selected.includes(value)
      ? selected.filter(item => item !== value)
      : [...selected, value]
  })
}

function clearColumnFilter (tableKey, name) {
  runWithFilterBusy(() => {
    columnFilters[filterKey(tableKey, name)] = []
  })
}

function selectAllColumnFilterOptions (tableKey, name) {
  runWithFilterBusy(() => {
    columnFilters[filterKey(tableKey, name)] = columnFilterOptions(tableKey, name).map(option => option.value)
  })
}

function runWithFilterBusy (apply) {
  filterBusy.value = true
  const done = () => {
    filterBusy.value = false
  }
  const execute = () => {
    apply()
    if (typeof window === 'undefined') {
      setTimeout(done, 0)
      return
    }
    window.requestAnimationFrame(() => {
      window.requestAnimationFrame(done)
    })
  }
  if (typeof window === 'undefined') {
    execute()
    return
  }
  window.requestAnimationFrame(execute)
}

function filterRowsForTable (tableKey, sourceRows, sourceColumns) {
  return sourceRows.filter(row => {
    return sourceColumns.every(col => {
      if (!isColumnFilterable(col.name)) return true
      const selected = selectedColumnFilters(tableKey, col.name)
      if (!selected.length) return true
      return selected.includes(columnFilterValue(row, col))
    })
  })
}

function columnFilterValue (row, col) {
  return String(rawColumnCellValue(row, col) ?? '').trim()
}

function columnFilterLabel (row, col) {
  return formattedColumnCellValue(row, col) || columnFilterValue(row, col)
}

function rawProductCellValue (row, name) {
  switch (name) {
    case 'urun_ilk_grubu': return row.urun_ilk_grubu || row.yas_grubu || ''
    case 'urun_ana_grubu': return row.urun_ana_grubu || row.seri || ''
    case 'market_key': return displayMarketName(row.market_key)
    case 'performance_bucket': return bucketLabel(row.performance_bucket)
    default: return row[name]
  }
}

function rawColumnCellValue (row, col) {
  const name = col?.name || col
  switch (name) {
    case 'urun_ilk_grubu': return row.urun_ilk_grubu || row.yas_grubu || ''
    case 'urun_ana_grubu': return row.urun_ana_grubu || row.seri || ''
    case 'market_key': return displayMarketName(row.market_key)
    case 'performance_bucket': return bucketLabel(row.performance_bucket)
    case 'is_overdue': return row.is_overdue ? 'Evet' : 'Hayır'
    default:
      if (row[name] !== undefined && row[name] !== null) return row[name]
      if (typeof col?.field === 'function') return col.field(row)
      if (typeof col?.field === 'string') return row[col.field]
      return ''
  }
}

function formattedColumnCellValue (row, col) {
  if (typeof col?.field === 'function') return col.field(row)
  return formatProductCell(row, col?.name || col)
}

function formatTableCell (row, colOrName) {
  const col = typeof colOrName === 'object' ? colOrName : null
  const name = col?.name || colOrName
  if (name === 'image') return ''
  if (name === 'market_key') return displayMarketName(row.market_key)
  if (name === 'performance_bucket') return bucketLabel(row.performance_bucket)
  if (name === 'is_overdue') return row.is_overdue ? 'Evet' : 'Hayır'
  if (isMoneyField(name)) return formatMoney(row[name], 'USD')
  if (isPercentField(name)) return formatPercent(row[name])
  if (isIntegerField(name)) return formatNumber(row[name], 0)
  if (isDecimalField(name)) return formatNumber(row[name], name === 'performance_score' ? 1 : 2)
  if (typeof col?.field === 'function') return col.field(row)
  return formatProductCell(row, name)
}

function isMoneyField (name) {
  return /(^|_)(usd|cost_value_usd|value_usd)$/.test(name) ||
    /(price_usd|cost_usd|profit.*usd|sales_usd|order_usd|base_price_usd|cost_price_usd|idle_cost_usd|stock_cost_value_usd|risk_stock_cost_value_usd)/.test(name)
}

function isPercentField (name) {
  return /(margin|gross_margin|expected_margin)/.test(name)
}

function isIntegerField (name) {
  return /(qty|count|stock_qty|line_count|invoice_count|order_count|product_count|market_count|customer_count|overdue_qty|net_stock_after_order)$/.test(name)
}

function isDecimalField (name) {
  return /(days|turnover|index|score|avg_daily)/.test(name)
}

function formatProductCell (row, name) {
  switch (name) {
    case 'stock_qty':
    case 'sales_qty_90d':
    case 'sales_qty_180d':
    case 'sales_qty_365d':
    case 'sales_qty_total':
    case 'market_count_90d':
    case 'customer_count_90d':
    case 'market_count_total':
    case 'customer_count_total':
      return formatNumber(row[name], 0)
    case 'stock_days_90d':
    case 'stock_days_180d':
    case 'stock_days_total':
    case 'stock_turnover_90d':
    case 'stock_turnover_180d':
    case 'stock_turnover_365d':
    case 'stock_turnover_total':
    case 'sales_index_90d':
    case 'sales_index_total':
    case 'performance_score':
      return formatNumber(row[name], name === 'performance_score' ? 1 : 2)
    case 'sales_usd_90d':
    case 'sales_usd_180d':
    case 'sales_usd_365d':
    case 'sales_usd_total':
    case 'avg_price_usd_90d':
    case 'avg_price_usd_180d':
    case 'avg_price_usd_365d':
    case 'avg_price_usd_total':
    case 'base_price_usd':
    case 'cost_price_usd':
    case 'unit_profit_base_90d':
    case 'unit_profit_cost_90d':
    case 'unit_profit_base_180d':
    case 'unit_profit_cost_180d':
    case 'unit_profit_base_total':
    case 'unit_profit_cost_total':
    case 'gross_profit_usd_90d':
    case 'gross_profit_usd_180d':
    case 'gross_profit_usd_total':
      return formatMoney(row[name], 'USD')
    case 'gross_margin_base_90d':
    case 'gross_margin_cost_90d':
    case 'gross_margin_base_180d':
    case 'gross_margin_cost_180d':
    case 'gross_margin_base_total':
    case 'gross_margin_cost_total':
    case 'gross_margin_90d':
    case 'gross_margin_180d':
      return formatPercent(row[name])
    case 'urun_ilk_grubu':
      return row.urun_ilk_grubu || row.yas_grubu || ''
    case 'urun_ana_grubu':
      return row.urun_ana_grubu || row.seri || ''
    case 'market_key':
      return displayMarketName(row.market_key)
    default:
      return rawProductCellValue(row, name) || ''
  }
}

function normalizeRow (row) {
  const product = String(row?.product_code || '').trim()
  const color = String(row?.color_code || '').trim()
  const yaka = String(row?.yaka_kodu || '').trim()
  const market = String(row?.market_key || '').trim()
  return withProductMargins({
    ...row,
    row_key: `${product}|${color}|${yaka}|${market}`
  })
}

function performanceVariantKey (row) {
  return [
    String(row?.product_code || '').trim(),
    String(row?.color_code || '').trim(),
    String(row?.yaka_kodu || '').trim(),
    displayMarketName(row?.market_key)
  ].join('|')
}

function generalMetricFields (row) {
  return {
    period_start: row?.period_start || '',
    period_end: row?.period_end || '',
    sales_qty_total: Number(row?.sales_qty_total || 0),
    sales_usd_total: Number(row?.sales_usd_total || 0),
    avg_daily_sales_total: Number(row?.avg_daily_sales_total || 0),
    stock_days_total: Number(row?.stock_days_total || 0),
    avg_price_usd_total: Number(row?.avg_price_usd_total || 0),
    gross_profit_usd_total: Number(row?.gross_profit_usd_total || 0),
    gross_margin_total: Number(row?.gross_margin_total || 0),
    unit_profit_cost_total: Number(row?.unit_profit_cost_total || 0),
    unit_profit_base_total: Number(row?.unit_profit_base_total || 0),
    market_count_total: Number(row?.market_count_total || 0),
    customer_count_total: Number(row?.customer_count_total || 0),
    invoice_count_total: Number(row?.invoice_count_total || 0),
    sales_index_total: Number(row?.sales_index_total || 0)
  }
}

function normalizeGeneralRow (row) {
  const product = String(row?.product_code || '').trim()
  const color = String(row?.color_code || '').trim()
  const yaka = String(row?.yaka_kodu || '').trim()
  const market = String(row?.market_key || '').trim()
  return withGeneralMargins({
    ...row,
    row_key: `general|${product}|${color}|${yaka}|${market}`
  })
}

function normalizeOrderAnalysisRow (row) {
  const product = String(row?.product_code || '').trim()
  const color = String(row?.color_code || '').trim()
  const yaka = String(row?.yaka_kodu || '').trim()
  const market = String(row?.market_key || '').trim()
  return {
    ...row,
    row_key: `orders|${product}|${color}|${yaka}|${market}`
  }
}

function normalizeOrderGroupRow (row) {
  const key = String(row?.group_key || '').trim()
  const mode = String(row?.breakdown || '').trim()
  return {
    ...row,
    row_key: `order-group|${mode}|${key}|${row?.market_key || ''}|${row?.customer_code || ''}`
  }
}

function normalizeOrderProductCustomerRow (row) {
  const product = String(row?.product_code || '').trim()
  const color = String(row?.color_code || '').trim()
  const yaka = String(row?.yaka_kodu || '').trim()
  const market = String(row?.market_key || '').trim()
  const customer = String(row?.customer_code || '').trim()
  return {
    ...row,
    row_key: `order-product-customer|${product}|${color}|${yaka}|${market}|${customer}`
  }
}

function normalizeOrderMarketDetailRow (row) {
  return {
    ...row,
    row_key: `order-market-detail|${row?.market_key || ''}|${row?.customer_code || ''}|${row?.order_number || ''}|${row?.product_code || ''}|${row?.color_code || ''}|${row?.yaka_kodu || ''}`
  }
}

function normalizeSalesBreakdownRow (row) {
  return {
    ...row,
    row_key: `sales-breakdown|${row?.breakdown || ''}|${row?.product_code || ''}|${row?.color_code || ''}|${row?.yaka_kodu || ''}|${row?.country || ''}|${row?.customer_segment || ''}|${row?.market_key || ''}|${row?.customer_code || ''}`
  }
}

function orderGroupLabel (row) {
  if (row?.breakdown === 'customer') {
    return [row.customer_code, row.customer_name].filter(Boolean).join(' - ') || '-'
  }
  return row?.group_key || row?.market_key || '-'
}

function productImageKey (row) {
  const product = String(row?.image_product_code || row?.product_code || '').trim()
  const color = String(row?.image_color_code || row?.color_code || '').trim()
  const yaka = String(row?.image_yaka_kodu || row?.yaka_kodu || '').trim()
  return `${product}|${color}|${yaka}`
}

function displayMarketName (value) {
  const parts = String(value || '').split('|').map(part => part.trim()).filter(Boolean)
  return parts.length ? parts[parts.length - 1] : ''
}

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 ''

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

  const imageId = Number(item.id || item.ID || 0)
  if (Number.isFinite(imageId) && imageId > 0) return `/api/product-images/${imageId}/content`

  const thumbURL = String(item.thumb_url || item.thumbUrl || '').trim()
  if (thumbURL) return thumbURL

  const fullURL = String(item.full_url || item.fullUrl || '').trim()
  if (fullURL) return fullURL

  const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
  if (uploadsPath) return uploadsPath

  const fileName = String(item.file_name || item.FileName || '').trim()
  return fileName ? `/uploads/image/${fileName}` : ''
}

async function fetchProductImagesForRow (row) {
  const key = productImageKey(row)
  if (Object.prototype.hasOwnProperty.call(imageListByKey.value, key)) {
    return imageListByKey.value[key]
  }
  if (performanceStore.hasImageKey(key)) {
    const urls = performanceStore.imageList(key)
    imageListByKey.value = { ...imageListByKey.value, [key]: urls }
    imageUrlByKey.value = { ...imageUrlByKey.value, [key]: urls[0] || '' }
    return urls
  }

  const code = String(row?.image_product_code || row?.product_code || '').trim()
  if (!code) return []

  const color = String(row?.image_color_code || row?.color_code || '').trim()
  const yaka = String(row?.image_yaka_kodu || row?.yaka_kodu || '').trim()

  try {
    const resp = await api.get('/product-images', {
      params: {
        code,
        dim1: color || undefined,
        dim3: yaka || undefined
      },
      timeout: 60000
    })
    const list = Array.isArray(resp?.data) ? resp.data : []
    const urls = list.map(resolveProductImageUrl).filter(Boolean)
    performanceStore.setImageCache(key, urls)
    imageListByKey.value = { ...imageListByKey.value, [key]: urls }
    imageUrlByKey.value = { ...imageUrlByKey.value, [key]: urls[0] || '' }
    return urls
  } catch {
    performanceStore.setImageCache(key, [])
    imageListByKey.value = { ...imageListByKey.value, [key]: [] }
    imageUrlByKey.value = { ...imageUrlByKey.value, [key]: '' }
    return []
  }
}

function getCachedProductImageUrl (row) {
  const key = productImageKey(row)
  return imageUrlByKey.value[key] || performanceStore.imageUrl(key) || ''
}

async function primeProductImages (sourceRows) {
  imagePrimeActiveRequests += 1
  imagePrimeLoading.value = true
  const items = []
  const seen = new Set()
  try {
    for (const row of sourceRows || []) {
      const key = productImageKey(row)
      const code = String(row?.image_product_code || row?.product_code || '').trim()
      if (!key || !code || seen.has(key) || Object.prototype.hasOwnProperty.call(imageListByKey.value, key) || performanceStore.hasImageKey(key)) continue
      seen.add(key)
      items.push({
        key,
        code,
        dim1: String(row?.image_color_code || row?.color_code || '').trim(),
        dim3: String(row?.image_yaka_kodu || row?.yaka_kodu || '').trim()
      })
      if (items.length >= 160) break
    }
    if (!items.length) return

    const batch = await performanceStore.fetchImageBatch(items)
    const nextLists = { ...imageListByKey.value }
    const nextUrls = { ...imageUrlByKey.value }
    for (const item of items) {
      const urls = batch?.lists?.[item.key] || performanceStore.imageList(item.key) || []
      nextLists[item.key] = urls
      nextUrls[item.key] = batch?.urls?.[item.key] || urls[0] || ''
    }
    imageListByKey.value = nextLists
    imageUrlByKey.value = nextUrls
  } catch {
    await Promise.all(items.slice(0, 24).map(item => fetchProductImagesForRow({
      product_code: item.code,
      color_code: item.dim1,
      yaka_kodu: item.dim3
    })))
  } finally {
    imagePrimeActiveRequests = Math.max(0, imagePrimeActiveRequests - 1)
    imagePrimeLoading.value = imagePrimeActiveRequests > 0
  }
}

async function openProductImageDialog (row) {
  imageDialogRow.value = row
  const urls = await fetchProductImagesForRow(row)
  imageDialogUrls.value = urls
  imageSlide.value = 0
  imageDialogTitle.value = String(row?.image_product_code || row?.product_code || '-')
  imageDialogSubtitle.value = [
    row?.item_description,
    row?.image_color_code || row?.color_code,
    row?.image_yaka_kodu || row?.yaka_kodu
  ].filter(Boolean).join(' | ')
  imageDialog.value = true
  await loadProductDetailRows(row)
}

async function openPerformanceDialog (row) {
  performanceDialogRow.value = row
  performanceDialogTitle.value = String(row?.product_code || '-')
  performanceDialogSubtitle.value = [
    row?.item_description,
    row?.color_code,
    row?.yaka_kodu,
    row?.market_key
  ].filter(Boolean).join(' | ')
  performanceDialog.value = true
  await loadProductDetailRows(row)
}

async function loadProductDetailRows (row) {
  detailLoading.value = true
  detailSalesRows.value = []
  detailStockSizes.value = []
  try {
    const params = {
      product_code: row?.image_product_code || row?.product_code || '',
      color_code: row?.image_color_code || row?.color_code || '',
      yaka_kodu: row?.image_yaka_kodu || row?.yaka_kodu || ''
    }
    if (!params.product_code) return
    const [salesResp, stockResp] = await Promise.all([
      api.get('/pricing/product-performance/sales-details', { params: { ...params, limit: 200 }, timeout: 60000 }),
      api.get('/pricing/product-performance/stock-sizes', { params, timeout: 60000 })
    ])
    detailSalesRows.value = (Array.isArray(salesResp?.data) ? salesResp.data : []).map((item, idx) => ({
      ...item,
      detail_key: `${item.sales_date}|${item.ref_number}|${item.customer_code}|${idx}`
    }))
    detailStockSizes.value = Array.isArray(stockResp?.data) ? stockResp.data : []
  } catch (err) {
    Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Ürün detay analizi alınamadı' })
  } finally {
    detailLoading.value = false
  }
}

function backendGroupedSupportedTab (tabKey = activeTab.value) {
  return tabKey === 'products' ||
    tabKey === 'idle' ||
    tabKey === 'order_product_customers' ||
    tabKey === 'order_market_details' ||
    salesBreakdownTabKeys.includes(tabKey)
}

function activeExpandedGroupKeys () {
  return Object.entries(expandedGroups.value)
    .filter(([, value]) => value === true)
    .map(([key]) => key)
}

function scheduleLoadBackendGroupedRows () {
  if (backendGroupedSupportedTab(activeTab.value)) backendGroupedLoading.value = true
  if (backendGroupedTimer) window.clearTimeout(backendGroupedTimer)
  backendGroupedTimer = window.setTimeout(() => {
    void loadBackendGroupedRows()
  }, 120)
}

function switchPerformanceTab (tabName) {
  if (!tabName || tabName === activeTab.value || pageBusy.value) return
  backendGroupedLoading.value = true
  activeTab.value = tabName
}

async function loadBackendGroupedRows () {
  const tabKey = activeTab.value
  if (!backendGroupedSupportedTab(tabKey)) return
  backendGroupedLoading.value = true
  const params = {
    mode: tabKey,
    groupLevels: activeGroupLevels.value.map(level => level.key),
    expandedKeys: activeExpandedGroupKeys(),
    limit: tabKey === 'products' || tabKey === 'idle' ? productKpiFetchLimit : 50000
  }
  try {
    const rows = await performanceStore.fetchGroupedRows(params)
    backendGroupedRows.value = {
      ...backendGroupedRows.value,
      [tabKey]: Array.isArray(rows) ? rows : []
    }
  } catch (err) {
    console.warn('product performance grouped rows failed', err)
  } finally {
    backendGroupedLoading.value = false
  }
}

async function reload () {
  loading.value = true
  try {
    const salesBreakdownRequests = salesBreakdownTabKeys.map(tabKey => {
      return api.get('/pricing/product-performance/sales-breakdown', {
        params: { limit: 800, mode: salesBreakdownModes[tabKey] },
        timeout: 60000
      })
    })
    const [summaryResp, listResp, generalResp, marketResp, countryResp, customerResp, ...salesBreakdownResp] = await Promise.all([
      api.get('/pricing/product-performance/summary', { timeout: 60000 }),
      api.get('/pricing/product-performance', {
        params: {
          page: 1,
          limit: productKpiFetchLimit,
          sort_by: pagination.value.sortBy || undefined,
          descending: pagination.value.descending ? 'true' : 'false'
        },
        timeout: 60000
      }),
      api.get('/pricing/product-performance/general', { params: { limit: 500 }, timeout: 60000 }),
      api.get('/pricing/product-performance/markets', { params: { limit: 500 }, timeout: 60000 }),
      api.get('/pricing/product-performance/countries', { params: { limit: 500 }, timeout: 60000 }),
      api.get('/pricing/product-performance/customers', {
        params: { limit: 500, breakdown: customerBreakdown.value },
        timeout: 60000
      }),
      ...salesBreakdownRequests
    ])
    summary.value = summaryResp?.data || {}
    const normalizedGeneralRows = (Array.isArray(generalResp?.data) ? generalResp.data : []).map(normalizeGeneralRow)
    const generalByVariant = new Map(normalizedGeneralRows.map(row => [performanceVariantKey(row), generalMetricFields(row)]))
    rows.value = (Array.isArray(listResp?.data?.rows) ? listResp.data.rows : []).map(row => {
      const generalMetrics = generalByVariant.get(performanceVariantKey(row)) || {}
      return normalizeRow({ ...row, ...generalMetrics })
    })
    generalRows.value = normalizedGeneralRows
    marketRows.value = Array.isArray(marketResp?.data) ? marketResp.data : []
    countryRows.value = (Array.isArray(countryResp?.data) ? countryResp.data : []).map(row => ({
      ...row,
      country_key: `${row.country || '-'}|${row.customer_segment || '-'}|${row.market_key || '-'}`
    }))
    customerRows.value = (Array.isArray(customerResp?.data) ? customerResp.data : []).map(row => ({
      ...row,
      customer_key: `${row.breakdown || '-'}|${row.market_key || '-'}|${row.country || '-'}|${row.customer_segment || '-'}|${row.customer_code || '-'}`
    }))
    salesBreakdownTabKeys.forEach((tabKey, index) => {
      salesBreakdownRows[tabKey] = (Array.isArray(salesBreakdownResp[index]?.data) ? salesBreakdownResp[index].data : []).map(normalizeSalesBreakdownRow)
    })
    pagination.value.rowsNumber = Number(listResp?.data?.total_count || 0)
    if (activeTab.value === 'order_product_customers') {
      await loadOrderProductCustomers(false)
    }
    if (activeTab.value === 'order_market_details') {
      await loadOrderMarketDetails(false)
    }
    await loadBackendGroupedRows()
    await primeProductImages(rows.value)
  } catch (err) {
    Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Ürün performans verisi alınamadı' })
  } finally {
    loading.value = false
  }
}

async function loadOrderProductCustomers (showLoading = true) {
  if (showLoading) loading.value = true
  try {
    const resp = await api.get('/pricing/product-performance/orders/product-customers', { params: { limit: 500 }, timeout: 90000 })
    orderProductCustomerRows.value = (Array.isArray(resp?.data) ? resp.data : []).map(normalizeOrderProductCustomerRow)
    orderProductCustomersLoaded.value = true
    await primeProductImages(orderProductCustomerRows.value)
  } catch (err) {
    Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Ürün müşteri sipariş analizi alınamadı' })
  } finally {
    if (showLoading) loading.value = false
  }
}

async function loadOrderMarketDetails (showLoading = true) {
  if (showLoading) loading.value = true
  try {
    const resp = await api.get('/pricing/product-performance/orders/market-details', { params: { limit: 800 }, timeout: 90000 })
    orderMarketDetailRows.value = (Array.isArray(resp?.data) ? resp.data : []).map(normalizeOrderMarketDetailRow)
    orderMarketDetailsLoaded.value = true
  } catch (err) {
    Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Piyasa sipariş detay analizi alınamadı' })
  } finally {
    if (showLoading) loading.value = false
  }
}

async function loadOrderAnalysis (showLoading = true) {
  if (showLoading) loading.value = true
  try {
    const [productResp, marketResp, customerResp] = await Promise.all([
      api.get('/pricing/product-performance/orders', { params: { limit: 500 }, timeout: 90000 }),
      api.get('/pricing/product-performance/orders/groups', { params: { limit: 500, breakdown: 'market' }, timeout: 90000 }),
      api.get('/pricing/product-performance/orders/groups', { params: { limit: 500, breakdown: 'customer' }, timeout: 90000 })
    ])
    orderAnalysisRows.value = (Array.isArray(productResp?.data) ? productResp.data : []).map(normalizeOrderAnalysisRow)
    orderMarketRows.value = (Array.isArray(marketResp?.data) ? marketResp.data : []).map(normalizeOrderGroupRow)
    orderCustomerRows.value = (Array.isArray(customerResp?.data) ? customerResp.data : []).map(normalizeOrderGroupRow)
    orderAnalysisLoaded.value = true
    await primeProductImages(orderAnalysisRows.value)
  } catch (err) {
    Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Sipariş analiz verisi alınamadı' })
  } finally {
    if (showLoading) loading.value = false
  }
}

function onRequest (props) {
  pagination.value = { ...pagination.value, ...props.pagination }
  reload()
}

function bucketLabel (value) {
  return bucketOptions.find(x => x.value === value)?.label || value || '-'
}

function bucketColor (value) {
  switch (value) {
    case 'YILDIZ_URUN': return 'green-7'
    case 'STOKSUZ_TALEP': return 'blue-7'
    case 'STOK_RISKI': return 'orange-8'
    case 'FIYAT_BASKISI': return 'red-7'
    case 'FIYAT_FIRSATI': return 'teal-7'
    case 'MALIYET_YOK': return 'blue-grey-7'
    default: return 'grey-7'
  }
}

watch(activeTab, tab => {
  if (tab === 'order_product_customers' && !orderProductCustomersLoaded.value) {
    void loadOrderProductCustomers(true)
  }
  if (tab === 'order_market_details' && !orderMarketDetailsLoaded.value) {
    void loadOrderMarketDetails(true)
  }
  scheduleLoadBackendGroupedRows()
})

watch(activeSelectedExpandLevelKeys, () => {
  scheduleLoadBackendGroupedRows()
})

watch(productTableRows, tableRows => {
  if (activeTab.value !== 'products') return
  const imageRows = tableRows
    .filter(row => !row.__group || groupShowsImage(row))
    .slice(0, 240)
  void primeProductImages(imageRows)
}, { immediate: true })

onMounted(reload)
</script>

<style scoped>
.product-performance-page {
  position: relative;
  background: #f6f7f9;
}

.page-busy-overlay {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background: rgba(246, 247, 249, 0.82);
  backdrop-filter: blur(2px);
  pointer-events: all;
}

.page-busy-label {
  color: #1f2937;
  font-size: 13px;
  font-weight: 700;
}

.performance-tab-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: 6px;
}

.performance-tab-button {
  min-height: 38px;
  padding: 6px 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  border: 1px solid #d5dce5;
  border-radius: 6px;
  background: #fff;
  color: #4b5563;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
  cursor: pointer;
}

.performance-tab-button span {
  white-space: normal;
  overflow-wrap: anywhere;
}

.performance-tab-button.active {
  border-color: var(--q-primary);
  color: var(--q-primary);
  background: #eef6ff;
}

.performance-tab-button:disabled {
  cursor: wait;
  opacity: 0.62;
}

.metric-card {
  min-height: 78px;
}

.metric-value {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.25;
  margin-top: 4px;
}

.detail-level-menu {
  width: 260px;
  padding: 10px;
}

.performance-table {
  max-height: calc(100vh - 260px);
}

.performance-table :deep(.q-table__middle) {
  max-height: calc(100vh - 320px);
}

.performance-table :deep(.q-table) {
  border-collapse: separate;
  border-spacing: 0;
}

.performance-table :deep(.q-table th),
.performance-table :deep(.q-table td) {
  border-right: 1px solid #d5dce5;
  border-bottom: 1px solid #d5dce5;
  vertical-align: middle;
  white-space: normal;
}

.performance-table :deep(.q-table tbody tr),
.performance-table :deep(.q-table tbody td) {
  height: auto;
  min-height: 48px;
}

.performance-table :deep(.q-table tbody td) {
  max-width: 320px;
  padding-top: 6px;
  padding-bottom: 6px;
  overflow-wrap: anywhere;
}

.performance-table :deep(.q-table tbody td span:not(.q-badge):not(.q-icon)) {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.25;
}

.performance-table :deep(.q-table tbody td .q-field),
.performance-table :deep(.q-table tbody td input),
.performance-table :deep(.q-table tbody td textarea) {
  min-width: 96px;
  max-width: 100%;
}

.performance-table :deep(.q-table th:first-child),
.performance-table :deep(.q-table td:first-child) {
  border-left: 1px solid #d5dce5;
}

.performance-table :deep(th) {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #f8fbff;
  border-top: 1px solid #d5dce5;
}

.product-breakdown-table :deep(.q-table) {
  min-width: 3200px;
  table-layout: fixed;
}

.product-breakdown-table :deep(.q-table th:nth-child(-n+11)),
.product-breakdown-table :deep(.q-table td:nth-child(-n+11)) {
  position: sticky;
  z-index: 2;
}

.product-breakdown-table :deep(.q-table th:nth-child(-n+11)) {
  z-index: 4;
  background: #f8fbff;
}

.product-breakdown-table :deep(.q-table tbody tr:not(.group-row) td:nth-child(-n+11)) {
  background: #fff;
}

.product-breakdown-table :deep(.q-table th:nth-child(1)),
.product-breakdown-table :deep(.q-table td:nth-child(1)) {
  left: 0;
  width: 92px;
  min-width: 92px;
  max-width: 92px;
}

.product-breakdown-table :deep(.q-table th:nth-child(2)),
.product-breakdown-table :deep(.q-table td:nth-child(2)) {
  left: 92px;
  width: 120px;
  min-width: 120px;
  max-width: 120px;
}

.product-breakdown-table :deep(.q-table th:nth-child(3)),
.product-breakdown-table :deep(.q-table td:nth-child(3)) {
  left: 212px;
  width: 64px;
  min-width: 64px;
  max-width: 64px;
}

.product-breakdown-table :deep(.q-table th:nth-child(4)),
.product-breakdown-table :deep(.q-table td:nth-child(4)) {
  left: 276px;
  width: 64px;
  min-width: 64px;
  max-width: 64px;
}

.product-breakdown-table :deep(.q-table th:nth-child(5)),
.product-breakdown-table :deep(.q-table td:nth-child(5)) {
  left: 340px;
  width: 200px;
  min-width: 200px;
  max-width: 200px;
}

.product-breakdown-table :deep(.q-table th:nth-child(6)),
.product-breakdown-table :deep(.q-table td:nth-child(6)) {
  left: 540px;
  width: 110px;
  min-width: 110px;
  max-width: 110px;
}

.product-breakdown-table :deep(.q-table th:nth-child(7)),
.product-breakdown-table :deep(.q-table td:nth-child(7)) {
  left: 650px;
  width: 100px;
  min-width: 100px;
  max-width: 100px;
}

.product-breakdown-table :deep(.q-table th:nth-child(8)),
.product-breakdown-table :deep(.q-table td:nth-child(8)) {
  left: 750px;
  width: 130px;
  min-width: 130px;
  max-width: 130px;
}

.product-breakdown-table :deep(.q-table th:nth-child(9)),
.product-breakdown-table :deep(.q-table td:nth-child(9)) {
  left: 880px;
  width: 130px;
  min-width: 130px;
  max-width: 130px;
}

.product-breakdown-table :deep(.q-table th:nth-child(10)),
.product-breakdown-table :deep(.q-table td:nth-child(10)) {
  left: 1010px;
  width: 130px;
  min-width: 130px;
  max-width: 130px;
}

.product-breakdown-table :deep(.q-table th:nth-child(11)),
.product-breakdown-table :deep(.q-table td:nth-child(11)) {
  left: 1140px;
  width: 190px;
  min-width: 190px;
  max-width: 190px;
  box-shadow: 8px 0 10px -10px rgba(17, 24, 39, 0.45);
}

.sticky-dim-table :deep(.q-table) {
  min-width: 2200px;
  table-layout: fixed;
}

.sticky-dim-table :deep(.q-table th),
.sticky-dim-table :deep(.q-table td) {
  min-width: 130px;
  width: 130px;
  max-width: 180px;
}

.sticky-dim-table :deep(.q-table th:nth-child(1)),
.sticky-dim-table :deep(.q-table td:nth-child(1)) {
  left: 0;
  position: sticky;
  z-index: 2;
  background: #fff;
}

.sticky-dim-table :deep(.q-table th:nth-child(2)),
.sticky-dim-table :deep(.q-table td:nth-child(2)) {
  left: 130px;
}

.sticky-dim-table :deep(.q-table th:nth-child(3)),
.sticky-dim-table :deep(.q-table td:nth-child(3)) {
  left: 260px;
}

.sticky-dim-table :deep(.q-table th:nth-child(4)),
.sticky-dim-table :deep(.q-table td:nth-child(4)) {
  left: 390px;
}

.sticky-dim-table :deep(.q-table th:nth-child(5)),
.sticky-dim-table :deep(.q-table td:nth-child(5)) {
  left: 520px;
}

.sticky-dim-table :deep(.q-table th:nth-child(6)),
.sticky-dim-table :deep(.q-table td:nth-child(6)) {
  left: 650px;
}

.sticky-dim-table :deep(.q-table th:nth-child(7)),
.sticky-dim-table :deep(.q-table td:nth-child(7)) {
  left: 780px;
}

.sticky-dim-table :deep(.q-table th:nth-child(8)),
.sticky-dim-table :deep(.q-table td:nth-child(8)) {
  left: 910px;
}

.sticky-dim-table :deep(.q-table th:nth-child(9)),
.sticky-dim-table :deep(.q-table td:nth-child(9)) {
  left: 1040px;
}

.sticky-dim-table :deep(.q-table th:nth-child(10)),
.sticky-dim-table :deep(.q-table td:nth-child(10)) {
  left: 1170px;
}

.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(-n+3)),
.sticky-dim-table.sticky-dim-3 :deep(.q-table td:nth-child(-n+3)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table th:nth-child(-n+5)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table td:nth-child(-n+5)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table th:nth-child(-n+6)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table td:nth-child(-n+6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table td:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table td:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(-n+10)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table td:nth-child(-n+10)) {
  position: sticky;
  z-index: 2;
}

.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(-n+3)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table th:nth-child(-n+5)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table th:nth-child(-n+6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(-n+10)) {
  z-index: 4;
  background: #f8fbff;
}

.sticky-dim-table :deep(.q-table tbody td:nth-child(-n+10)) {
  background: #fff;
}

.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(3)),
.sticky-dim-table.sticky-dim-3 :deep(.q-table td:nth-child(3)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table th:nth-child(5)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table td:nth-child(5)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table th:nth-child(6)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table td:nth-child(6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(7)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table td:nth-child(7)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(9)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table td:nth-child(9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(10)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table td:nth-child(10)) {
  box-shadow: 8px 0 10px -10px rgba(17, 24, 39, 0.45);
}

.filterable-header-cell {
  vertical-align: middle;
}

.header-with-filter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 24px;
  align-items: center;
  gap: 4px;
  min-width: 80px;
}

.header-with-filter > span {
  line-height: 1.15;
  white-space: normal;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-filter-btn {
  width: 24px;
  height: 24px;
  min-height: 24px;
}

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

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

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

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

.excel-filter-options {
  max-height: 260px;
  margin-top: 4px;
  border: 1px solid #e0e3e7;
  border-radius: 6px;
}

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

.excel-filter-empty {
  padding: 12px;
  color: #7a8390;
  text-align: center;
}

.group-row td {
  background: color-mix(in srgb, var(--q-primary) 8%, #ffffff);
  font-weight: 600;
  color: color-mix(in srgb, var(--q-primary) 55%, #1f2937);
  border-color: color-mix(in srgb, var(--q-primary) 18%, #d5dce5);
  white-space: nowrap;
}

.group-row-level-0 td {
  background: color-mix(in srgb, var(--q-primary) 82%, #1f2937);
  color: #fff;
  border-color: color-mix(in srgb, var(--q-primary) 75%, #111827);
}

.group-row-level-1 td {
  background: color-mix(in srgb, var(--q-primary) 68%, #ffffff);
  color: #fff;
  border-color: color-mix(in srgb, var(--q-primary) 58%, #d5dce5);
}

.group-row-level-2 td {
  background: color-mix(in srgb, var(--q-primary) 36%, #ffffff);
  color: color-mix(in srgb, var(--q-primary) 65%, #111827);
  border-color: color-mix(in srgb, var(--q-primary) 34%, #d5dce5);
}

.group-row-level-3 td {
  background: color-mix(in srgb, var(--q-primary) 22%, #ffffff);
  color: color-mix(in srgb, var(--q-primary) 58%, #1f2937);
  border-color: color-mix(in srgb, var(--q-primary) 24%, #d5dce5);
}

.group-row-level-4 td {
  background: color-mix(in srgb, var(--q-primary) 14%, #ffffff);
  color: color-mix(in srgb, var(--q-primary) 52%, #1f2937);
  border-color: color-mix(in srgb, var(--q-primary) 18%, #d5dce5);
}

.group-row-level-5 td {
  background: color-mix(in srgb, var(--q-primary) 8%, #ffffff);
  color: color-mix(in srgb, var(--q-primary) 48%, #1f2937);
  border-color: color-mix(in srgb, var(--q-primary) 14%, #d5dce5);
}

.group-cell-label {
  display: flex;
  align-items: center;
  min-width: 180px;
}

.group-title {
  margin-left: 4px;
  white-space: normal;
}

.product-image-cell {
  width: 80px;
  min-width: 80px;
}

.product-thumb-button {
  width: 68px;
  height: 92px;
  border: 1px solid #d9dde3;
  border-radius: 6px;
  background: #fff;
  padding: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.product-thumb,
.product-thumb-placeholder {
  width: 58px;
  height: 82px;
}

.product-thumb {
  display: block;
  object-fit: contain;
}

.product-thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #9aa3af;
  background: #f3f5f7;
  border-radius: 4px;
}

.product-image-dialog {
  background: #f6f7f9;
}

.product-image-dialog-body {
  height: calc(100vh - 74px);
  padding: 12px;
  overflow: hidden;
}

.performance-image-layout {
  display: grid;
  grid-template-columns: minmax(280px, 330px) minmax(360px, 1fr) minmax(440px, 1.25fr);
  gap: 12px;
  height: 100%;
  min-height: 0;
}

.image-product-fields,
.image-sales-panel,
.image-media-panel {
  min-height: 0;
}

.image-product-fields,
.image-sales-panel {
  overflow: auto;
  background: #fff;
  border: 1px solid #d9dde3;
  border-radius: 8px;
  padding: 12px;
}

.image-section-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--q-primary);
  text-transform: uppercase;
  letter-spacing: 0;
  margin-bottom: 8px;
}

.image-field-row {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
  min-height: 30px;
  padding: 6px 0;
  border-bottom: 1px solid #edf0f3;
  font-size: 12px;
}

.image-field-row .k {
  color: #6b7280;
  font-weight: 600;
}

.image-field-row .v {
  color: #1f2937;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.image-product-section {
  position: relative;
  margin-top: 14px;
}

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

.image-size-stock-cell {
  min-height: 54px;
  padding: 8px 6px;
  border: 1px solid #dfe4ea;
  border-radius: 6px;
  background: #f8fafc;
  text-align: center;
}

.image-size-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: #6b7280;
}

.image-size-qty {
  display: block;
  margin-top: 3px;
  font-size: 16px;
  font-weight: 800;
  color: #111827;
}

.image-empty-text {
  color: #7a8390;
  font-size: 12px;
}

.product-image-carousel {
  height: 100%;
  background: #fff;
  border: 1px solid #d9dde3;
  border-radius: 8px;
}

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

.product-image-empty {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #7a8390;
  background: #fff;
  border: 1px solid #d9dde3;
  border-radius: 8px;
}

.image-metric-card .q-card__section {
  padding: 8px;
}

.image-metric-card .metric-value {
  font-size: 14px;
}

@media (max-width: 1260px) {
  .product-image-dialog-body {
    overflow: auto;
  }

  .performance-image-layout {
    grid-template-columns: 1fr;
    height: auto;
  }

  .image-media-panel {
    min-height: 520px;
  }
}
</style>


