import { Controller, Post, Get, Param, Body, UseGuards, HttpException, HttpStatus, Logger, Req, HttpCode } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'
import { User, UserDocument } from '../user/user.schema'
import { PaymentOrder, PaymentOrderDocument } from './payment-order.schema'
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'
import { CurrentUser } from '../../common/decorators/current-user.decorator'
import { WechatPayService } from './wechat-pay.service'
import { QuotaService } from '../user/quota.service'
import { PricingService } from '../schemas/pricing.service'
import { Public } from '../../common/decorators/public.decorator'
import { GravityTransaction } from '../schemas/gravity-transaction.schema'

@Controller('payment')
export class PaymentController {
  private readonly logger = new Logger(PaymentController.name)

  constructor(
    @InjectModel(User.name) private userModel: Model<UserDocument>,
    @InjectModel(PaymentOrder.name) private orderModel: Model<PaymentOrderDocument>,
    @InjectModel(GravityTransaction.name) private gravityTxModel: Model<GravityTransaction>,
    private wechatPay: WechatPayService,
    private quotaService: QuotaService,
    private pricingService: PricingService,
  ) {}

  /** 创建套餐订单（H5：Native 扫码支付） */
  @UseGuards(JwtAuthGuard)
  @Post('create')
  @HttpCode(200)
  async create(@CurrentUser('userId') userId: string, @Body('plan') plan: string = 'growth') {
    if (!['growth', 'sprint'].includes(plan)) throw new HttpException('无效套餐', HttpStatus.BAD_REQUEST)
    const user = await this.userModel.findById(userId).exec()
    if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
    if (user.plan !== 'free') throw new HttpException('已是会员', HttpStatus.BAD_REQUEST)

    const pricing = await this.pricingService.getConfig()
    const planCfg = pricing.plans[plan === 'sprint' ? 'sprint' : 'growth']
    const amount = planCfg.price
    const title = plan === 'sprint' ? '职引冲刺版月度会员' : '职引成长版月度会员'
    const outTradeNo = `${plan === 'sprint' ? 'SPR' : 'VIP'}${Date.now()}${userId.slice(-6)}`
    const result = await this.wechatPay.nativePay(title, outTradeNo, amount)

    await this.orderModel.create({ outTradeNo, userId, userPhone: user.phone || '', amount, title, status: 'pending', channel: 'native', type: 'membership', plan })

    return { outTradeNo, codeUrl: result.codeUrl, amount, title }
  }

  /** 创建按次购买订单 */
  @UseGuards(JwtAuthGuard)
  @Post('create-product')
  async createProduct(
    @CurrentUser('userId') userId: string,
    @Body('type') type: string,
    @Body('quantity') quantity: number = 1,
    @Body('metadata') metadata?: Record<string, any>,
  ) {
    if (!['interview', 'optimize', 'download'].includes(type)) {
      throw new HttpException('无效产品类型', HttpStatus.BAD_REQUEST)
    }
    const qty = Math.max(1, Math.min(99, quantity || 1))
    const user = await this.userModel.findById(userId).exec()
    if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)

    const pricing = await this.pricingService.getConfig()
    const priceMap: Record<string, number> = {
      interview: pricing.interview.pricePerSession,
      optimize: pricing.resumeOptimize.pricePerOptimize,
      download: pricing.resumeDownload.pricePerDownload,
    }
    const price = priceMap[type] * qty
    if (!priceMap[type]) throw new HttpException('价格未配置', HttpStatus.INTERNAL_SERVER_ERROR)

    const titles: Record<string, string> = {
      interview: 'AI 模拟面试单次',
      optimize: '简历优化单次',
      download: '简历下载',
    }
    const title = qty > 1 ? `${titles[type]}×${qty}` : titles[type]
    const outTradeNo = `${type.slice(0, 3).toUpperCase()}${Date.now()}${userId.slice(-6)}`
    const result = await this.wechatPay.nativePay(title, outTradeNo, price)

    await this.orderModel.create({ outTradeNo, userId, userPhone: user.phone || '', amount: price, title, status: 'pending', channel: 'native', type, plan: 'growth', metadata: { ...metadata, quantity: qty } })

