import { defineStore } from 'pinia'
import api from 'src/services/api'

function toText (value) {
  return String(value ?? '').trim()
}

function toNumber (value) {
  const n = parseFlexibleNumber(value)
  return Number.isFinite(n) ? Number(n.toFixed(2)) : 0
}

function parseFlexibleNumber (value) {
  if (typeof value === 'number') return value
  const text = String(value ?? '').trim().replace(/\s/g, '')
  if (!text) return 0

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

  if (lastComma >= 0 && lastDot >= 0) {
    // Keep the last separator as decimal, remove the other as thousand.
    if (lastComma > lastDot) {
      normalized = text.replace(/\./g, '').replace(',', '.')
    } else {
      normalized = text.replace(/,/g, '')
    }
  } else if (lastComma >= 0) {
    normalized = text.replace(/\./g, '').replace(',', '.')
  } else {
    normalized = text.replace(/,/g, '')
  }

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

function mapRow (raw, index, baseIndex = 0) {
  const row = {
    id: baseIndex + index + 1,
    productCode: toText(raw?.ProductCode),
    stockQty: toNumber(raw?.StockQty),
    stockEntryDate: toText(raw?.StockEntryDate),
    lastCostingDate: toText(raw?.LastCostingDate),
    lastPricingDate: toText(raw?.LastPricingDate),
    askiliYan: toText(raw?.AskiliYan),
    kategori: toText(raw?.Kategori),
    urunIlkGrubu: toText(raw?.UrunIlkGrubu),
    urunAnaGrubu: toText(raw?.UrunAnaGrubu),
    urunAltGrubu: toText(raw?.UrunAltGrubu),
    icerik: toText(raw?.Icerik),
    karisim: toText(raw?.Karisim),
    marka: toText(raw?.Marka),
    brandGroupSelection: toText(raw?.BrandGroupSec),
    costPrice: toNumber(raw?.CostPrice),
    expenseForBasePrice: 0,
    basePriceUsd: toNumber(raw?.BasePriceUsd),
    basePriceTry: toNumber(raw?.BasePriceTry),
    usd1: toNumber(raw?.USD1),
    usd2: toNumber(raw?.USD2),
    usd3: toNumber(raw?.USD3),
    usd4: toNumber(raw?.USD4),
    usd5: toNumber(raw?.USD5),
    usd6: toNumber(raw?.USD6),
    eur1: toNumber(raw?.EUR1),
    eur2: toNumber(raw?.EUR2),
    eur3: toNumber(raw?.EUR3),
    eur4: toNumber(raw?.EUR4),
    eur5: toNumber(raw?.EUR5),
    eur6: toNumber(raw?.EUR6),
    try1: toNumber(raw?.TRY1),
    try2: toNumber(raw?.TRY2),
    try3: toNumber(raw?.TRY3),
    try4: toNumber(raw?.TRY4),
    try5: toNumber(raw?.TRY5),
    try6: toNumber(raw?.TRY6)
  }
  const originalFields = [
    'costPrice',
    'basePriceUsd',
    'basePriceTry',
    'usd1', 'usd2', 'usd3', 'usd4', 'usd5', 'usd6',
    'eur1', 'eur2', 'eur3', 'eur4', 'eur5', 'eur6',
    'try1', 'try2', 'try3', 'try4', 'try5', 'try6'
  ]
  originalFields.forEach((field) => {
    row[`__orig_${field}`] = row[field]
  })
  return row
}

function cloneRows (rows = []) {
  return rows.map((r) => ({ ...r }))
}

function normalizeFilterList (list) {
  if (!Array.isArray(list)) return []
  return list.map((x) => toText(x)).filter(Boolean).sort()
}

function normalizeFilters (filters = {}) {
  const keys = ['product_code', 'brand_group_selection', 'askili_yan', 'kategori', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'icerik', 'karisim', 'marka']
  const out = {}
  for (const key of keys) out[key] = normalizeFilterList(filters[key])
  const q = toText(filters.q)
  if (q) out.q = q
  return out
}

function hasPrimaryFilter (filters = {}) {
  return (Array.isArray(filters.product_code) && filters.product_code.length > 0) ||
    (Array.isArray(filters.urun_ilk_grubu) && filters.urun_ilk_grubu.length > 0) ||
    (Array.isArray(filters.urun_ana_grubu) && filters.urun_ana_grubu.length > 0)
}

function makeCacheKey (limit, page, filters) {
  return JSON.stringify({
    limit: Number(limit) || 500,
    page: Number(page) || 1,
    filters: normalizeFilters(filters),
    sortBy: toText(filters?.__sortBy),
    descending: Boolean(filters?.__descending)
  })
}

export const useProductPricingStore = defineStore('product-pricing-store', {
  state: () => ({
    rows: [],
    loading: false,
    error: '',
    hasMore: true,
    page: 1,
    totalPages: 1,
    totalCount: 0,
    pageCache: {},
    cacheOrder: [],
    prefetchInFlight: {}
  }),

  actions: {
    cachePut (key, value) {
      this.pageCache[key] = value
      this.cacheOrder = this.cacheOrder.filter((x) => x !== key)
      this.cacheOrder.push(key)
      while (this.cacheOrder.length > 24) {
        const oldest = this.cacheOrder.shift()
        if (oldest) delete this.pageCache[oldest]
      }
    },

    cacheGet (key) {
      return this.pageCache[key] || null
    },

    applyPageResult (payload = {}, requestedPage = 1) {
      const data = Array.isArray(payload?.rows) ? payload.rows : []
      this.rows = cloneRows(data)
      this.totalCount = Number.isFinite(payload?.totalCount) ? payload.totalCount : 0
      this.totalPages = Math.max(1, Number(payload?.totalPages || 1))
      this.page = Math.max(1, Number(payload?.page || requestedPage))
      this.hasMore = this.page < this.totalPages
    },

    async prefetchPage (options = {}) {
      const limit = Number(options?.limit) > 0 ? Number(options.limit) : 500
      const page = Number(options?.page) > 0 ? Number(options.page) : 1
      const filters = normalizeFilters(options?.filters || {})
      const sortBy = toText(options?.sortBy)
      const descending = Boolean(options?.descending)
      const key = makeCacheKey(limit, page, filters)
      if (this.pageCache[key]) return
      if (this.prefetchInFlight[key]) {
        await this.prefetchInFlight[key]
        return
      }
      const run = async () => {
        try {
          const includeTotal = hasPrimaryFilter(filters) ? 1 : 0
          const params = { limit, page, include_total: includeTotal }
          if (sortBy) {
            params.sort_by = sortBy
            params.desc = descending ? 1 : 0
          }
          for (const k of Object.keys(filters)) {
            if (k === 'q') {
              params.q = filters.q
              continue
            }
            if (Array.isArray(filters[k]) && filters[k].length > 0) {
              params[k] = filters[k].join(',')
            }
          }
          const res = await api.request({
            method: 'GET',
            url: '/pricing/products',
            params,
            timeout: 180000
          })
          const totalCount = Number(res?.headers?.['x-total-count'] || 0) 
          let totalPages = Math.max(1, Number(res?.headers?.['x-total-pages'] || 0)) 
          const currentPage = Math.max(1, Number(res?.headers?.['x-page'] || page)) 
          const data = Array.isArray(res?.data) ? res.data : [] 
          const mapped = data.map((x, i) => mapRow(x, i, 0)) 
          if (!Number.isFinite(totalPages) || totalPages <= 0) {
            totalPages = mapped.length >= limit ? currentPage + 1 : currentPage
          }
          this.cachePut(key, {
            rows: mapped,
            totalCount: Number.isFinite(totalCount) ? totalCount : 0,
            totalPages: Number.isFinite(totalPages) ? totalPages : 1,
            page: currentPage
          })
        } catch {
        }
      }
      this.prefetchInFlight[key] = run()
      try {
        await this.prefetchInFlight[key]
      } finally {
        delete this.prefetchInFlight[key]
      }
    },

    async fetchRows (options = {}) {
      const silent = Boolean(options?.silent)
      if (!silent) {
        this.loading = true
        this.error = ''
      }
      const limit = Number(options?.limit) > 0 ? Number(options.limit) : 500
      const page = Number(options?.page) > 0 ? Number(options.page) : 1
      const append = Boolean(options?.append)
      const baseIndex = append ? this.rows.length : 0
      const filters = normalizeFilters(options?.filters || {})
      const sortBy = toText(options?.sortBy)
      const descending = Boolean(options?.descending)
      const cacheKey = makeCacheKey(limit, page, filters)
      const startedAt = Date.now()
      console.info('[product-pricing][frontend] request:start', {
        at: new Date(startedAt).toISOString(),
        timeout_ms: 180000,
        limit,
        page,
        append
      })
      try {
        if (options?.useCache !== false) {
          const inFlight = this.prefetchInFlight[cacheKey]
          if (inFlight) {
            await inFlight
          }
          const cached = this.cacheGet(cacheKey)
          if (cached) {
            this.applyPageResult(cached, page)
            console.info('[product-pricing][frontend] request:cache-hit', {
              page: this.page,
              total_pages: this.totalPages,
              row_count: this.rows.length,
              duration_ms: Date.now() - startedAt
            })
            return {
              traceId: null,
              fetched: this.rows.length,
              hasMore: this.hasMore,
              page: this.page,
              totalPages: this.totalPages,
              totalCount: this.totalCount
            }
          }
        }

        const includeTotal = hasPrimaryFilter(filters) ? 1 : 0
        const params = { limit, page, include_total: includeTotal }
        if (sortBy) {
          params.sort_by = sortBy
          params.desc = descending ? 1 : 0
        }
        for (const key of Object.keys(filters)) {
          if (key === 'q') {
            params.q = filters.q
            continue
          }
          const list = filters[key]
          if (Array.isArray(list) && list.length > 0) params[key] = list.join(',')
        }
        const res = await api.request({
          method: 'GET',
          url: '/pricing/products',
          params,
          timeout: 180000
        })
        const traceId = res?.headers?.['x-trace-id'] || null
        const totalCount = Number(res?.headers?.['x-total-count'] || 0) 
        let totalPages = Math.max(1, Number(res?.headers?.['x-total-pages'] || 0)) 
        const currentPage = Math.max(1, Number(res?.headers?.['x-page'] || page)) 
        const data = Array.isArray(res?.data) ? res.data : [] 
        const mapped = data.map((x, i) => mapRow(x, i, baseIndex))
        if (!Number.isFinite(totalPages) || totalPages <= 0) {
          // When server skips count, infer "hasMore" from page size.
          totalPages = mapped.length >= limit ? currentPage + 1 : currentPage
        }
        const payload = {
          rows: mapped,
          totalCount: Number.isFinite(totalCount) ? totalCount : 0,
          totalPages: Number.isFinite(totalPages) ? totalPages : 1,
          page: Number.isFinite(currentPage) ? currentPage : page
        }
        this.cachePut(cacheKey, payload)
        if (append) {
          this.rows = [...cloneRows(this.rows || []), ...mapped.map((r) => ({ ...r }))]
          this.totalCount = Number.isFinite(payload.totalCount) ? payload.totalCount : this.totalCount
          this.totalPages = Math.max(1, Number(payload.totalPages || this.totalPages || 1))
          this.page = Math.max(1, Number(payload.page || page))
          this.hasMore = this.page < this.totalPages
        } else {
          this.applyPageResult(payload, page)
        }

        console.info('[product-pricing][frontend] request:success', {
          trace_id: traceId,
          duration_ms: Date.now() - startedAt,
          row_count: this.rows.length,
          fetched_count: mapped.length,
          has_more: this.hasMore,
          page: this.page,
          total_pages: this.totalPages,
          total_count: this.totalCount
        })
        return {
          traceId,
          fetched: mapped.length,
          hasMore: this.hasMore,
          page: this.page,
          totalPages: this.totalPages,
          totalCount: this.totalCount
        }
      } catch (err) {
        this.rows = []
        this.hasMore = false
        const msg = err?.response?.data || err?.message || 'Urun fiyatlandirma listesi alinamadi'
        this.error = toText(msg)
        console.error('[product-pricing][frontend] request:error', {
          trace_id: err?.response?.headers?.['x-trace-id'] || null,
          duration_ms: Date.now() - startedAt,
          timeout_ms: err?.config?.timeout ?? null,
          status: err?.response?.status || null,
          message: this.error
        })
        throw err
      } finally {
        if (!silent) this.loading = false
      }
    },

    // fetchAllByGroups removed: keep paging server-side.

    updateCell (row, field, val) {
      if (!row || !field) return
      row[field] = toNumber(val)
    },

    updateBrandGroupSelection (row, val) {
      if (!row) return
      row.brandGroupSelection = toText(val)
    }
  }
})
