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, runtimeConfig } from '../../../config/runtime.js'
import { readAppConfigEntry, saveAppConfigEntry } from '../../config/app-config-store.js'

const KUAISHOU_INDUSTRY_SOURCE_FILE_PATH = path.join(
  PROJECT_ROOT,
  'data',
  'kuaishou-industry-source.json',
)
const DEFAULT_CALLBACK_BASE_URL = 'https://openapi.kwaixiaodian.com'
const DEFAULT_AUTH_BASE_URL = 'https://open.kwaixiaodian.com'
const LEGACY_DEFAULT_REDIRECT_URI = 'https://ks.khhao.com/oauth-callback'
const DEFAULT_REDIRECT_URI = 'https://ks.khhao.com/admin/platform-shops?tab=kuaishouIndustry'
const DEFAULT_SCOPES = 'merchant_item'

export type KuaishouIndustryShopConfig = {
  enabled: boolean
  sellerId: string
  shopId: string
  shopName: string
  customShopName: string
  authState: string
  accessToken: string
  refreshToken: string
  accessTokenExpiresAt: string
  refreshTokenExpiresAt: string
  openId: string
  grantedScopes: string
  lastRefreshedAt: string
  lastRefreshError: string
}

export type KuaishouIndustrySourceConfig = {
  enabled: boolean
  baseUrl: string
  authBaseUrl: string
  redirectUri: string
  scopes: string
  authState: string
  appKey: string
  appSecret: string
  signSecret: string
  messageSecret: string
  accessToken: string
  refreshToken: string
  accessTokenExpiresAt: string
  refreshTokenExpiresAt: string
  openId: string
  grantedScopes: string
  sellerId: string
  provider: string
  platform: string
  shopId: string
  shopName: string
  version: string
  shops: KuaishouIndustryShopConfig[]
  lastRefreshedAt: string
  lastRefreshError: string
}

export function getKuaishouIndustrySourceFilePath(): string {
  return KUAISHOU_INDUSTRY_SOURCE_FILE_PATH
}

export function getKuaishouIndustrySourceConfig(): KuaishouIndustrySourceConfig {
  return readAppConfigEntry({
    configKey: APP_CONFIG_KEYS.kuaishouIndustrySource,
    legacyFilePath: KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
    fallback: createDefaultKuaishouIndustrySourceConfig,
    normalize: normalizeKuaishouIndustrySourceConfig,
  })
}

export function saveKuaishouIndustrySourceConfig(
  rawValue: unknown,
): Promise<KuaishouIndustrySourceConfig> {
  return saveAppConfigEntry({
    configKey: APP_CONFIG_KEYS.kuaishouIndustrySource,
    legacyFilePath: KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
    value: rawValue,
    normalize: normalizeKuaishouIndustrySourceConfig,
  })
}

export function patchKuaishouIndustrySourceConfig(
  patch: Partial<KuaishouIndustrySourceConfig>,
): Promise<KuaishouIndustrySourceConfig> {
  return saveKuaishouIndustrySourceConfig({
    ...getKuaishouIndustrySourceConfig(),
    ...patch,
  })
}

export function listKuaishouIndustryShopConfigs(
  source: KuaishouIndustrySourceConfig = getKuaishouIndustrySourceConfig(),
): KuaishouIndustryShopConfig[] {
  return Array.isArray(source.shops) ? source.shops : []
}

export function findKuaishouIndustryShopConfig(
  sellerId: unknown,
  source: KuaishouIndustrySourceConfig = getKuaishouIndustrySourceConfig(),
): KuaishouIndustryShopConfig | null {
  const normalizedSellerId = String(sellerId || '').trim()
  if (!normalizedSellerId) {
    return null
  }

  return (
    listKuaishouIndustryShopConfigs(source).find(
      (shop) => String(shop.sellerId || shop.shopId || '').trim() === normalizedSellerId,
    ) || null
  )
}

export function patchKuaishouIndustryShopConfig(
  sellerId: unknown,
  patch: Partial<KuaishouIndustryShopConfig>,
): Promise<KuaishouIndustrySourceConfig> {
  const source = getKuaishouIndustrySourceConfig()
  const normalizedSellerId = String(patch.sellerId || sellerId || '').trim()
  const existing = findKuaishouIndustryShopConfig(normalizedSellerId, source)
  const nextShop = normalizeKuaishouIndustryShopConfig({
    ...(existing || {}),
    ...patch,
    sellerId: normalizedSellerId,
  })

  if (!nextShop) {
    return Promise.resolve(source)
  }

  const shops = listKuaishouIndustryShopConfigs(source).filter(
    (shop) => String(shop.sellerId || shop.shopId || '').trim() !== normalizedSellerId,
  )

  return saveKuaishouIndustrySourceConfig({
    ...source,
    shops: [...shops, nextShop],
  })
}

