import { createHttpError } from '../../../utils/http.js'
import { logInfo } from '../../../utils/logger.js'
import { encryptCloudtentaclesPayload, md5CloudtentaclesPassword } from './crypto-service.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
import type { JsonObject } from '../../../types/json.js'

export async function sendCloudtentaclesSmsCode(payload: JsonObject = {}) {
  const username = String(payload.username || '').trim()
  const phone = String(payload.phone || '').trim()

  if (!username) {
    throw createHttpError('cloudtentacles 缺少账号', {
      statusCode: 400,
      errorCode: 'cloudtentacles_missing_username',
    })
  }

  if (!phone) {
    throw createHttpError('cloudtentacles 缺少手机号', {
      statusCode: 400,
      errorCode: 'cloudtentacles_missing_phone',
    })
  }

  const config = resolveCloudtentaclesConfig(payload)
  const encrypted = encryptCloudtentaclesPayload(
    {
      account: username,
      phone,
    },
    config,
  )

  const result = await cloudtentaclesRequest(config.sendSmsPath, {
    ...config,
    method: 'POST',
    body: {
      covert: encrypted.covert,
      t: encrypted.t,
      r: encrypted.r,
    },
    businessErrorStatusCode: 400,
    businessErrorCode: 'cloudtentacles_send_sms_failed',
  })

  logInfo('[cloudtentacles/session]', '短信验证码发送成功', {
    username,
    phone: maskPhone(phone),
  })

  return {
    baseUrl: config.baseUrl,
    username,
    phone,
    sentAt: new Date().toISOString(),
    responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
  }
}

export async function loginCloudtentaclesSession(payload: JsonObject = {}) {
  const username = String(payload.username || '').trim()
  const password = String(payload.password || '').trim()
  const phone = String(payload.phone || '').trim()
  const code = String(payload.code || '').trim()

  if (!username) {
    throw createHttpError('cloudtentacles 登录缺少账号', {
      statusCode: 400,
      errorCode: 'cloudtentacles_login_missing_username',
    })
  }

  if (!password) {
    throw createHttpError('cloudtentacles 登录缺少密码', {
      statusCode: 400,
      errorCode: 'cloudtentacles_login_missing_password',
    })
  }

  if (!phone) {
    throw createHttpError('cloudtentacles 登录缺少手机号', {
      statusCode: 400,
      errorCode: 'cloudtentacles_login_missing_phone',
    })
  }

  if (!code) {
    throw createHttpError('cloudtentacles 登录缺少短信验证码', {
      statusCode: 400,
      errorCode: 'cloudtentacles_login_missing_code',
    })
  }

  const config = resolveCloudtentaclesConfig(payload)
  const encrypted = encryptCloudtentaclesPayload(
    {
      account: username,
      password: md5CloudtentaclesPassword(password),
      phone,
      code,
    },
    config,
  )

  const loginResult = await cloudtentaclesRequest(config.loginPath, {
    ...config,
    method: 'POST',
    body: {
      covert: encrypted.covert,
      t: encrypted.t,
      r: encrypted.r,
    },
    businessErrorStatusCode: 401,
    businessErrorCode: 'cloudtentacles_login_failed',
  })

  const token = String(loginResult.payload?.data || '').trim()
  if (!token) {
    throw createHttpError('cloudtentacles 登录成功但未返回 token', {
      statusCode: 502,
      errorCode: 'cloudtentacles_missing_token',
    })
  }

  const session = await validateCloudtentaclesSession({
    ...config,
    token,
  })

  return {
    ...session,
    username,
    phone,
    responseMessage: String(loginResult.payload?.message || loginResult.payload?.msg || 'success'),
  }
}

export async function validateCloudtentaclesSession(payload: JsonObject = {}) {
  const token = String(payload.token || '').trim()

  if (!token) {
    throw createHttpError('cloudtentacles 会话校验缺少 token', {
      statusCode: 400,
      errorCode: 'cloudtentacles_validate_missing_token',
    })
  }

  const config = resolveCloudtentaclesConfig(payload)
  const [userInfoResult, assetResult, permissionResult] = await Promise.all([
    cloudtentaclesRequest(config.userInfoPath, {
      ...config,
      method: 'POST',
      token,
      body: {},
      businessErrorStatusCode: 401,
      businessErrorCode: 'cloudtentacles_user_info_failed',
    }),
    cloudtentaclesRequest(config.assetPath, {
      ...config,
      method: 'GET',
      token,
      contentType: 'application/json',
      businessErrorStatusCode: 401,
      businessErrorCode: 'cloudtentacles_asset_failed',
    }),
    cloudtentaclesRequest(config.permissionPath, {
      ...config,
      method: 'GET',
      token,
      contentType: 'application/json',
      businessErrorStatusCode: 401,
      businessErrorCode: 'cloudtentacles_permission_failed',
    }),
  ])

  return {
    baseUrl: config.baseUrl,
    token,
    loggedInAt: new Date().toISOString(),
    userInfo: isPlainObject(userInfoResult.payload?.data) ? userInfoResult.payload.data : {},
    asset: Number(assetResult.payload?.data || 0),
    permissions: Array.isArray(permissionResult.payload?.data)
      ? permissionResult.payload.data
          .map((item: unknown) => String(item || '').trim())
          .filter(Boolean)
      : [],
  }
}

function maskPhone(phone: unknown) {
  const normalized = String(phone || '').trim()
  if (normalized.length < 7) {
    return normalized
  }

  return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`
}

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