import { Injectable, NotFoundException, BadRequestException, ForbiddenException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between } from 'typeorm';
import { Order } from '@/entities/order.entity';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { Review } from '@/entities/review.entity';
import { CreateOrderDto, QueryOrderDto } from './dto/order.dto';
import { ActivityService } from '@/modules/app/activity/activity.service';
import { ConfigService } from '@/modules/shared/config/config.service';
import { RefundService } from '@/modules/shared/finance/refund.service';
import { AccountService } from '@/modules/shared/finance/account.service';
import { CouponService } from '@/modules/app/coupon/coupon.service';

@Injectable()
export class OrderService {
  constructor(
    @InjectRepository(Order)
    private orderRepo: Repository<Order>,
    @InjectRepository(Room)
    private roomRepo: Repository<Room>,
    @InjectRepository(RoomCalendar)
    private calendarRepo: Repository<RoomCalendar>,
    @InjectRepository(Review)
    private reviewRepo: Repository<Review>,
    private readonly activityService: ActivityService,
    private readonly configService: ConfigService,
    private readonly refundService: RefundService,
    private readonly accountService: AccountService,
    private readonly couponService: CouponService,
  ) {}

  /**
   * 用户创建订单
   */
  async create(userId: number, dto: CreateOrderDto) {
    const room = await this.roomRepo.findOne({ where: { id: dto.roomId, status: 'on_sale' } });
    if (!room) throw new NotFoundException('房源不存在或已下架');

    const checkIn = new Date(dto.checkInDate);
    const checkOut = new Date(dto.checkOutDate);
    if (checkIn >= checkOut) throw new BadRequestException('离店日期必须大于入住日期');

    const nights = Math.ceil((checkOut.getTime() - checkIn.getTime()) / (1000 * 60 * 60 * 24));
    if (nights < 1) throw new BadRequestException('至少入住一晚');

    // 获取入住期间每天的房价和库存
    const dates: string[] = [];
    for (let i = 0; i < nights; i++) {
      const date = new Date(checkIn);
      date.setDate(date.getDate() + i);
      dates.push(date.toISOString().split('T')[0]);
    }

    const calendars = await this.calendarRepo.find({
      where: { roomId: dto.roomId, date: Between(dates[0], dates[dates.length - 1]) },
    });

    // 检查每天的库存和房态
    const roomCount = dto.roomCount || 1;
    let totalRoomPrice = 0;

    for (const date of dates) {
      const calendar = calendars.find(c => c.date === date);

      if (!calendar) {
        throw new BadRequestException(`${date} 未设置房价和库存`);
      }

      if (calendar.status === 'unavailable') {
        throw new BadRequestException(`${date} 房间不可售`);
      }

      const availableStock = calendar.stock - calendar.sold;
      if (availableStock < roomCount) {
        throw new BadRequestException(`${date} 库存不足，仅剩 ${availableStock} 间`);
      }

      // 累加每天的房价
      totalRoomPrice += Number(calendar.price);
    }

    const roomAmount = totalRoomPrice * roomCount;

    // 处理优惠券
    let couponDiscount = 0;
    let userCouponId: number | null = null;

    if (dto.couponId) {
      // 查询用户可用优惠券
      const availableCoupons = await this.couponService.findAvailableCoupons(
        userId,
        roomAmount,
        room.merchantId,
        dto.roomId,
      );

      const userCoupon = availableCoupons.find(uc => uc.coupon.id === dto.couponId);

      if (!userCoupon) {
        throw new BadRequestException('优惠券不可用');
      }

      // 计算优惠金额（基于房费）
      couponDiscount = this.couponService.calculateDiscount(userCoupon.coupon, roomAmount);
      userCouponId = userCoupon.id;
    }

    // 订单总额 = 房费
    const totalAmount = roomAmount;
    // 用户实付 = 房费 - 优惠券
    const payAmount = totalAmount - couponDiscount;

    // 计算平台服务费（基于用户实付金额）
    const serviceFeeRate = await this.configService.getServiceFeeRate();
    const serviceFee = Math.round(payAmount * serviceFeeRate * 100) / 100;

    // 商家收入 = 用户实付 - 服务费
    const merchantIncome = Math.round((payAmount - serviceFee) * 100) / 100;

    const now = new Date();
    const orderNo = [
      now.getFullYear(),
      String(now.getMonth() + 1).padStart(2, '0'),
      String(now.getDate()).padStart(2, '0'),
      String(now.getHours()).padStart(2, '0'),
      String(now.getMinutes()).padStart(2, '0'),
      String(now.getSeconds()).padStart(2, '0'),
      String(Math.floor(Math.random() * 1000000)).padStart(6, '0'),
    ].join('');

    const order = this.orderRepo.create({
      orderNo,
      userId,
      merchantId: room.merchantId,
      roomId: room.id,
      checkInDate: dto.checkInDate,
      checkOutDate: dto.checkOutDate,
      nights,
      roomCount,
      guestCount: dto.guestCount || 1,
      roomPrice: Math.round((totalRoomPrice / nights) * 100) / 100, // 使用平均房价
      roomAmount,
      serviceFee,
      merchantIncome,
      couponDiscount,
      userCouponId: userCouponId !== null ? userCouponId : undefined,
      totalAmount,
      payAmount,
      contactName: dto.contactName,
      contactPhone: dto.contactPhone,
      contactIdCard: dto.contactIdCard || undefined,
      remark: dto.remark || '',
      paymentMethod: dto.paymentMethod || null,
    });

    const savedOrder = await this.orderRepo.save(order);

    // 使用优惠券
    if (userCouponId) {
      await this.couponService.useCoupon(userCouponId, savedOrder.id);
    }

    // 扣减库存
    for (const date of dates) {
      await this.calendarRepo.increment(
        { roomId: dto.roomId, date },
        'sold',
        roomCount,
      );
    }

    return savedOrder;
  }

