import fs from 'node:fs'
import path from 'node:path'

import { PROJECT_ROOT, runtimeConfig } from '../../../config/runtime.js'

const AGISO_SHOPS_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'agiso-shops.json')
const AGISO_MESSAGING_DEFAULT_KEYS = ['messageTemplate', 'autoDeliveryMessageTemplate']
const AGISO_SHOP_CONFIG_KEYS = [
  'shopName',
  'accessToken',
  'messageTemplate',
  'autoDeliveryMessageTemplate',
  'appSecret',
  'apiVersion',
  'sendMessageEndpoint',
  'tradeDetailEndpoint',
  'tradeDetailApiVersion',
  'tradeDetailTimeoutMs',
]

type JsonObject = Record<string, unknown>

export type AgisoMessagingDefaults = {
  messageTemplate?: string
  autoDeliveryMessageTemplate?: string
}

export type AgisoShopConfig = {
  enabled?: boolean
  shopName?: string
  accessToken?: string
  messageTemplate?: string
  autoDeliveryMessageTemplate?: string
  appSecret?: string
  apiVersion?: string
  sendMessageEndpoint?: string
  tradeDetailEndpoint?: string
  tradeDetailApiVersion?: string
  tradeDetailTimeoutMs?: string
}

export type AgisoMessagingConfigDocument = {
  defaults: AgisoMessagingDefaults
  shops: Record<string, AgisoShopConfig>
}

export function getAgisoShopsFilePath(): string {
  return AGISO_SHOPS_FILE_PATH
}

export function getAgisoShopConfigMap(): Record<string, AgisoShopConfig> {
  const envConfig = normalizeAgisoShopConfigMap(runtimeConfig.platforms?.agiso?.messaging?.shops || {})
  const fileConfig = loadAgisoMessagingConfigDocumentFromFile()

  return {
    ...envConfig,
    ...fileConfig.shops,
  }
}

export function getAgisoShopConfig(shopId: unknown): AgisoShopConfig | null {
  const normalizedShopId = String(shopId || '').trim()
  if (!normalizedShopId) {
    return null
  }

  return getAgisoShopConfigMap()[normalizedShopId] || null
}

export function getAgisoMessagingDefaults(): AgisoMessagingDefaults {
  return loadAgisoMessagingConfigDocumentFromFile().defaults
}

export function saveAgisoMessagingConfig(rawValue: unknown): AgisoMessagingConfigDocument {
  const normalized = normalizeAgisoMessagingConfigDocument(rawValue)
  fs.mkdirSync(path.dirname(AGISO_SHOPS_FILE_PATH), { recursive: true })
  fs.writeFileSync(AGISO_SHOPS_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
  return normalized
}

function loadAgisoMessagingConfigDocumentFromFile(): AgisoMessagingConfigDocument {
  if (!fs.existsSync(AGISO_SHOPS_FILE_PATH)) {
    return {
      defaults: {},
      shops: {},
    }
  }

  try {
    const rawText = fs.readFileSync(AGISO_SHOPS_FILE_PATH, 'utf8')
    const parsed = JSON.parse(rawText)
    return normalizeAgisoMessagingConfigDocument(parsed)
  } catch {
    return {
      defaults: {},
      shops: {},
    }
  }
}

function normalizeAgisoShopConfigMap(rawValue: unknown): Record<string, AgisoShopConfig> {
  const output: Record<string, AgisoShopConfig> = {}

  const entries = isPlainObject(rawValue) ? Object.entries(rawValue) : []
  for (const [shopId, config] of entries) {
    const normalizedShopId = String(shopId || '').trim()
    if (!normalizedShopId || !isPlainObject(config)) {
      continue
    }

    const next: AgisoShopConfig = {}
    const enabled = normalizeBooleanLike(config.enabled)
    if (enabled !== null) {
      next.enabled = enabled
    }

    for (const key of AGISO_SHOP_CONFIG_KEYS) {
      const value = String(config[key] || '').trim()
      if (value) {
        next[key] = value
      }
    }

    output[normalizedShopId] = next
  }

  return output
}

function normalizeAgisoMessagingDefaults(rawValue: unknown): AgisoMessagingDefaults {
  const output: AgisoMessagingDefaults = {}

  if (!isPlainObject(rawValue)) {
    return output
  }

  for (const key of AGISO_MESSAGING_DEFAULT_KEYS) {
    const value = String(rawValue[key] || '').trim()
    if (value) {
      output[key] = value
    }
  }

  return output
}

function normalizeAgisoMessagingConfigDocument(rawValue: unknown): AgisoMessagingConfigDocument {
  const normalizedValue = isPlainObject(rawValue) ? rawValue : {}
  const hasStructuredShape = Object.prototype.hasOwnProperty.call(normalizedValue, 'defaults')
    || Object.prototype.hasOwnProperty.call(normalizedValue, 'shops')

  return {
    defaults: normalizeAgisoMessagingDefaults(hasStructuredShape ? normalizedValue.defaults : {}),
    shops: normalizeAgisoShopConfigMap(hasStructuredShape ? normalizedValue.shops : normalizedValue),
  }
}

function normalizeBooleanLike(value: unknown): boolean | null {
  if (typeof value === 'boolean') {
    return value
  }

  const normalized = String(value || '').trim().toLowerCase()
  if (!normalized) {
    return null
  }

  if (['1', 'true', 'yes', 'on'].includes(normalized)) {
    return true
  }

  if (['0', 'false', 'no', 'off'].includes(normalized)) {
    return false
  }

  return null
}

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