import {
  cloneJson,
  isContractRelatedForageKey,
  isContractRelatedKeyedStateKey,
  isRecord,
  SERVICE_PRICING_METHODS
} from '@/lib/contractSegment'

type AnyRecord = Record<string, unknown>

export interface KvStoreLike {
  keys: () => Promise<string[]>
  getItem: (key: string) => Promise<unknown>
}

export interface ZxFwPricingStoreLike {
  contracts: Record<string, unknown>
  servicePricingStates: Record<string, unknown>
  htFeeMainStates: Record<string, unknown>
  htFeeMethodStates: Record<string, unknown>
  keyedStates: Record<string, unknown>
  loadContract: (...args: any[]) => Promise<unknown>
  getContractState: (...args: any[]) => unknown
  setContractState: (...args: any[]) => Promise<unknown>
  setServicePricingMethodState: (...args: any[]) => unknown
  setHtFeeMainState: (...args: any[]) => unknown
  setHtFeeMethodState: (...args: any[]) => unknown
  setKeyState: (...args: any[]) => unknown
}

export const buildContractPiniaPayload = async (
  store: ZxFwPricingStoreLike,
  contractIds: string[]
) => {
  const idSet = new Set(contractIds.map(id => String(id || '').trim()).filter(Boolean))
  const payload = {
    contracts: {} as AnyRecord,
    servicePricingStates: {} as AnyRecord,
    htFeeMainStates: {} as AnyRecord,
    htFeeMethodStates: {} as AnyRecord
  }
  if (idSet.size === 0) return payload

  await Promise.all(Array.from(idSet).map(id => store.loadContract(id)))

  for (const contractId of idSet) {
    const contractState = store.getContractState(contractId)
    if (contractState) {
      payload.contracts[contractId] = cloneJson(contractState)
    }

    const servicePricingState = store.servicePricingStates[contractId]
    if (isRecord(servicePricingState)) {
      payload.servicePricingStates[contractId] = cloneJson(servicePricingState)
    }

    const mainPrefix = `htExtraFee-${contractId}-`
    for (const [mainKey, mainState] of Object.entries(store.htFeeMainStates)) {
      if (!mainKey.startsWith(mainPrefix)) continue
      payload.htFeeMainStates[mainKey] = cloneJson(mainState)
    }

    for (const [mainKey, methodState] of Object.entries(store.htFeeMethodStates)) {
      if (!mainKey.startsWith(mainPrefix)) continue
      payload.htFeeMethodStates[mainKey] = cloneJson(methodState)
    }
  }

  return payload
}

export const applyImportedContractPiniaPayload = async (
  store: ZxFwPricingStoreLike,
  piniaPayload: unknown,
  oldToNewIdMap: Map<string, string>
) => {
  if (!isRecord(piniaPayload)) return
  const zxFwPayload = isRecord(piniaPayload.zxFwPricing) ? piniaPayload.zxFwPricing : null
  if (!zxFwPayload) return

  const contractsMap = isRecord(zxFwPayload.contracts) ? zxFwPayload.contracts : {}
  const servicePricingStatesMap = isRecord(zxFwPayload.servicePricingStates) ? zxFwPayload.servicePricingStates : {}
  const htFeeMainStatesMap = isRecord(zxFwPayload.htFeeMainStates) ? zxFwPayload.htFeeMainStates : {}
  const htFeeMethodStatesMap = isRecord(zxFwPayload.htFeeMethodStates) ? zxFwPayload.htFeeMethodStates : {}

  for (const [oldId, newId] of oldToNewIdMap.entries()) {
    const rawContractState = contractsMap[oldId]
    if (isRecord(rawContractState) && Array.isArray(rawContractState.detailRows)) {
      await store.setContractState(newId, rawContractState as any)
    }

    const rawServicePricingByService = servicePricingStatesMap[oldId]
    if (isRecord(rawServicePricingByService)) {
      for (const [serviceId, rawServiceMethods] of Object.entries(rawServicePricingByService)) {
        if (!isRecord(rawServiceMethods)) continue
        for (const method of SERVICE_PRICING_METHODS) {
          const methodState = rawServiceMethods[method]
          if (!isRecord(methodState) || !Array.isArray(methodState.detailRows)) continue
          store.setServicePricingMethodState(newId, serviceId, method, methodState as any, { force: true })
        }
      }
    }

    const oldMainPrefix = `htExtraFee-${oldId}-`
    const newMainPrefix = `htExtraFee-${newId}-`
    for (const [oldMainKey, rawMainState] of Object.entries(htFeeMainStatesMap)) {
      if (!oldMainKey.startsWith(oldMainPrefix)) continue
      if (!isRecord(rawMainState) || !Array.isArray(rawMainState.detailRows)) continue
      const newMainKey = oldMainKey.replace(oldMainPrefix, newMainPrefix)
      store.setHtFeeMainState(newMainKey, rawMainState as any, { force: true })
    }

    for (const [oldMainKey, rawByRow] of Object.entries(htFeeMethodStatesMap)) {
      if (!oldMainKey.startsWith(oldMainPrefix)) continue
      if (!isRecord(rawByRow)) continue
      const newMainKey = oldMainKey.replace(oldMainPrefix, newMainPrefix)
      for (const [rowId, rawByMethod] of Object.entries(rawByRow)) {
        if (!isRecord(rawByMethod)) continue
        const ratePayload = rawByMethod['rate-fee']
        const hourlyPayload = rawByMethod['hourly-fee']
        const quantityPayload = rawByMethod['quantity-unit-price-fee']
        if (ratePayload != null) {
          store.setHtFeeMethodState(newMainKey, rowId, 'rate-fee', cloneJson(ratePayload), { force: true })
        }
        if (hourlyPayload != null) {
          store.setHtFeeMethodState(newMainKey, rowId, 'hourly-fee', cloneJson(hourlyPayload), { force: true })
        }
        if (quantityPayload != null) {
          store.setHtFeeMethodState(newMainKey, rowId, 'quantity-unit-price-fee', cloneJson(quantityPayload), { force: true })
        }
      }
    }
  }
}

export const readContractRelatedForageEntries = async (
  kvStore: KvStoreLike,
  contractIds: string[]
) => {
  const keys = await kvStore.keys()
  const idSet = new Set(contractIds)
  const targetKeys = keys.filter(key => {
    for (const id of idSet) {
      if (isContractRelatedForageKey(key, id)) return true
    }
    return false
  })
  return Promise.all(
    targetKeys.map(async key => ({
      key,
      value: await kvStore.getItem(key)
    }))
  )
}

export const readContractRelatedKeyedEntries = (
  store: Pick<ZxFwPricingStoreLike, 'keyedStates'>,
  contractIds: string[]
) => {
  const idSet = new Set(contractIds.map(id => String(id || '').trim()).filter(Boolean))
  return Object.entries(store.keyedStates)
    .filter(([key]) => {
      for (const id of idSet) {
        if (isContractRelatedKeyedStateKey(key, id)) return true
      }
      return false
    })
    .map(([key, value]) => ({
      key,
      value: cloneJson(value)
    }))
}