export function normalizeKuaishouIndustrySourceConfig(
  rawValue: unknown,
): KuaishouIndustrySourceConfig {
  const fallback = createDefaultKuaishouIndustrySourceConfig()
  const source = isPlainObject(rawValue) ? rawValue : {}
  const shops = normalizeKuaishouIndustryShopList(source)
  const primaryShop = shops[0] || createEmptyKuaishouIndustryShopConfig()

  return {
    enabled: typeof source.enabled === 'boolean' ? source.enabled : fallback.enabled,
    baseUrl: normalizeUrlLike(source.baseUrl, fallback.baseUrl),
    authBaseUrl: normalizeUrlLike(source.authBaseUrl, fallback.authBaseUrl),
    redirectUri: normalizeRedirectUri(source.redirectUri, fallback.redirectUri),
    scopes: normalizeScopeText(normalizeString(source.scopes, fallback.scopes)),
    authState: normalizeString(source.authState, fallback.authState),
    appKey: normalizeString(source.appKey, fallback.appKey),
    appSecret: normalizeString(source.appSecret, fallback.appSecret),
    signSecret: normalizeString(source.signSecret, fallback.signSecret),
    messageSecret: normalizeString(source.messageSecret, fallback.messageSecret),
    accessToken: primaryShop.accessToken,
    refreshToken: primaryShop.refreshToken,
    accessTokenExpiresAt: primaryShop.accessTokenExpiresAt,
    refreshTokenExpiresAt: primaryShop.refreshTokenExpiresAt,
    openId: primaryShop.openId,
    grantedScopes: primaryShop.grantedScopes,
    sellerId: primaryShop.sellerId,
    provider: normalizeString(source.provider, fallback.provider),
    platform: normalizeString(source.platform, fallback.platform),
    shopId: normalizeString(source.shopId, primaryShop.shopId || fallback.shopId),
    shopName: normalizeString(source.shopName, primaryShop.shopName || fallback.shopName),
    version: normalizeString(source.version, fallback.version),
    shops,
    lastRefreshedAt: primaryShop.lastRefreshedAt || normalizeNullableIso(source.lastRefreshedAt),
    lastRefreshError: primaryShop.lastRefreshError || normalizeString(source.lastRefreshError, ''),
  }
}

function createDefaultKuaishouIndustrySourceConfig(): KuaishouIndustrySourceConfig {
  const runtime = runtimeConfig.platforms?.kuaishouIndustry || {}

  return {
    enabled: true,
    baseUrl: DEFAULT_CALLBACK_BASE_URL,
    authBaseUrl: DEFAULT_AUTH_BASE_URL,
    redirectUri: DEFAULT_REDIRECT_URI,
    scopes: DEFAULT_SCOPES,
    authState: '',
    appKey: String(runtime.appKey || '').trim(),
    appSecret: String(runtime.appSecret || '').trim(),
    signSecret: String(runtime.signSecret || '').trim(),
    messageSecret: String(runtime.messageSecret || '').trim(),
    accessToken: '',
    refreshToken: '',
    accessTokenExpiresAt: '',
    refreshTokenExpiresAt: '',
    openId: '',
    grantedScopes: '',
    sellerId: '',
    provider: String(runtime.provider || 'kuaishou-industry').trim() || 'kuaishou-industry',
    platform: String(runtime.platform || 'kuaishou').trim() || 'kuaishou',
    shopId: String(runtime.shopId || 'kuaishou-industry').trim() || 'kuaishou-industry',
    shopName: String(runtime.shopName || '快手行业电子凭证').trim() || '快手行业电子凭证',
    version: String(runtime.version || '1').trim() || '1',
    shops: [],
    lastRefreshedAt: '',
    lastRefreshError: '',
  }
}

function normalizeKuaishouIndustryShopList(source: JsonObject): KuaishouIndustryShopConfig[] {
  const rawShops = Array.isArray(source.shops) ? source.shops : buildLegacySingleShopList(source)

  const deduped = new Map<string, KuaishouIndustryShopConfig>()
  let unnamedIndex = 0
  for (const item of rawShops) {
    const shop = normalizeKuaishouIndustryShopConfig(item)
    if (!shop) {
      continue
    }

    const key = shop.sellerId || shop.shopId || `__legacy_${unnamedIndex++}`

    deduped.set(key, shop)
  }

  return [...deduped.values()]
}

