import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between } from 'typeorm';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { RoomCalendarLog } from '@/entities/room-calendar-log.entity';
import { Room } from '@/entities/room.entity';
import {
  QueryCalendarDto,
  BatchUpdateCalendarDto,
  SingleDayUpdateDto,
} from './dto/room-calendar.dto';

@Injectable()
export class MerchantRoomCalendarService {
  constructor(
    @InjectRepository(RoomCalendar)
    private calendarRepo: Repository<RoomCalendar>,
    @InjectRepository(RoomCalendarLog)
    private logRepo: Repository<RoomCalendarLog>,
    @InjectRepository(Room)
    private roomRepo: Repository<Room>,
  ) {}

  async getCalendar(roomId: number, query: QueryCalendarDto) {
    const safeRoomId = Number(roomId);
    const room = await this.roomRepo.findOne({ where: { id: safeRoomId } });
    const basePrice = room ? Number(room.price) : 0;

    const records = await this.calendarRepo.find({
      where: {
        roomId: safeRoomId,
        date: Between(query.startDate, query.endDate),
      },
      order: { date: 'ASC' },
    });

    const recordMap = new Map(records.map((r) => [r.date, r]));

    const days = this.getDateRange(query.startDate, query.endDate);
    return days.map((date) => {
      const rec = recordMap.get(date);
      return {
        date,
        price: rec ? Number(rec.price) : basePrice,
        stock: rec ? rec.stock : 0,
        sold: rec ? rec.sold : 0,
        status: rec ? rec.status : 'available',
        initialized: !!rec,
      };
    });
  }

  async batchUpdate(dto: BatchUpdateCalendarDto, operatorId: number) {
    const safeRoomId = Number(dto.roomId);
    const safeOperatorId = Number(operatorId);
    const days = this.getDateRange(dto.startDate, dto.endDate);

    for (const date of days) {
      const existing = await this.calendarRepo.findOne({
        where: { roomId: safeRoomId, date },
      });

      if (existing) {
        const update: Partial<RoomCalendar> = {};
        if (dto.price !== undefined) update.price = dto.price;
        if (dto.stock !== undefined) update.stock = dto.stock;
        if (dto.status !== undefined) update.status = dto.status;
        await this.calendarRepo.update(existing.id, update);
      } else {
        await this.calendarRepo.save(
          this.calendarRepo.create({
            roomId: safeRoomId,
            date,
            price: dto.price ?? 0,
            stock: dto.stock ?? 0,
            sold: 0,
            status: dto.status ?? 'available',
          }),
        );
      }
    }

    // 记录变更日志
    const changes: string[] = [];
    if (dto.price !== undefined) changes.push('price');
    if (dto.stock !== undefined) changes.push('stock');
    if (dto.status !== undefined) changes.push('status');

    for (const changeType of changes) {
      await this.logRepo.save(
        this.logRepo.create({
          roomId: safeRoomId,
          operatorId: safeOperatorId,
          dateRange: `${dto.startDate}~${dto.endDate}`,
          changeType: changeType as any,
          newValue: String(dto[changeType]),
        }),
      );
    }

    return { message: '批量更新成功', days: days.length };
  }

  async singleDayUpdate(dto: SingleDayUpdateDto, operatorId: number) {
    const safeRoomId = Number(dto.roomId);
    const safeOperatorId = Number(operatorId);

    const existing = await this.calendarRepo.findOne({
      where: { roomId: safeRoomId, date: dto.date },
    });

    if (existing) {
      const update: Partial<RoomCalendar> = {};
      if (dto.price !== undefined) update.price = dto.price;
      if (dto.stock !== undefined) update.stock = dto.stock;
      if (dto.status !== undefined) update.status = dto.status;
      await this.calendarRepo.update(existing.id, update);
    } else {
      const room = await this.roomRepo.findOne({ where: { id: safeRoomId } });
      await this.calendarRepo.save(
        this.calendarRepo.create({
          roomId: safeRoomId,
          date: dto.date,
          price: dto.price ?? (room ? Number(room.price) : 0),
          stock: dto.stock ?? 0,
          sold: 0,
          status: dto.status ?? 'available',
        }),
      );
    }

    // 记录变更日志
    const changes: { type: 'price' | 'stock' | 'status'; val: any }[] = [];
    if (dto.price !== undefined)
      changes.push({ type: 'price', val: dto.price });
    if (dto.stock !== undefined)
      changes.push({ type: 'stock', val: dto.stock });
    if (dto.status !== undefined)
      changes.push({ type: 'status', val: dto.status });

    for (const c of changes) {
      await this.logRepo.save(
        this.logRepo.create({
          roomId: safeRoomId,
          operatorId: safeOperatorId,
          dateRange: dto.date,
          changeType: c.type,
          newValue: String(c.val),
        }),
      );
    }

    return { message: '更新成功' };
  }

  private getDateRange(start: string, end: string): string[] {
    const days: string[] = [];
    const current = new Date(start);
    const endDate = new Date(end);
    while (current <= endDate) {
      days.push(current.toISOString().slice(0, 10));
      current.setDate(current.getDate() + 1);
    }
    return days;
  }
}
