import path from 'node:path'
import type { JsonObject } from '../../../types/json.js'

import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT } from '../../../config/runtime.js'
import {
  hasAppConfigEntry,
  readAppConfigEntry,
  saveAppConfigEntry,
} from '../../config/app-config-store.js'
import { normalizeCloudtentaclesMatchName } from '../../order/cloudtentacles-match-utils.js'
import type { KuaishouFeifeiProductRule } from '../../../types/runtime-config.js'

const KUAISHOU_FEIFEI_CONFIG_FILE_PATH = path.join(
  PROJECT_ROOT,
  'data',
  'kuaishou-feifei-config.json',
)

export type KuaishouFeifeiSourceConfig = {
  enabled: boolean
  baseUrl: string
  appKey: string
  appSecret: string
  timeoutMs: number
  notifyUrl: string
  productRules: KuaishouFeifeiProductRule[]
}

export function getKuaishouFeifeiConfigFilePath() {
  return KUAISHOU_FEIFEI_CONFIG_FILE_PATH
}

export function hasKuaishouFeifeiConfigFile() {
  return hasAppConfigEntry(APP_CONFIG_KEYS.kuaishouFeifei, KUAISHOU_FEIFEI_CONFIG_FILE_PATH)
}

export function getKuaishouFeifeiSourceConfig(): KuaishouFeifeiSourceConfig {
  return readAppConfigEntry({
    configKey: APP_CONFIG_KEYS.kuaishouFeifei,
    legacyFilePath: KUAISHOU_FEIFEI_CONFIG_FILE_PATH,
    fallback: createDefaultKuaishouFeifeiSourceConfig,
    normalize: normalizeKuaishouFeifeiSourceConfig,
  })
}

export function saveKuaishouFeifeiSourceConfig(
  rawValue: unknown,
): Promise<KuaishouFeifeiSourceConfig> {
  return saveAppConfigEntry({
    configKey: APP_CONFIG_KEYS.kuaishouFeifei,
    legacyFilePath: KUAISHOU_FEIFEI_CONFIG_FILE_PATH,
    value: rawValue,
    normalize: normalizeKuaishouFeifeiSourceConfig,
  })
}

export function normalizeKuaishouFeifeiSourceConfig(rawValue: unknown): KuaishouFeifeiSourceConfig {
  const source = isPlainObject(rawValue) ? rawValue : {}

  return {
    enabled: source.enabled !== false,
    baseUrl: String(source.baseUrl || 'http://skin-exchange.yiquyou.icu').trim(),
    appKey: String(source.appKey || '').trim(),
    appSecret: String(source.appSecret || '').trim(),
    timeoutMs: normalizePositiveInteger(source.timeoutMs, 10000),
    notifyUrl: String(source.notifyUrl || '').trim(),
    productRules: normalizeKuaishouFeifeiProductRules(source.productRules),
  }
}

export function normalizeKuaishouFeifeiProductRules(value: unknown): KuaishouFeifeiProductRule[] {
  const rules = Array.isArray(value) ? value : []
  const normalizedRules = rules
    .map((item) => normalizeKuaishouFeifeiProductRule(item))
    .filter((item): item is KuaishouFeifeiProductRule => Boolean(item))

  return dedupeProductRules(normalizedRules)
}

function normalizeKuaishouFeifeiProductRule(rawValue: unknown): KuaishouFeifeiProductRule | null {
  const source = isPlainObject(rawValue) ? rawValue : {}
  const productName = String(source.productName || source.name || '').trim()
  const normalizedProductName = normalizeCloudtentaclesMatchName(productName)
  const productCode = String(source.productCode || source.code || '').trim()

  if (!productName || !normalizedProductName || !productCode) {
    return null
  }

  return {
    id: String(source.id || normalizedProductName).trim() || normalizedProductName,
    enabled: source.enabled !== false,
    productName,
    normalizedProductName,
    productCode,
    skuName: String(source.skuName || source.productName || productName).trim(),
    notes: String(source.notes || '').trim(),
  }
}

function dedupeProductRules(rules: KuaishouFeifeiProductRule[]) {
  const map = new Map<string, KuaishouFeifeiProductRule>()

  for (const rule of rules) {
    const key = normalizeCloudtentaclesMatchName(rule.productName)
    if (!key) {
      continue
    }

    map.set(key, rule)
  }

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

function createDefaultKuaishouFeifeiSourceConfig(): KuaishouFeifeiSourceConfig {
  return {
    enabled: true,
    baseUrl: 'http://skin-exchange.yiquyou.icu',
    appKey: '',
    appSecret: '',
    timeoutMs: 10000,
    notifyUrl: '',
    productRules: [],
  }
}

function normalizePositiveInteger(value: unknown, fallback: number) {
  const parsed = Number(value)
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
}

function isPlainObject(value: unknown): value is JsonObject {
  return Object.prototype.toString.call(value) === '[object Object]'
}
