import type { JsonObject } from '../../../types/json.js'
import {
  getNotificationConfig,
  getNotificationConfigFilePath,
  saveNotificationConfig,
} from '../../notification/config-service.js'
import { sendInternalNotification } from '../../notification/notification-service.js'
import { listCloudtentaclesSources } from '../../platforms/cloudtentacles/source-config-service.js'
import { getAllCloudtentaclesSessionStates } from '../../platforms/cloudtentacles/session-state-service.js'
import {
  getScheduledJobsConfig,
  getScheduledJobsFilePath,
  saveScheduledJobsConfig,
} from '../../scheduler/config-service.js'
import {
  getScheduledJobRuntimeStates,
  reloadScheduledJobs,
  runScheduledJobNow,
} from '../../scheduler/scheduler-service.js'
import { maskPhone, maskSecret } from './cloudtentacles/mappers.js'

import type {
  AdminNotificationConfigInput,
  AdminNotificationTestInput,
  AdminScheduledJobsConfigInput,
} from '../../../types/admin/write-inputs.js'

export function getAdminNotificationConfig() {
  const config = getNotificationConfig()

  return {
    filePath: getNotificationConfigFilePath(),
    source: mapAdminNotificationConfig(config),
  }
}

export async function updateAdminNotificationConfig(payload: AdminNotificationConfigInput = {}) {
  const saved = await saveNotificationConfig(payload)

  return {
    filePath: getNotificationConfigFilePath(),
    source: mapAdminNotificationConfig(saved),
  }
}

export async function testAdminNotification(payload: AdminNotificationTestInput = {}) {
  return sendInternalNotification({
    title: String(payload.title || '订单系统测试通知').trim() || '订单系统测试通知',
    body: String(payload.body || '这是一条内部通知测试。').trim() || '这是一条内部通知测试。',
    category: 'test',
    url: String(payload.url || '').trim(),
  })
}

export function getAdminScheduledJobsConfig() {
  const config = getScheduledJobsConfig()

  return {
    filePath: getScheduledJobsFilePath(),
    source: mapAdminScheduledJobsConfig(config),
    runtime: getScheduledJobRuntimeStates(),
    cloudtentaclesAccounts: listAdminCloudtentaclesMonitorAccounts(),
  }
}

export async function updateAdminScheduledJobsConfig(payload: AdminScheduledJobsConfigInput = {}) {
  const saved = await saveScheduledJobsConfig(payload)
  reloadScheduledJobs()

  return {
    filePath: getScheduledJobsFilePath(),
    source: mapAdminScheduledJobsConfig(saved),
    runtime: getScheduledJobRuntimeStates(),
    cloudtentaclesAccounts: listAdminCloudtentaclesMonitorAccounts(),
  }
}

export async function runAdminScheduledJobNow(jobId: unknown) {
  const result = await runScheduledJobNow(jobId)

  return {
    result,
    runtime: getScheduledJobRuntimeStates(),
  }
}

function mapAdminNotificationConfig(config: JsonObject = {}) {
  const bark = config.channels?.bark || {}
  const wpush = config.channels?.wpush || {}

  return {
    enabled: config.enabled !== false,
    channels: {
      bark: {
        enabled: bark.enabled !== false,
        serverUrl: String(bark.serverUrl || 'https://api.day.app').trim(),
        recipients: (Array.isArray(bark.recipients) ? bark.recipients : []).map(
          (item: JsonObject) => ({
            id: String(item.id || '').trim(),
            name: String(item.name || '').trim(),
            deviceKey: String(item.deviceKey || '').trim(),
            deviceKeyMasked: maskSecret(item.deviceKey),
            enabled: item.enabled !== false,
          }),
        ),
      },
      wpush: {
        enabled: wpush.enabled !== false,
        recipients: (Array.isArray(wpush.recipients) ? wpush.recipients : []).map(
          (item: JsonObject) => ({
            id: String(item.id || '').trim(),
            name: String(item.name || '').trim(),
            apiKey: String(item.apiKey || item.apikey || '').trim(),
            apiKeyMasked: maskSecret(item.apiKey || item.apikey),
            enabled: item.enabled !== false,
          }),
        ),
      },
    },
  }
}