function normalizeKuaishouIndustryShopConfig(rawValue: unknown): KuaishouIndustryShopConfig | null {
  if (!isPlainObject(rawValue)) {
    return null
  }

  const sellerId = String(rawValue.sellerId || rawValue.shopId || rawValue.userId || '').trim()
  const shopId = String(rawValue.shopId || sellerId).trim()
  const shopName = String(rawValue.shopName || rawValue.kshopName || rawValue.userName || '').trim()
  const customShopName = String(rawValue.customShopName || '').trim()
  const accessToken = normalizeString(rawValue.accessToken, '')
  const refreshToken = normalizeString(rawValue.refreshToken, '')
  const openId = normalizeString(rawValue.openId, '')

  if (
    !sellerId &&
    !shopId &&
    !shopName &&
    !customShopName &&
    !accessToken &&
    !refreshToken &&
    !openId
  ) {
    return null
  }

  return {
    enabled: typeof rawValue.enabled === 'boolean' ? rawValue.enabled : true,
    sellerId: sellerId || shopId,
    shopId: shopId || sellerId,
    shopName,
    customShopName,
    authState: normalizeString(rawValue.authState, ''),
    accessToken,
    refreshToken,
    accessTokenExpiresAt: normalizeNullableIso(rawValue.accessTokenExpiresAt),
    refreshTokenExpiresAt: normalizeNullableIso(rawValue.refreshTokenExpiresAt),
    openId,
    grantedScopes: normalizeScopeText(normalizeString(rawValue.grantedScopes, '')),
    lastRefreshedAt: normalizeNullableIso(rawValue.lastRefreshedAt),
    lastRefreshError: normalizeString(rawValue.lastRefreshError, ''),
  }
}

function buildLegacySingleShopList(source: JsonObject): JsonObject[] {
  const legacyShopId = String(source.shopId || '').trim()
  const sellerId = String(
    source.sellerId || (legacyShopId && legacyShopId !== 'kuaishou-industry' ? legacyShopId : ''),
  ).trim()
  const accessToken = String(source.accessToken || '').trim()
  const refreshToken = String(source.refreshToken || '').trim()
  const openId = String(source.openId || '').trim()
  const shopName = String(source.shopName || '').trim()
  const customShopName = String(source.customShopName || '').trim()

  if (!sellerId && !accessToken && !refreshToken && !openId && !shopName && !customShopName) {
    return []
  }

  return [
    {
      enabled: source.enabled !== false,
      sellerId,
      shopId: sellerId,
      shopName,
      customShopName,
      authState: source.authState,
      accessToken,
      refreshToken,
      accessTokenExpiresAt: source.accessTokenExpiresAt,
      refreshTokenExpiresAt: source.refreshTokenExpiresAt,
      openId,
      grantedScopes: source.grantedScopes,
      lastRefreshedAt: source.lastRefreshedAt,
      lastRefreshError: source.lastRefreshError,
    },
  ]
}

function createEmptyKuaishouIndustryShopConfig(): KuaishouIndustryShopConfig {
  return {
    enabled: true,
    sellerId: '',
    shopId: '',
    shopName: '',
    customShopName: '',
    authState: '',
    accessToken: '',
    refreshToken: '',
    accessTokenExpiresAt: '',
    refreshTokenExpiresAt: '',
    openId: '',
    grantedScopes: '',
    lastRefreshedAt: '',
    lastRefreshError: '',
  }
}

function normalizeString(value: unknown, fallback: string): string {
  const text = String(value || '').trim()
  return text || fallback
}

function normalizeRedirectUri(value: unknown, fallback: string): string {
  const text = String(value || '').trim()
  if (!text || text === LEGACY_DEFAULT_REDIRECT_URI) {
    return fallback
  }

  return text
}

function normalizeScopeText(value: unknown): string {
  return String(value || '')
    .split(/[,\s]+/)
    .map((item) => item.trim())
    .filter(Boolean)
    .join(',')
}

function normalizeUrlLike(value: unknown, fallback: string): string {
  return (
    String(value || fallback)
      .trim()
      .replace(/\/+$/, '') || fallback
  )
}

function normalizeNullableIso(value: unknown): string {
  const text = String(value || '').trim()
  if (!text) {
    return ''
  }

  const timestamp = Date.parse(text)
  return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : ''
}

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