import { Repository } from 'typeorm';
import { AppDataSource } from '../index';
import { CalendarConnection } from '../entities/CalendarConnection.entity';
import { CalendarEventSync } from '../entities/CalendarEventSync.entity';

export class CalendarRepository {
  private connRepo: Repository<CalendarConnection>;
  private syncRepo: Repository<CalendarEventSync>;

  constructor() {
    this.connRepo = AppDataSource.getRepository(CalendarConnection);
    this.syncRepo = AppDataSource.getRepository(CalendarEventSync);
  }

  findConnectionsByUserId(userId: string): Promise<CalendarConnection[]> {
    return this.connRepo.find({
      where: { userId, status: 'connected' as const },
      order: { createdAt: 'DESC' },
    });
  }

  findConnectionById(id: string): Promise<CalendarConnection | null> {
    return this.connRepo.findOne({ where: { id } });
  }

  findAllActiveConnections(): Promise<CalendarConnection[]> {
    return this.connRepo.find({ where: { status: 'connected' } });
  }

  findExpiringTokens(withinMinutes: number): Promise<CalendarConnection[]> {
    const threshold = new Date(Date.now() + withinMinutes * 60 * 1000);
    return this.connRepo
      .createQueryBuilder('c')
      .where('c.status = :status', { status: 'connected' })
      .andWhere('c.token_expires_at IS NOT NULL')
      .andWhere('c.token_expires_at <= :threshold', { threshold })
      .getMany();
  }

  getWriteTarget(userId: string): Promise<CalendarConnection | null> {
    return this.connRepo
      .createQueryBuilder('c')
      .where('c.user_id = :userId', { userId })
      .andWhere('c.status = :status', { status: 'connected' })
      .andWhere("JSON_SEARCH(c.calendar_config, 'one', 'true', NULL, '$[*].writeTarget') IS NOT NULL")
      .getOne();
  }

  saveConnection(data: Partial<CalendarConnection>): Promise<CalendarConnection> {
    return this.connRepo.save(this.connRepo.create(data));
  }

  async updateConnection(id: string, data: Partial<CalendarConnection>): Promise<CalendarConnection> {
    await this.connRepo.update(id, data);
    const conn = await this.findConnectionById(id);
    if (!conn) throw new Error('Connection not found');
    return conn;
  }

  deleteConnection(id: string): Promise<void> {
    return this.connRepo.delete(id).then(() => undefined);
  }

  saveSync(data: Partial<CalendarEventSync>): Promise<CalendarEventSync> {
    return this.syncRepo.save(this.syncRepo.create(data));
  }

  findSyncByBooking(bookingId: string): Promise<CalendarEventSync[]> {
    return this.syncRepo.find({ where: { bookingId } });
  }

  async markSynced(
    bookingId: string,
    connectionId: string,
    externalEventId: string,
    calendarId: string,
  ): Promise<void> {
    await this.syncRepo.update(
      { bookingId, connectionId },
      {
        syncStatus: 'synced',
        externalEventId,
        externalCalendarId: calendarId,
        syncedAt: new Date(),
      },
    );
  }
}
