import { createRequire } from 'node:module'

import { runtimeConfig } from '../../config/runtime.js'
import { createHttpError } from '../../utils/http.js'
import { logWarn } from '../../utils/logger.js'

const require = createRequire(import.meta.url)
const Dysmsapi = require('@alicloud/dysmsapi20170525') as {
  default: new (config: unknown) => AliyunSmsClient
  SendSmsRequest: new (input: Record<string, unknown>) => unknown
}
const OpenApiClient = require('@alicloud/openapi-client') as {
  Config: new (config: Record<string, unknown>) => unknown
}

type AliyunSmsClient = {
  sendSmsWithOptions(
    request: unknown,
    runtime: unknown,
  ): Promise<{ body?: { code?: string; message?: string } }>
}

export interface SmsProvider {
  sendCode(phone: string, code: string): Promise<void>
}

const ALIYUN_DEFAULT_ENDPOINT = 'dysmsapi.aliyuncs.com'

export function getSmsProvider(): SmsProvider {
  const config = runtimeConfig.worker.sms
  if (String(config.provider || '').trim() === 'aliyun') {
    const accessKeyId = String(config.accessKeyId || '').trim()
    const accessKeySecret = String(config.accessKeySecret || '').trim()
    const signName = String(config.signName || '').trim()
    const templateCode = String(config.templateCode || '').trim()
    if (!accessKeyId || !accessKeySecret || !signName || !templateCode) {
      logWarn('[sms]', '阿里云短信配置不完整，已降级为 Mock 模式', {
        hasAccessKeyId: Boolean(accessKeyId),
        hasAccessKeySecret: Boolean(accessKeySecret),
        hasSignName: Boolean(signName),
        hasTemplateCode: Boolean(templateCode),
      })
      return new MockSmsProvider()
    }
    return new AliyunSmsProvider({ accessKeyId, accessKeySecret, signName, templateCode })
  }
  return new MockSmsProvider()
}

export class MockSmsProvider implements SmsProvider {
  async sendCode(phone: string, code: string) {
    logWarn('[sms/mock]', `【开发模式】手机验证码：${phone} → ${code}`, {
      phone,
      code,
      hint: '生产环境请配置 WORKER_SMS_PROVIDER=aliyun 后使用真实短信',
    })
  }
}

export class AliyunSmsProvider implements SmsProvider {
  private readonly client: AliyunSmsClient
  private readonly signName: string
  private readonly templateCode: string

  constructor(input: {
    accessKeyId: string
    accessKeySecret: string
    signName: string
    templateCode: string
    endpoint?: string
  }) {
    const Config = OpenApiClient.Config
    this.client = new Dysmsapi.default(
      new Config({
        accessKeyId: input.accessKeyId,
        accessKeySecret: input.accessKeySecret,
        endpoint: (input.endpoint || ALIYUN_DEFAULT_ENDPOINT).replace(/^https?:\/\//, ''),
      }),
    ) as AliyunSmsClient
    this.signName = input.signName
    this.templateCode = input.templateCode
  }

  async sendCode(phone: string, code: string) {
    try {
      const request = new Dysmsapi.SendSmsRequest({
        phoneNumbers: phone,
        signName: this.signName,
        templateCode: this.templateCode,
        templateParam: JSON.stringify({ code }),
      })
      const response = await this.client.sendSmsWithOptions(request, {})
      const resultCode = String(response?.body?.code || '')
      if (resultCode !== 'OK') {
        throw createHttpError(
          `短信发送失败：${String(response?.body?.message || resultCode || '未知错误').trim()}`,
          {
            statusCode: 502,
            errorCode: 'worker_sms_send_failed',
          },
        )
      }
    } catch (error) {
      if (error instanceof Error && 'errorCode' in error) {
        throw error
      }
      throw createHttpError(
        `短信发送失败：${error instanceof Error ? error.message : '未知错误'}`,
        {
          statusCode: 502,
          errorCode: 'worker_sms_send_failed',
        },
      )
    }
  }
}
