// timeline/timeline.service.ts
import {
  Injectable,
  NotFoundException,
  ForbiddenException,
  BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { Timeline } from '@/entities/timeline.entity';
import { Trip } from '@/entities/trip.entity';
import { NotificationHelper } from '@/helpers/notification.helper';
import { NotificationService } from '@/notification/notification.service';
import { buildScheduledAt } from '@/common/helpers';

@Injectable()
export class TimelineService {
  constructor(
    @InjectRepository(Timeline)
    private timelineRepo: Repository<Timeline>,

    @InjectRepository(Trip)
    private tripRepo: Repository<Trip>,

    private notificationService: NotificationService,
  ) {}

  // =============================
  // CREATE
  // =============================
  async create(userId: string, dto: any) {
    const trip = await this.tripRepo.findOne({
      where: { id: dto.tripId },
      relations: ['group', 'group.members', 'group.members.user'],
    });

    if (!trip) throw new NotFoundException('Trip not found');

    const scheduledAt = buildScheduledAt(trip.startDate, dto.day, dto.time);

    const timeline = this.timelineRepo.create({
      ...dto,
      trip,
      createdBy: { id: userId },
      scheduledAt,
    } as Partial<Timeline>);

    const savedTimeline = await this.timelineRepo.save(timeline);

    if (trip.group) {
      const payload: any[] = [];

      trip.group.members.forEach((m) => {
        if (m.user.id !== userId) {
          const notification = NotificationHelper.newTimeline({
            timeline: savedTimeline,
            trip,
            group: trip.group,
            user: m.user,
            createdBy: userId,
          });
          payload.push(notification);
        }
      });

      await this.notificationService.createManyAndPush(trip.group.id, payload);
    }

    return savedTimeline;
  }

  // =============================
  // BULK CREATE (for AI)
  // =============================
  async createBulk(userId: string, tripId: string, timelines: any[]) {
    if (!timelines || timelines.length === 0) {
      throw new BadRequestException('No timelines to create');
    }

    const trip = await this.tripRepo.findOne({
      where: { id: tripId },
      relations: ['group', 'group.members', 'group.members.user'],
    });

    if (!trip) throw new NotFoundException('Trip not found');

    // Check if user is leader
    // if (trip.leaderId !== userId) {
    //   throw new ForbiddenException('Only leader can create timelines');
    // }

    const createdTimelines : any = [];

    for (const item of timelines) {
      const scheduledAt = buildScheduledAt(trip.startDate, item.day, item.time);

      const timeline = this.timelineRepo.create({
        ...item,
        trip,
        createdBy: { id: userId },
        scheduledAt,
      } as Partial<Timeline>);

      const savedTimeline = await this.timelineRepo.save(timeline);
      createdTimelines.push(savedTimeline);
    }

    // Send notifications for the first timeline
    if (trip.group && createdTimelines.length > 0) {
      const payload: any[] = [];

      trip.group.members.forEach((m) => {
        if (m.user.id !== userId) {
          const notification = NotificationHelper.newTimeline({
            timeline: createdTimelines[0],
            trip,
            group: trip.group,
            user: m.user,
            createdBy: userId,
          });
          payload.push(notification);
        }
      });

      await this.notificationService.createManyAndPush(trip.group.id, payload);
    }

    return createdTimelines;
  }

  // =============================
  // UPDATE
  // =============================
  async update(id: string, userId: string, dto: any) {
    const timeline = await this.timelineRepo.findOne({
      where: { id },
      relations: ['createdBy', 'trip'],
    });

    if (!timeline) throw new NotFoundException('Timeline not found');

    // 🔥 chỉ người tạo mới sửa (hoặc leader - đã check bằng guard)
    if (timeline.createdBy.id !== userId) {
      throw new ForbiddenException('Bạn không có quyền sửa');
    }

    Object.assign(timeline, dto);

    if (dto.day || dto.time) {
      timeline.scheduledAt = buildScheduledAt(
        timeline.trip.startDate,
        dto.day ?? timeline.day,
        dto.time ?? timeline.time,
      );
    }

    const result = await this.timelineRepo.save(timeline);

    return result;
  }

  // =============================
  // DELETE
  // =============================
  async delete(id: string, userId: string) {
    const timeline = await this.timelineRepo.findOne({
      where: { id },
      relations: ['createdBy'],
    });

    if (!timeline) throw new NotFoundException('Timeline not found');

    if (timeline.createdBy.id !== userId) {
      throw new ForbiddenException('Bạn không có quyền xoá');
    }

    await this.timelineRepo.delete(id);

    return { message: 'Deleted successfully' };
  }

  // =============================
  // DELETE ALL BY TRIP
  // =============================
  async deleteByTrip(tripId: string, userId: string) {
    const trip = await this.tripRepo.findOne({
      where: { id: tripId },
    });

    if (!trip) throw new NotFoundException('Trip not found');

    // Check if user is leader
    // if (trip.leaderId !== userId) {
    //   throw new ForbiddenException('Only leader can delete all timelines');
    // }

    const result = await this.timelineRepo.delete({ trip: { id: tripId } });

    return {
      message: 'All timelines deleted successfully',
      deletedCount: result.affected || 0,
    };
  }

  // =============================
  // LIST BY TRIP
  // =============================
  async findByTrip(tripId: string) {
    const data = await this.timelineRepo.find({
      where: { trip: { id: tripId } },
      select: {
        id: true,
        title: true,
        description: true,
        time: true,
        notify: true,
        day: true,
      },
      order: {
        day: 'ASC',
        time: 'ASC',
      },
    });
    return data;
  }

  async findById(id: string) {
    return await this.timelineRepo.findOne({
      where: { id },
    });
  }
}