import { getMajorDictById, getMajorIdAliasMap, getServiceDictById } from '@/sql'
import { toFiniteNumberOrNull } from '@/lib/decimal'
import { useKvStore } from '@/pinia/kv'
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'

const CONSULT_CATEGORY_FACTOR_KEY = 'xm-consult-category-factor-v1'
const MAJOR_FACTOR_KEY = 'xm-major-factor-v1'

type XmFactorRow = {
  id: string
  standardFactor: number | null
  budgetValue: number | null
}

type XmFactorState = {
  detailRows?: XmFactorRow[]
}

type FactorDictItem = {
  defCoe?: number | null
}

type FactorDict = Record<string, FactorDictItem>

const buildStandardFactorMap = (dict: FactorDict): Map<string, number | null> => {
  const map = new Map<string, number | null>()
  for (const [id, item] of Object.entries(dict)) {
    map.set(String(id), toFiniteNumberOrNull(item?.defCoe))
  }
  return map
}

const resolveFactorValue = (
  row: Partial<XmFactorRow> | undefined,
  fallbackStandard: number | null
): number | null => {
  if (!row) return null
  if (Object.prototype.hasOwnProperty.call(row, 'budgetValue')) {
    return toFiniteNumberOrNull(row.budgetValue)
  }
  if (Object.prototype.hasOwnProperty.call(row, 'standardFactor')) {
    return toFiniteNumberOrNull(row.standardFactor)
  }
  return fallbackStandard
}

const getKvStoreSafely = () => {
  try {
    return useKvStore()
  } catch {
    return null
  }
}

const getZxFwPricingStoreSafely = () => {
  try {
    return useZxFwPricingStore()
  } catch {
    return null
  }
}

const loadFactorMap = async (
  storageKey: string,
  dict: FactorDict,
  aliases?: Map<string, string>
): Promise<Map<string, number | null>> => {
  const zxFwPricingStore = getZxFwPricingStoreSafely()
  const kvStore = getKvStoreSafely()
  const piniaData = zxFwPricingStore ? await zxFwPricingStore.loadKeyState<XmFactorState>(storageKey) : null
  const data = piniaData ?? (kvStore ? await kvStore.getItem<XmFactorState>(storageKey) : null)
  const map = buildStandardFactorMap(dict)
  for (const row of data?.detailRows || []) {
    if (!row?.id) continue
    const rowId = String(row.id)
    const id = map.has(rowId) ? rowId : aliases?.get(rowId) || rowId
    map.set(id, resolveFactorValue(row, map.get(id) ?? null))
  }
  return map
}

export const loadConsultCategoryFactorMap = async (storageKey = CONSULT_CATEGORY_FACTOR_KEY) =>
  loadFactorMap(storageKey, getServiceDictById() as FactorDict)

export const loadMajorFactorMap = async (storageKey = MAJOR_FACTOR_KEY) =>
  loadFactorMap(storageKey, getMajorDictById() as FactorDict, getMajorIdAliasMap())
