import { createId } from "@paralleldrive/cuid2";
import { Injectable } from "@nestjs/common";
import { textbooksRepository } from "./textbooks.repository.js";
import type { Textbook, NewTextbook } from "./textbooks.schema.js";
import { OutboxService } from "../shared/outbox/outbox.service.js";
import { AGGREGATE_TYPES, EVENT_TYPES } from "../shared/outbox/events.js";
import { NotFoundError } from "../shared/errors/application-error.js";

export interface CreateTextbookInput {
  title: string;
  subjectId: string;
  gradeId: string;
  version?: string;
  metadata?: Record<string, unknown> | null;
}

export interface UpdateTextbookInput {
  title?: string;
  status?: string;
  metadata?: Record<string, unknown> | null;
}

export interface ListTextbooksInput {
  subjectId?: string;
  gradeId?: string;
  page?: number;
  pageSize?: number;
}

@Injectable()
export class TextbooksService {
  constructor(private readonly outbox: OutboxService) {}

  async create(input: CreateTextbookInput): Promise<{ id: string }> {
    const id = createId();
    const record: NewTextbook = {
      id,
      title: input.title,
      subjectId: input.subjectId,
      gradeId: input.gradeId,
      version: input.version ?? "1.0",
      status: "draft",
      metadata: input.metadata ?? null,
    };
    await textbooksRepository.create(record);

    await this.outbox.publish(
      EVENT_TYPES.TEXTBOOK_CREATED,
      AGGREGATE_TYPES.TEXTBOOK,
      id,
      {
        title: record.title,
        subject_id: record.subjectId,
        grade_id: record.gradeId,
        version: record.version,
        status: record.status,
      },
    );

    return { id };
  }

  async list(query?: ListTextbooksInput): Promise<Textbook[]> {
    return textbooksRepository.find(query);
  }

  async getById(id: string): Promise<Textbook> {
    const result = await textbooksRepository.findById(id);
    if (!result) {
      throw new NotFoundError("Textbook", id);
    }
    return result;
  }

  async update(id: string, data: UpdateTextbookInput): Promise<void> {
    const existing = await this.getById(id);
    await textbooksRepository.update(id, data);

    const eventType =
      data.status === "published"
        ? EVENT_TYPES.TEXTBOOK_PUBLISHED
        : data.status === "archived"
          ? EVENT_TYPES.TEXTBOOK_ARCHIVED
          : EVENT_TYPES.TEXTBOOK_UPDATED;

    await this.outbox.publish(eventType, AGGREGATE_TYPES.TEXTBOOK, id, {
      title: data.title ?? existing.title,
      status: data.status ?? existing.status,
      metadata: data.metadata ?? existing.metadata,
    });
  }

  async delete(id: string): Promise<void> {
    await this.getById(id);
    await textbooksRepository.delete(id);
    // 教材删除视为归档事件，下游可感知失效
    await this.outbox.publish(
      EVENT_TYPES.TEXTBOOK_ARCHIVED,
      AGGREGATE_TYPES.TEXTBOOK,
      id,
      { deleted: true },
    );
  }
}
