import { runtimeConfig } from '../../../config/runtime.js'
import { createHttpError } from '../../../utils/http.js'
import type { AffiliateDashSkuMapping, RuntimeConfig } from '../../../types/runtime-config.js'
import {
  getAffiliateDashSourceConfig,
  hasAffiliateDashConfig,
  type AffiliateDashSourceConfig,
} from './source-config-service.js'

export const AFFILIATE_DASH_EXECUTOR_KEY = 'affiliate_dash'
export const AFFILIATE_DASH_PROFILE_KEY = 'affiliate_dash'
export const AFFILIATE_DASH_WEBHOOK_PATH = '/api/v1/open/affiliate-dash'
export const AFFILIATE_DASH_TIMESTAMP_TOLERANCE_SECONDS = 300

type AffiliateDashRuntimeConfig = RuntimeConfig['platforms']['affiliateDash']

export function getAffiliateDashConfig(overrides: Partial<AffiliateDashRuntimeConfig> = {}) {
  const runtimeValue = runtimeConfig.platforms?.affiliateDash || {}
  const savedValue = hasAffiliateDashConfig() ? getAffiliateDashSourceConfig() : null
  const config = mergeAffiliateDashConfig(runtimeValue, savedValue, overrides)

  return {
    enabled: config.enabled !== false,
    baseUrl: String(config.baseUrl || '')
      .trim()
      .replace(/\/+$/, ''),
    appKey: String(config.appKey || '').trim(),
    appSecret: String(config.appSecret || '').trim(),
    callbackSecret: String(config.callbackSecret || '').trim(),
    timeoutMs: Math.max(1, Number(config.timeoutMs || 10000) || 10000),
    notifyUrl: String(config.notifyUrl || '').trim(),
    timestampToleranceSeconds: Math.max(
      1,
      Number(config.timestampToleranceSeconds || AFFILIATE_DASH_TIMESTAMP_TOLERANCE_SECONDS) ||
        AFFILIATE_DASH_TIMESTAMP_TOLERANCE_SECONDS,
    ),
    preferredMatchEnabled: config.preferredMatchEnabled !== false,
    skuMapping: isRecord(config.skuMapping) ? config.skuMapping : {},
  }
}

export function assertAffiliateDashConfig() {
  const config = getAffiliateDashConfig()

  if (config.enabled === false) {
    throw createHttpError('affiliate-dash 已停用', {
      statusCode: 409,
      errorCode: 'affiliate_dash_disabled',
    })
  }

  if (!config.baseUrl) {
    throw createHttpError('affiliate-dash baseUrl 未配置', {
      statusCode: 500,
      errorCode: 'affiliate_dash_missing_base_url',
    })
  }

  if (!config.appKey || !config.appSecret) {
    throw createHttpError('affiliate-dash App Key / App Secret 未配置', {
      statusCode: 500,
      errorCode: 'affiliate_dash_missing_credential',
    })
  }

  return config
}

function mergeAffiliateDashConfig(
  runtimeValue: Partial<AffiliateDashRuntimeConfig>,
  savedValue: Partial<AffiliateDashSourceConfig> | null,
  overrides: Partial<AffiliateDashRuntimeConfig>,
): AffiliateDashRuntimeConfig {
  const base: AffiliateDashRuntimeConfig = savedValue
    ? {
        enabled: savedValue.enabled !== false,
        baseUrl: savedValue.baseUrl || runtimeValue.baseUrl || '',
        appKey: savedValue.appKey || runtimeValue.appKey || '',
        appSecret: savedValue.appSecret || runtimeValue.appSecret || '',
        callbackSecret: savedValue.callbackSecret || runtimeValue.callbackSecret || '',
        timeoutMs: savedValue.timeoutMs || runtimeValue.timeoutMs || 10000,
        notifyUrl: savedValue.notifyUrl || runtimeValue.notifyUrl || '',
        timestampToleranceSeconds:
          savedValue.timestampToleranceSeconds ||
          runtimeValue.timestampToleranceSeconds ||
          AFFILIATE_DASH_TIMESTAMP_TOLERANCE_SECONDS,
        preferredMatchEnabled:
          savedValue.preferredMatchEnabled ?? runtimeValue.preferredMatchEnabled ?? true,
        skuMapping: pickSkuMapping(savedValue.skuMapping, runtimeValue.skuMapping),
      }
    : {
        enabled: runtimeValue.enabled !== false,
        baseUrl: runtimeValue.baseUrl || '',
        appKey: runtimeValue.appKey || '',
        appSecret: runtimeValue.appSecret || '',
        callbackSecret: runtimeValue.callbackSecret || '',
        timeoutMs: runtimeValue.timeoutMs || 10000,
        notifyUrl: runtimeValue.notifyUrl || '',
        timestampToleranceSeconds:
          runtimeValue.timestampToleranceSeconds || AFFILIATE_DASH_TIMESTAMP_TOLERANCE_SECONDS,
        preferredMatchEnabled: runtimeValue.preferredMatchEnabled ?? true,
        skuMapping: pickSkuMapping(undefined, runtimeValue.skuMapping),
      }

  return {
    enabled: overrides.enabled ?? base.enabled,
    baseUrl: overrides.baseUrl ?? base.baseUrl,
    appKey: overrides.appKey ?? base.appKey,
    appSecret: overrides.appSecret ?? base.appSecret,
    callbackSecret: overrides.callbackSecret ?? base.callbackSecret,
    timeoutMs: overrides.timeoutMs ?? base.timeoutMs,
    notifyUrl: overrides.notifyUrl ?? base.notifyUrl,
    timestampToleranceSeconds:
      overrides.timestampToleranceSeconds ?? base.timestampToleranceSeconds,
    preferredMatchEnabled: overrides.preferredMatchEnabled ?? base.preferredMatchEnabled,
    skuMapping: pickSkuMapping(overrides.skuMapping, base.skuMapping),
  }
}

function pickSkuMapping(
  preferred?: AffiliateDashSkuMapping,
  fallback?: AffiliateDashSkuMapping,
): AffiliateDashSkuMapping {
  if (preferred && Object.keys(preferred).length) {
    return preferred
  }
  if (fallback && Object.keys(fallback).length) {
    return fallback
  }
  return {}
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return Object.prototype.toString.call(value) === '[object Object]'
}