function mapAdminScheduledJobsConfig(config: JsonObject = {}) {
  const cloudtentaclesAccountMap = new Map(
    listAdminCloudtentaclesMonitorAccounts().map((item) => [item.sourceKey, item]),
  )

  return {
    enabled: config.enabled !== false,
    jobs: (Array.isArray(config.jobs) ? config.jobs : []).map((item) => ({
      id: String(item.id || '').trim(),
      type: String(item.type || '').trim(),
      enabled: item.enabled === true,
      intervalSeconds: Number(item.intervalSeconds || 300),
      cooldownSeconds: Number(item.cooldownSeconds || 1800),
      config: {
        assetThreshold: normalizeNonNegativeNumber(item.config?.assetThreshold, 500),
        accounts: mapScheduledJobCloudtentaclesAccounts(
          item.config?.accounts,
          normalizeNonNegativeNumber(item.config?.assetThreshold, 500),
          cloudtentaclesAccountMap,
        ),
      },
    })),
  }
}

function listAdminCloudtentaclesMonitorAccounts() {
  const sourcesConfig = listCloudtentaclesSources()
  const sessionsConfig = getAllCloudtentaclesSessionStates()
  const sessions: Record<string, JsonObject> = sessionsConfig.sessions || {}

  return (Array.isArray(sourcesConfig.sources) ? sourcesConfig.sources : [])
    .map((source) => {
      const sourceKey = String(source.key || '').trim()
      const session = sessions[sourceKey] || {}
      const label = String(source.label || source.username || sourceKey).trim() || sourceKey

      return {
        sourceKey,
        label,
        enabled: source.enabled !== false,
        username: String(source.username || '').trim(),
        phoneMasked: maskPhone(source.phone || session.phone),
        hasToken: Boolean(String(session.token || '').trim()),
        loggedInAt: String(session.loggedInAt || '').trim(),
      }
    })
    .filter((item) => item.sourceKey)
}

function mapScheduledJobCloudtentaclesAccounts(
  rawAccounts: unknown,
  defaultAssetThreshold: number,
  cloudtentaclesAccountMap: Map<string, JsonObject>,
) {
  const accounts = Array.isArray(rawAccounts) ? rawAccounts : []
  const configuredMap = new Map(
    accounts
      .map((item) => {
        const source = isPlainObject(item) ? item : {}
        const sourceKey = String(source.sourceKey || source.key || '').trim()
        if (!sourceKey) {
          return null
        }

        const option = cloudtentaclesAccountMap.get(sourceKey) || {}
        return [
          sourceKey,
          {
            sourceKey,
            label: String(source.label || option.label || sourceKey).trim(),
            enabled: source.enabled !== false,
            assetThreshold: normalizeNonNegativeNumber(
              source.assetThreshold ?? source.threshold,
              defaultAssetThreshold,
            ),
          },
        ] as const
      })
      .filter(Boolean) as Array<
      readonly [
        string,
        {
          sourceKey: string
          label: string
          enabled: boolean
          assetThreshold: number
        },
      ]
    >,
  )

  // 读配置时合并全部 kuaishou-lewan 账号，避免前端/任务只看到历史 default。
  const merged = Array.from(cloudtentaclesAccountMap.values())
    .map((option) => {
      const sourceKey = String(option.sourceKey || '').trim()
      const configured = configuredMap.get(sourceKey)
      return {
        sourceKey,
        label: String(configured?.label || option.label || sourceKey).trim(),
        enabled: configured ? configured.enabled !== false : option.enabled !== false,
        assetThreshold: normalizeNonNegativeNumber(
          configured?.assetThreshold,
          defaultAssetThreshold,
        ),
      }
    })
    .filter((item) => item.sourceKey)

  const mergedKeys = new Set(merged.map((item) => item.sourceKey))
  for (const [sourceKey, configured] of configuredMap.entries()) {
    if (mergedKeys.has(sourceKey)) {
      continue
    }
    merged.push(configured)
  }

  return merged
}

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

function isPlainObject(value: unknown): value is JsonObject {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
}
