import { Injectable } from "@nestjs/common";
import type { NotificationTemplate } from "../notifications/notifications.schema.js";
import * as repo from "./templates.repository.js";
import type {
  CreateTemplateDto,
  UpdateTemplateDto,
  ListTemplatesDto,
  RenderTemplateDto,
} from "./templates.dto.js";
import {
  NotFoundError,
  ValidationError,
} from "../shared/errors/application-error.js";

export interface RenderedNotification {
  title: string;
  content: string;
}

/**
 * TemplateService —— 通知模板管理 + 渲染。
 *
 * 职责：
 * - CRUD 模板
 * - 渲染模板（{{variable}} 占位符替换）
 *
 * 仲裁依据 02-architecture-design.md §3.1.3：模板按 (code, locale) 唯一。
 */
@Injectable()
export class TemplatesService {
  async create(dto: CreateTemplateDto): Promise<NotificationTemplate> {
    return repo.insert({
      code: dto.code,
      type: dto.type,
      titleTemplate: dto.titleTemplate,
      contentTemplate: dto.contentTemplate,
      defaultChannels: dto.defaultChannels,
      variables: dto.variables,
      locale: dto.locale,
      status: "draft",
    });
  }

  async getById(id: string): Promise<NotificationTemplate> {
    const tpl = await repo.findById(id);
    if (!tpl) {
      throw new NotFoundError("Template", id);
    }
    return tpl;
  }

  async list(dto: ListTemplatesDto): Promise<NotificationTemplate[]> {
    return repo.list(dto);
  }

  async update(
    id: string,
    dto: UpdateTemplateDto,
  ): Promise<NotificationTemplate> {
    const existing = await this.getById(id);
    await repo.update(id, {
      titleTemplate: dto.titleTemplate,
      contentTemplate: dto.contentTemplate,
      defaultChannels: dto.defaultChannels,
      variables: dto.variables,
      status: dto.status,
    });
    return { ...existing, ...dto } as NotificationTemplate;
  }

  async delete(id: string): Promise<void> {
    await this.getById(id); // 确保存在
    await repo.remove(id);
  }

  /**
   * 渲染模板：将 {{variable}} 占位符替换为实际值。
   *
   * 仲裁依据 02-architecture-design.md §4.2.3 RenderTemplate RPC。
   */
  async render(dto: RenderTemplateDto): Promise<RenderedNotification> {
    const tpl = await repo.findByCode(dto.code, dto.locale);
    if (!tpl) {
      throw new NotFoundError(
        "Template",
        `code=${dto.code} locale=${dto.locale ?? "default"}`,
      );
    }

    // 检查必填变量
    if (tpl.variables && Array.isArray(tpl.variables)) {
      for (const varName of tpl.variables) {
        if (!(varName in dto.variables)) {
          throw new ValidationError(`Missing required variable: ${varName}`);
        }
      }
    }

    const title = this.replacePlaceholders(tpl.titleTemplate, dto.variables);
    const content = this.replacePlaceholders(
      tpl.contentTemplate,
      dto.variables,
    );

    return { title, content };
  }

  /**
   * 替换 {{variable}} 占位符。
   * 简单实现：正则匹配 {{key}} 并替换。
   */
  private replacePlaceholders(
    template: string,
    variables: Record<string, string>,
  ): string {
    return template.replace(/\{\{(\w+)\}\}/g, (match, key: string) => {
      return variables[key] ?? match;
    });
  }
}
