import { createId } from "@paralleldrive/cuid2";
import { Injectable } from "@nestjs/common";
import { chaptersRepository } from "./chapters.repository.js";
import type { Chapter, NewChapter } from "./chapters.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 CreateChapterInput {
  textbookId: string;
  title: string;
  order?: number;
  parentId?: string;
}

export interface UpdateChapterInput {
  title?: string;
  order?: number;
  status?: string;
}

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

  async createChapter(input: CreateChapterInput): Promise<{ id: string }> {
    const id = createId();
    const record: NewChapter = {
      id,
      textbookId: input.textbookId,
      title: input.title,
      order: input.order ?? 0,
      parentId: input.parentId,
      status: "draft",
    };
    await chaptersRepository.create(record);

    await this.outbox.publish(
      EVENT_TYPES.CHAPTER_CREATED,
      AGGREGATE_TYPES.CHAPTER,
      id,
      {
        textbook_id: record.textbookId,
        title: record.title,
        order: record.order,
        parent_id: record.parentId,
      },
    );

    return { id };
  }

  async getChapter(id: string): Promise<Chapter> {
    const chapter = await chaptersRepository.findById(id);
    if (!chapter) {
      throw new NotFoundError("Chapter", id);
    }
    return chapter;
  }

  async listChaptersByTextbook(textbookId: string): Promise<Chapter[]> {
    return chaptersRepository.findByTextbookId(textbookId);
  }

  async updateChapter(id: string, data: UpdateChapterInput): Promise<void> {
    const existing = await this.getChapter(id);
    await chaptersRepository.update(id, data);

    await this.outbox.publish(
      EVENT_TYPES.CHAPTER_UPDATED,
      AGGREGATE_TYPES.CHAPTER,
      id,
      {
        title: data.title ?? existing.title,
        order: data.order ?? existing.order,
        status: data.status ?? existing.status,
      },
    );
  }

  async deleteChapter(id: string): Promise<void> {
    await this.getChapter(id);
    await chaptersRepository.delete(id);

    await this.outbox.publish(
      EVENT_TYPES.CHAPTER_DELETED,
      AGGREGATE_TYPES.CHAPTER,
      id,
      { deleted: true },
    );
  }
}