    return { outTradeNo, codeUrl: result.codeUrl, amount: price, title, quantity: qty }
  }

  /** JSAPI 支付（微信小程序） */
  @UseGuards(JwtAuthGuard)
  @Post('jsapi')
  @HttpCode(200)
  async jsapi(@CurrentUser('userId') userId: string, @Body('plan') plan: string = 'growth') {
    this.logger.log(`[jsapi] userId=${userId}, plan=${plan}`)
    if (!['growth', 'sprint'].includes(plan)) throw new HttpException('无效套餐', HttpStatus.BAD_REQUEST)
    const user = await this.userModel.findById(userId).exec()
    if (!user) { this.logger.warn(`[jsapi] 用户不存在 userId=${userId}`); throw new HttpException('用户不存在', HttpStatus.NOT_FOUND) }
    this.logger.log(`[jsapi] 用户查询结果: plan=${user.plan}, wxOpenid=${user.wxOpenid ? '已设置' : '空'}, phone=${user.phone || '无'}`)
    if (user.plan !== 'free') { this.logger.warn(`[jsapi] 已是会员 plan=${user.plan}`); throw new HttpException('已是会员', HttpStatus.BAD_REQUEST) }
    const openid = user.wxOpenid
    if (!openid) {
      this.logger.warn(`[jsapi] 未绑定微信openid userId=${userId}`)
      throw new HttpException({ message: '未绑定微信openid', needBindWx: true }, HttpStatus.BAD_REQUEST)
    }

    const pricing = await this.pricingService.getConfig()
    this.logger.log(`[jsapi] pricing获取成功`)
    const planCfg = pricing.plans[plan === 'sprint' ? 'sprint' : 'growth']
    const amount = planCfg.price
    const title = plan === 'sprint' ? '职引冲刺版月度会员' : '职引成长版月度会员'
    const outTradeNo = `${plan === 'sprint' ? 'SPR' : 'VIP'}${Date.now()}${userId.slice(-6)}`
    this.logger.log(`[jsapi] 准备调用微信: outTradeNo=${outTradeNo}, amount=${amount}, openid=${openid}`)
    let result: any
    try {
      result = await this.wechatPay.jsapiPay(title, outTradeNo, amount, openid)
      this.logger.log(`[jsapi] 微信下单成功 prepayId=${result?.prepayId}`)
    } catch (e: any) {
      this.logger.error(`[jsapi] 微信下单失败: ${e.message}`, e.response?.data ? JSON.stringify(e.response.data) : '')
      throw new HttpException(e.response?.data?.message || '微信支付下单失败', HttpStatus.INTERNAL_SERVER_ERROR)
    }

    await this.orderModel.create({ outTradeNo, userId, userPhone: user.phone || '', amount, title, status: 'pending', channel: 'jsapi', type: 'membership', plan })

    return { ...result, outTradeNo }
  }

  /** JSAPI 按次购买 */
  @UseGuards(JwtAuthGuard)
  @Post('jsapi-product')
  async jsapiProduct(
    @CurrentUser('userId') userId: string,
    @Body('type') type: string,
    @Body('quantity') quantity: number = 1,
    @Body('metadata') metadata?: Record<string, any>,
  ) {
    if (!['interview', 'optimize', 'download'].includes(type)) {
      throw new HttpException('无效产品类型', HttpStatus.BAD_REQUEST)
    }
    const qty = Math.max(1, Math.min(99, quantity || 1))
    const user = await this.userModel.findById(userId).exec()
    if (!user) throw new HttpException('用户不存在', HttpStatus.NOT_FOUND)
    const openid = user.wxOpenid
    if (!openid) {
      throw new HttpException({ message: '未绑定微信openid', needBindWx: true }, HttpStatus.BAD_REQUEST)
    }

    const pricing = await this.pricingService.getConfig()
    const priceMap: Record<string, number> = {
      interview: pricing.interview.pricePerSession,
      optimize: pricing.resumeOptimize.pricePerOptimize,
      download: pricing.resumeDownload.pricePerDownload,
    }
    const price = priceMap[type] * qty
    if (!priceMap[type]) throw new HttpException('价格未配置', HttpStatus.INTERNAL_SERVER_ERROR)

    const titles: Record<string, string> = {
      interview: 'AI 模拟面试单次',
      optimize: '简历优化单次',
      download: '简历下载',
    }
    const title = qty > 1 ? `${titles[type]}×${qty}` : titles[type]
    const outTradeNo = `${type.slice(0, 3).toUpperCase()}${Date.now()}${userId.slice(-6)}`
    const result = await this.wechatPay.jsapiPay(title, outTradeNo, price, openid)

    await this.orderModel.create({ outTradeNo, userId, userPhone: user.phone || '', amount: price, title, status: 'pending', channel: 'jsapi', type, plan: 'growth', metadata: { ...metadata, quantity: qty } })

    return { ...result, outTradeNo, quantity: qty }
  }

  /** 支付回调通知 */
  @Public()
  @Post('notify')
  async notify(@Body() body: any, @Req() req: any) {
    try {
      const wechatSignature = req.headers['wechatpay-signature'] || ''
      const wechatTimestamp = req.headers['wechatpay-timestamp'] || ''
      const wechatNonce = req.headers['wechatpay-nonce'] || ''
      const decrypted = this.wechatPay.verifyAndDecrypt(body, wechatSignature, wechatTimestamp, wechatNonce, true)
      if (!decrypted) return { code: 'FAIL', message: '处理失败' }

      const outTradeNo = decrypted.out_trade_no
      const wxTransactionId = decrypted.transaction_id

      const order = await this.orderModel.findOne({ outTradeNo }).exec()
      if (!order) {
        this.logger.warn(`支付回调：订单不存在 ${outTradeNo}`)
        return { code: 'FAIL', message: '订单不存在' }
      }

      if (order.status === 'pending') {
        order.status = 'success'
        order.paidAt = new Date()
        order.wxTransactionId = wxTransactionId
        order.description = `${decrypted.trade_type || ''} 支付成功`
        await order.save()
      } else {
        return { code: 'SUCCESS', message: '已处理' }
      }

      if (order.type === 'membership') {
        await this.activateMembership(order)
      } else {
        await this.activateProduct(order)
      }
      return { code: 'SUCCESS', message: '成功' }
    } catch (e) {
      this.logger.error(`支付回调处理失败: ${e.message}`)
      return { code: 'FAIL', message: '处理失败' }
    }
  }

  private async activateMembership(order: PaymentOrderDocument) {
    const user = await this.userModel.findById(order.userId).exec()
    if (!user || user.plan !== 'free') return

    const pricing = await this.pricingService.getConfig()
    const planCfg = pricing.plans[order.plan === 'sprint' ? 'sprint' : 'growth']
    const expireAt = new Date()
    expireAt.setDate(expireAt.getDate() + planCfg.durationDays)
    const isSprint = order.plan === 'sprint'
    if (isSprint) {
      user.plan = 'sprint'
      user.sprintExpireAt = expireAt
      user.sprintRemaining = 10
    } else {
      user.plan = 'growth'
      user.vipExpireAt = expireAt
    }
    user.gravity = planCfg.gravityPerMonth
    user.freeOptimizeUsed = 3
    await user.save()
    await this.gravityTxModel.create({
      userId: order.userId,
      amount: planCfg.gravityPerMonth,
      balance: planCfg.gravityPerMonth,
      type: 'plan_set',
      description: `开通${isSprint ? '冲刺版' : '成长版'}会员，获得 ${planCfg.gravityPerMonth} 引力值`,
      refId: order.outTradeNo,
    })
  }

  private async activateProduct(order: PaymentOrderDocument) {
    const pricing = await this.pricingService.getConfig()
    const gravityMap: Record<string, number> = {
      interview: pricing.gravityRates.interviewPerUse,
      optimize: pricing.gravityRates.optimizePerUse,
      download: pricing.gravityRates.downloadPerUse,
    }
    const g = gravityMap[order.type]
    if (!g) return
    const quantity = order.metadata?.quantity || 1
    await this.quotaService.grantGravity(order.userId, g * quantity)
  }

  /** 查询订单（微信侧） */
  @UseGuards(JwtAuthGuard)
  @Post('query')
  async query(@Body('outTradeNo') outTradeNo: string, @CurrentUser('userId') userId: string) {
    const order = await this.orderModel.findOne({ outTradeNo, userId }).exec()
    if (!order) throw new HttpException('订单不存在', HttpStatus.NOT_FOUND)
    return this.wechatPay.queryOrder(outTradeNo)
  }

  /** 检查本地订单状态（前端轮询） */
  @UseGuards(JwtAuthGuard)
  @Get('check/:outTradeNo')
  async checkOrder(@Param('outTradeNo') outTradeNo: string, @CurrentUser('userId') userId: string) {
    const order = await this.orderModel.findOne({ outTradeNo, userId }).exec()
    if (!order) throw new HttpException('订单不存在', HttpStatus.NOT_FOUND)
    return { status: order.status, plan: order.plan, type: order.type }
  }

  /** 凭订单号激活（前端支付成功后调用，兜底） */
  @UseGuards(JwtAuthGuard)
  @Post('activate')
  async activate(@CurrentUser('userId') userId: string, @Body('outTradeNo') outTradeNo: string) {
    const order = await this.orderModel.findOne({ outTradeNo, userId }).exec()
    if (!order) throw new HttpException('订单不存在', HttpStatus.NOT_FOUND)
    if (order.status !== 'success') throw new HttpException('支付未完成', HttpStatus.BAD_REQUEST)

    if (order.type === 'membership') {
      await this.activateMembership(order)
      return { success: true, plan: order.plan }
    }

    // For product orders, check if already activated via callback
    const user = await this.userModel.findById(userId).exec()
    if (user && order.type === 'interview' && (user.interviewCredits || 0) > 0) {
      return { success: true, type: order.type, alreadyActivated: true }
    }
    if (user && order.type === 'optimize' && (user.resumeOptimizeCredits || 0) > 0) {
      return { success: true, type: order.type, alreadyActivated: true }
    }

    await this.activateProduct(order)
    return { success: true, type: order.type }
  }
}