  /**
   * 用户查询自己的订单列表
   */
  async findByUser(userId: number, query: QueryOrderDto) {
    const { page = 1, pageSize = 10, status } = query;
    const qb = this.orderRepo.createQueryBuilder('o')
      .leftJoinAndSelect('o.room', 'r')
      .leftJoinAndSelect('o.merchant', 'm')
      .where('o.user_id = :userId', { userId });

    if (status) {
      qb.andWhere('o.status = :status', { status });
    }

    qb.orderBy('o.createdAt', 'DESC');
    qb.skip((page - 1) * pageSize).take(pageSize);

    const [list, total] = await qb.getManyAndCount();

    // 查询每个订单是否已评价
    const orderIds = list.map(order => order.id);
    const reviews = orderIds.length > 0
      ? await this.reviewRepo.find({
          where: orderIds.map(id => ({ orderId: id })),
          select: ['orderId'],
        })
      : [];

    const reviewedOrderIds = new Set(reviews.map(r => r.orderId));

    // 添加 hasReviewed 字段到每个订单
    const listWithReview = list.map(order => ({
      ...order,
      hasReviewed: reviewedOrderIds.has(order.id),
    }));

    return { list: listWithReview, total, page, pageSize, totalPages: Math.ceil(total / pageSize) };
  }

  /**
   * 用户查询订单详情（通过订单号）
   */
  async findByOrderNo(orderNo: string) {
    const order = await this.orderRepo.findOne({
      where: { orderNo },
      relations: ['room', 'merchant', 'user'],
    });
    if (!order) throw new NotFoundException('订单不存在');
    return order;
  }

  /**
   * 用户查询订单详情（通过ID，保留用于内部调用）
   */
  async findById(id: number) {
    const order = await this.orderRepo.findOne({
      where: { id },
      relations: ['room', 'merchant', 'user'],
    });
    if (!order) throw new NotFoundException('订单不存在');
    return order;
  }

  /**
   * 用户取消订单（通过订单号）
   */
  async cancelByOrderNo(userId: number, orderNo: string, reason: string) {
    const order = await this.findByOrderNo(orderNo);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (!['pending_pay', 'pending_confirm', 'pending_checkin'].includes(order.status)) {
      throw new BadRequestException('当前订单状态不可取消');
    }

    // 恢复房态库存（所有可取消的订单都需要恢复库存）
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      await this.calendarRepo.decrement(
        { roomId: order.roomId, date: dateStr },
        'sold',
        order.roomCount,
      );
    }

    // 已支付的订单（pending_confirm、pending_checkin）取消时需退款
    const needRefund = order.status !== 'pending_pay';

