import assert from 'node:assert/strict'
import test from 'node:test'
import { Readable } from 'node:stream'

import {
  manifestKeyFor,
  parseBackupArgs,
  pickLatestDumpKey,
  resolveBackupStorageConfig,
  runDownload,
  runLatest,
  runList,
  runUpload,
} from './db-backup.js'
import type { StorageObjectSummary } from './services/file-storage/object-storage.js'

test('resolveBackupStorageConfig 优先 DB_BACKUP_OSS_* 并按字段回退 STORAGE_OSS_*', () => {
  const config = resolveBackupStorageConfig({
    DB_BACKUP_OSS_ENDPOINT: 'https://backup.example.com',
    STORAGE_OSS_ENDPOINT: 'https://storage.example.com',
    STORAGE_OSS_BUCKET: 'order-site',
    STORAGE_OSS_ACCESS_KEY_ID: 'storage-key',
    DB_BACKUP_OSS_ACCESS_KEY_ID: 'backup-key',
    STORAGE_OSS_SECRET_ACCESS_KEY: 'storage-secret',
  })

  assert.equal(config.endpoint, 'https://backup.example.com')
  assert.equal(config.bucket, 'order-site')
  assert.equal(config.accessKeyId, 'backup-key')
  assert.equal(config.secretAccessKey, 'storage-secret')
  assert.equal(config.region, 'oss-cn-hangzhou')
})

test('resolveBackupStorageConfig 全部未配置时返回空值由调用方校验', () => {
  const config = resolveBackupStorageConfig({})
  assert.equal(config.endpoint, '')
  assert.equal(config.bucket, '')
})

test('parseBackupArgs 解析命令与参数并去掉前缀尾部斜杠', () => {
  const args = parseBackupArgs([
    'upload',
    '--key',
    'backups/postgres/order_site-20260824-030000.dump',
    '--prefix',
    'backups/postgres/',
    '--kind',
    'app-configs',
    '--size',
    '1234',
  ])

  assert.equal(args.command, 'upload')
  assert.equal(args.key, 'backups/postgres/order_site-20260824-030000.dump')
  assert.equal(args.prefix, 'backups/postgres')
  assert.equal(args.kind, 'app-configs')
  assert.equal(args.size, 1234)
})

test('parseBackupArgs 无参数时使用默认前缀与类型', () => {
  const args = parseBackupArgs(['list'])
  assert.equal(args.command, 'list')
  assert.equal(args.prefix, 'backups/postgres')
  assert.equal(args.kind, 'postgres-dump')
  assert.equal(args.key, '')
  assert.equal(args.allowUnverified, false)
})

test('parseBackupArgs 支持显式兼容未校验备份', () => {
  assert.equal(parseBackupArgs(['latest', '--allow-unverified']).allowUnverified, true)
})

test('manifestKeyFor 在备份 key 后追加清单后缀', () => {
  assert.equal(manifestKeyFor('backups/postgres/a.dump'), 'backups/postgres/a.dump.manifest.json')
})

test('pickLatestDumpKey 只认 dump 并取最近修改的对象', () => {
  const key = pickLatestDumpKey([
    {
      key: 'backups/postgres/a.dump',
      size: 1,
      etag: '',
      lastModified: new Date('2026-08-01T00:00:00Z'),
    },
    {
      key: 'backups/postgres/a.dump.manifest.json',
      size: 1,
      etag: '',
      lastModified: new Date('2026-08-23T00:00:00Z'),
    },
    {
      key: 'backups/configs/a.tar.gz',
      size: 1,
      etag: '',
      lastModified: new Date('2026-08-23T00:00:00Z'),
    },
    {
      key: 'backups/postgres/b.dump',
      size: 1,
      etag: '',
      lastModified: new Date('2026-08-22T00:00:00Z'),
    },
  ])

  assert.equal(key, 'backups/postgres/b.dump')
})

test('pickLatestDumpKey 无备份时返回 null,无时间时按 key 兜底', () => {
  assert.equal(pickLatestDumpKey([]), null)
  assert.equal(
    pickLatestDumpKey([
      { key: 'backups/postgres/order_site-1.dump', size: 1, etag: '' },
      { key: 'backups/postgres/order_site-2.dump', size: 1, etag: '' },
    ]),
    'backups/postgres/order_site-2.dump',
  )
})

test('runUpload 支持流式输入并生成带长度和 sha256 的 manifest', async () => {
  const uploads: Array<{ key: string; content: Buffer; contentLength?: number }> = []
  const storage = {
    putObject: async (input: {
      key: string
      content: Buffer | Readable
      contentLength?: number
    }) => {
      const chunks: Buffer[] = []
      if (Buffer.isBuffer(input.content)) {
        chunks.push(input.content)
      } else {
        for await (const chunk of input.content) chunks.push(Buffer.from(chunk))
      }
      uploads.push({
        key: input.key,
        content: Buffer.concat(chunks),
        contentLength: input.contentLength,
      })
    },
  } as never

  await runUpload(
    storage,
    parseBackupArgs([
      'upload',
      '--key',
      'backups/configs/a.tar.gz',
      '--kind',
      'app-configs',
      '--size',
      '5',
    ]),
    Readable.from([Buffer.from('hello')]),
  )

  assert.equal(uploads.length, 2)
  assert.equal(uploads[0]?.content.toString(), 'hello')
  assert.equal(uploads[0]?.contentLength, 5)
  assert.match(uploads[1]?.content.toString() || '', /"size": 5/)
  assert.match(uploads[1]?.content.toString() || '', /sha256/)
})

test('runLatest 跳过没有 manifest 的新对象并选择最近的有效备份', async () => {
  const objects: StorageObjectSummary[] = [
    {
      key: 'backups/postgres/new.dump',
      size: 5,
      etag: '',
      lastModified: new Date('2026-08-23T03:00:00Z'),
    },
    {
      key: 'backups/postgres/valid.dump',
      size: 5,
      etag: '',
      lastModified: new Date('2026-08-22T03:00:00Z'),
    },
  ]
  const storage = {
    listObjects: async () => objects,
    getObject: async (key: string) => {
      if (key.endsWith('new.dump.manifest.json')) {
        const error = Object.assign(new Error('missing'), { name: 'NoSuchKey' })
        throw error
      }
      return {
        reader: Readable.from([
          JSON.stringify({
            key: 'backups/postgres/valid.dump',
            kind: 'postgres-dump',
            size: 5,
            sha256: 'a'.repeat(64),
            createdAt: '2026-08-22T03:00:00Z',
          }),
        ]),
      }
    },
  } as never

  assert.equal(
    await runLatest(storage, parseBackupArgs(['latest', '--prefix', 'backups/postgres'])),
    'backups/postgres/valid.dump',
  )
})
