import { Injectable } from '@nestjs/common';
import { createHash } from 'node:crypto';
import { TemplateRepository } from './template.repository';
import { renderTemplate, type RawTemplate, type RenderedContent } from './template.renderer';
import { isInlineSource, type RenderOptions, type TemplateSource } from './template.model';

/** The provenance of a rendered send — carried onto the outbound command for replay/audit. */
export interface RenderProvenance {
  templateKey: string | null; // null for inline sources
  templateVersion: number | null;
  templateLocale: string | null;
  renderedHash: string; // sha256 of the rendered content
}

export interface RenderResult {
  content: RenderedContent;
  provenance: RenderProvenance;
}

@Injectable()
export class TemplateService {
  constructor(private readonly repo: TemplateRepository) {}

  /**
   * Resolve (if a stored key) and render a template with `vars`, returning the content plus the
   * provenance to record on the send. Inline sources skip the DB and carry null key/version — the
   * caller owns inline content, so no declared-variable contract is enforced for it.
   */
  async render(source: TemplateSource, vars: Record<string, unknown>, opts: RenderOptions): Promise<RenderResult> {
    const locale = opts.locale ?? 'en';

    if (isInlineSource(source)) {
      const raw: RawTemplate = {
        subject: source.inline.subject,
        bodyHtml: source.inline.html,
        bodyText: source.inline.text,
        variables: source.inline.variables ?? [],
      };
      const content = renderTemplate(raw, vars);
      return { content, provenance: this.provenance(content, null, null, null) };
    }

    const tpl = await this.repo.resolve(source.key, opts.channel, locale, opts.scopeId, source.version);
    const content = renderTemplate(
      { subject: tpl.subject, bodyHtml: tpl.bodyHtml, bodyText: tpl.bodyText, variables: (tpl.variables as string[] | null) ?? [] },
      vars,
    );
    return { content, provenance: this.provenance(content, tpl.key, tpl.version, tpl.locale) };
  }

  private provenance(content: RenderedContent, key: string | null, version: number | null, locale: string | null): RenderProvenance {
    const hash = createHash('sha256').update(JSON.stringify(content)).digest('hex');
    return { templateKey: key, templateVersion: version, templateLocale: locale, renderedHash: hash };
  }
}
