import { Injectable, NotFoundException } from '@nestjs/common';
import { IiosMessageTemplate, IiosTemplateChannel } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';

export class TemplateNotFoundError extends NotFoundException {
  constructor(key: string, channel: string, locale: string) {
    super(`no active template for key="${key}" channel=${channel} locale=${locale}`);
    this.name = 'TemplateNotFoundError';
  }
}

@Injectable()
export class TemplateRepository {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Resolve the template to use: the highest active version for (key, channel, locale), preferring
   * a row owned by `scopeId` (a tenant override) and falling back to the global default (scopeId
   * NULL). Throws if neither exists.
   */
  async resolve(
    key: string,
    channel: IiosTemplateChannel,
    locale = 'en',
    scopeId?: string,
    version?: number,
  ): Promise<IiosMessageTemplate> {
    // Scoped override first, then the global default — for both the pinned and highest-active paths.
    if (scopeId) {
      const scoped = await this.pick({ key, channel, locale, scopeId }, version);
      if (scoped) return scoped;
    }
    const global = await this.pick({ key, channel, locale, scopeId: null }, version);
    if (global) return global;
    throw new TemplateNotFoundError(key, channel, locale);
  }

  /** A pinned `version` fetches that exact version (the caller was explicit); otherwise the highest
   *  active version — a retracted (inactive) newest version falls back to the last good one. */
  private pick(
    where: { key: string; channel: IiosTemplateChannel; locale: string; scopeId: string | null },
    version?: number,
  ) {
    return this.prisma.iiosMessageTemplate.findFirst({
      where: version != null ? { ...where, version } : { ...where, active: true },
      orderBy: { version: 'desc' },
    });
  }
}
