import type { AuditEvent } from '@prisma/client';
import type { IAuditEventRepository, AuditEventFilter, AuditEventCreateInput } from '../repositories/interfaces.js';
import { NotFoundError } from './mcp-server.service.js';

export interface AuditEventQueryParams {
  sessionId?: string;
  projectName?: string;
  eventKind?: string;
  serverName?: string;
  correlationId?: string;
  userName?: string;
  tokenName?: string;
  tokenSha?: string;
  from?: string;
  to?: string;
  limit?: number;
  offset?: number;
}

export class AuditEventService {
  constructor(private readonly repo: IAuditEventRepository) {}

  async list(params?: AuditEventQueryParams): Promise<{ events: AuditEvent[]; total: number }> {
    const filter = this.buildFilter(params);
    const [events, total] = await Promise.all([
      this.repo.findAll(filter),
      this.repo.count(filter),
    ]);
    return { events, total };
  }

  async getById(id: string): Promise<AuditEvent> {
    const event = await this.repo.findById(id);
    if (!event) {
      throw new NotFoundError(`Audit event '${id}' not found`);
    }
    return event;
  }

  async createBatch(events: AuditEventCreateInput[]): Promise<number> {
    return this.repo.createMany(events);
  }

  async listSessions(params?: { projectName?: string; userName?: string; from?: string; to?: string; limit?: number; offset?: number }): Promise<{ sessions: Awaited<ReturnType<IAuditEventRepository['listSessions']>>; total: number }> {
    const filter: { projectName?: string; userName?: string; from?: Date; to?: Date; limit?: number; offset?: number } = {};
    if (params?.projectName !== undefined) filter.projectName = params.projectName;
    if (params?.userName !== undefined) filter.userName = params.userName;
    if (params?.from !== undefined) filter.from = new Date(params.from);
    if (params?.to !== undefined) filter.to = new Date(params.to);
    if (params?.limit !== undefined) filter.limit = params.limit;
    if (params?.offset !== undefined) filter.offset = params.offset;

    const countFilter: { projectName?: string; userName?: string; from?: Date; to?: Date } = {};
    if (params?.projectName !== undefined) countFilter.projectName = params.projectName;
    if (params?.userName !== undefined) countFilter.userName = params.userName;
    if (params?.from !== undefined) countFilter.from = new Date(params.from);
    if (params?.to !== undefined) countFilter.to = new Date(params.to);

    const [sessions, total] = await Promise.all([
      this.repo.listSessions(Object.keys(filter).length > 0 ? filter : undefined),
      this.repo.countSessions(Object.keys(countFilter).length > 0 ? countFilter : undefined),
    ]);
    return { sessions, total };
  }

  /**
   * Rank a project's tools by invocation count over a recent window, to derive
   * a usage-weighted favourite shortlist. Presented names are normalized to
   * canonical `server/tool` in the repository.
   */
  async toolUsage(projectName: string, windowDays = 30, limit = 50): Promise<Awaited<ReturnType<IAuditEventRepository['toolUsage']>>> {
    const from = new Date(Date.now() - windowDays * 86400_000);
    const ranked = await this.repo.toolUsage(projectName, from);
    return limit > 0 ? ranked.slice(0, limit) : ranked;
  }

  private buildFilter(params?: AuditEventQueryParams): AuditEventFilter | undefined {
    if (!params) return undefined;
    const filter: AuditEventFilter = {};

    if (params.sessionId !== undefined) filter.sessionId = params.sessionId;
    if (params.projectName !== undefined) filter.projectName = params.projectName;
    if (params.eventKind !== undefined) filter.eventKind = params.eventKind;
    if (params.serverName !== undefined) filter.serverName = params.serverName;
    if (params.correlationId !== undefined) filter.correlationId = params.correlationId;
    if (params.userName !== undefined) filter.userName = params.userName;
    if (params.tokenName !== undefined) filter.tokenName = params.tokenName;
    if (params.tokenSha !== undefined) filter.tokenSha = params.tokenSha;
    if (params.from !== undefined) filter.from = new Date(params.from);
    if (params.to !== undefined) filter.to = new Date(params.to);
    if (params.limit !== undefined) filter.limit = params.limit;
    if (params.offset !== undefined) filter.offset = params.offset;

    return filter;
  }
}
