import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository } from 'typeorm';
import { CreateLogDTO } from './dto/create-log.dto';
import { LogEntry } from './entities/log-entry.entity';
import { LOGEVENT, LOGLEVEL } from './model/logging-event.type';

@Injectable()
export class LoggingService {
  constructor(
    @InjectRepository(LogEntry)
    private repository: Repository<LogEntry>,
  ) {
    // void this.onStart();
  }

  private async onStart() {
    await this.repository.save({
      level: 'DEBUG',
      event: 'application_start',
      details: 'application started',
      userId: -1,
    });
  }

  async info(
    {
      event,
      details,
      userId,
    }: {
      event: LOGEVENT;
      details: string;
      userId: number;
    },
    manager?: EntityManager,
  ) {
    const e: CreateLogDTO = {
      event,
      details,
      userId,
      level: 'INFO',
    };
    await (manager?.getRepository(LogEntry) ?? this.repository).save(e);
  }

  async error({
    event,
    details,
    userId,
  }: {
    event: LOGEVENT;
    details: string;
    userId: number;
  }) {
    const e: CreateLogDTO = {
      event,
      details,
      userId,
      level: 'ERROR',
    };
    await this.repository.save(e);
  }

  async warn({
    event,
    details,
    userId,
  }: {
    event: LOGEVENT;
    details: string;
    userId: number;
  }) {
    const e: CreateLogDTO = {
      event,
      details,
      userId,
      level: 'WARN',
    };
    await this.repository.save(e);
  }

  async debug(data: {
    event: LOGEVENT;
    details: string;
    userId: number;
    duration?: number;
  }) {
    const e: CreateLogDTO = {
      event: data.event,
      details: data.details,
      userId: data.userId,
      level: 'DEBUG',
      duration: data.duration,
    };
    await this.repository.save(e);
  }

  async findLogs(query: {
    page: number;
    limit: number;
    level?: LOGLEVEL;
    event?: LOGEVENT;
    from?: string;
    to?: string;
    search?: string;
  }): Promise<{
    data: LogEntry[];
    page: number;
    limit: number;
    total: number;
    hasNextPage: boolean;
  }> {
    const builder = this.repository.createQueryBuilder('log');
    if (query.level) builder.andWhere('log.level = :level', { level: query.level });
    if (query.event) builder.andWhere('log.event = :event', { event: query.event });
    if (query.from) builder.andWhere('log.createdAt >= :from', { from: query.from });
    if (query.to) {
      builder.andWhere('log.createdAt <= :to', { to: new Date(`${query.to}T23:59:59.999Z`) });
    }
    const term = query.search?.trim().toLocaleLowerCase();
    if (term) {
      builder.andWhere('LOWER(log.details) LIKE :search', { search: `%${term}%` });
    }
    const total = await builder.getCount();
    const data = await builder
      .orderBy('log.createdAt', 'DESC')
      .offset((query.page - 1) * query.limit)
      .limit(query.limit)
      .getMany();
    return {
      data,
      page: query.page,
      limit: query.limit,
      total,
      hasNextPage: query.page * query.limit < total,
    };
  }
}