    await this.orderRepo.update(order.id, {
      status: 'cancelled',
      cancelReason: reason,
      cancelledAt: new Date(),
      ...(needRefund ? {
        refundAmount: order.payAmount,
        refundAt: new Date(),
      } : {}),
    });
    return { message: needRefund ? '订单已取消，退款将原路返回' : '订单已取消' };
  }

  /**
   * 用户取消订单（通过ID，保留用于内部调用）
   */
  async cancel(userId: number, id: number, reason: string) {
    const order = await this.findById(id);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (!['pending_pay', 'pending_confirm', 'pending_checkin'].includes(order.status)) {
      throw new BadRequestException('当前订单状态不可取消');
    }

    // 恢复房态库存（所有可取消的订单都需要恢复库存）
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      await this.calendarRepo.decrement(
        { roomId: order.roomId, date: dateStr },
        'sold',
        order.roomCount,
      );
    }

    // 已支付的订单（pending_confirm、pending_checkin）取消时需退款
    const needRefund = order.status !== 'pending_pay';

    await this.orderRepo.update(id, {
      status: 'cancelled',
      cancelReason: reason,
      cancelledAt: new Date(),
      ...(needRefund ? {
        refundAmount: order.payAmount,
        refundAt: new Date(),
      } : {}),
    });
    return { message: needRefund ? '订单已取消，退款将原路返回' : '订单已取消' };
  }

  /**
   * 用户支付订单（通过订单号）
   */
  async payByOrderNo(userId: number, orderNo: string, paymentMethod: 'wechat' | 'alipay' | 'balance') {
    const order = await this.findByOrderNo(orderNo);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (order.status !== 'pending_pay') {
      throw new BadRequestException('当前订单状态不可支付');
    }

    // 模拟支付成功
    const paymentNo = `PAY${Date.now()}${Math.floor(Math.random() * 10000)}`;
    await this.orderRepo.update(order.id, {
      status: 'pending_confirm',
      paymentMethod,
      paymentNo,
      paidAt: new Date(),
    });

    // 记录平台账户收入
    const transactionNo = `TXN${Date.now()}${Math.floor(Math.random() * 10000)}`;
    await this.accountService.addPlatformBalance(
      order.payAmount,
      order.serviceFee || 0,
      transactionNo,
      'order_payment',
      order.id,
      order.orderNo,
      `用户支付订单：${order.orderNo}`,
    );

    // 扣减房态库存
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      const calendar = await this.calendarRepo.findOne({
        where: { roomId: order.roomId, date: dateStr },
      });
      if (calendar) {
        await this.calendarRepo.update(calendar.id, {
          sold: calendar.sold + order.roomCount,
        });
      }
    }

    return { message: '支付成功', paymentNo };
  }

  /**
   * 用户支付订单（通过ID，保留用于内部调用）
   */
  async pay(userId: number, id: number, paymentMethod: 'wechat' | 'alipay' | 'balance') {
    const order = await this.findById(id);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (order.status !== 'pending_pay') {
      throw new BadRequestException('当前订单状态不可支付');
    }

    // 模拟支付成功
    const paymentNo = `PAY${Date.now()}${Math.floor(Math.random() * 10000)}`;
    await this.orderRepo.update(id, {
      status: 'pending_confirm',
      paymentMethod,
      paymentNo,
      paidAt: new Date(),
    });

    // 记录平台账户收入
    const transactionNo = `TXN${Date.now()}${Math.floor(Math.random() * 10000)}`;
    await this.accountService.addPlatformBalance(
      order.payAmount,
      order.serviceFee || 0,
      transactionNo,
      'order_payment',
      order.id,
      order.orderNo,
      `用户支付订单：${order.orderNo}`,
    );

    // 扣减房态库存
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      const calendar = await this.calendarRepo.findOne({
        where: { roomId: order.roomId, date: dateStr },
      });
      if (calendar) {
        await this.calendarRepo.update(calendar.id, {
          sold: calendar.sold + order.roomCount,
        });
      }
    }

    return { message: '支付成功', paymentNo };
  }

  /**
   * 用户申请退款（通过订单号）
   */
  async refundByOrderNo(userId: number, orderNo: string, reason: string) {
    const order = await this.findByOrderNo(orderNo);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (!['pending_confirm', 'pending_checkin'].includes(order.status)) {
      throw new BadRequestException('当前订单状态不可申请退款');
    }

    // 恢复房态库存
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      const calendar = await this.calendarRepo.findOne({
        where: { roomId: order.roomId, date: dateStr },
      });
      if (calendar) {
        await this.calendarRepo.update(calendar.id, {
          sold: Math.max(0, calendar.sold - order.roomCount),
        });
      }
    }

    // 调用 RefundService 处理财务退款
    try {
      await this.refundService.processRefund(order, reason);
      return { message: '退款成功，款项将原路返回' };
    } catch (error) {
      // 退款失败，恢复订单状态（库存已恢复，需要手动回滚）
      throw new BadRequestException(`退款失败: ${error.message}`);
    }
  }

  /**
   * 用户申请退款（通过ID，保留用于内部调用）
   */
  async refund(userId: number, id: number, reason: string) {
    const order = await this.findById(id);
    if (order.userId !== userId) throw new ForbiddenException('无权操作此订单');
    if (!['pending_confirm', 'pending_checkin'].includes(order.status)) {
      throw new BadRequestException('当前订单状态不可申请退款');
    }

    // 恢复房态库存
    const checkIn = new Date(order.checkInDate);
    const checkOut = new Date(order.checkOutDate);
    for (let d = new Date(checkIn); d < checkOut; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      const calendar = await this.calendarRepo.findOne({
        where: { roomId: order.roomId, date: dateStr },
      });
      if (calendar) {
        await this.calendarRepo.update(calendar.id, {
          sold: Math.max(0, calendar.sold - order.roomCount),
        });
      }
    }

    // 调用 RefundService 处理财务退款
    try {
      await this.refundService.processRefund(order, reason);
      return { message: '退款成功，款项将原路返回' };
    } catch (error) {
      // 退款失败，恢复订单状态（库存已恢复，需要手动回滚）
      throw new BadRequestException(`退款失败: ${error.message}`);
    }
  }
}
