import { createId } from "@paralleldrive/cuid2";
import { Injectable } from "@nestjs/common";
import { questionsRepository } from "./questions.repository.js";
import type { Question, NewQuestion } from "./questions.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 CreateQuestionInput {
  knowledgePointId: string;
  type: string;
  content: string;
  options?: Record<string, unknown> | null;
  answer: string;
  explanation?: string;
  difficulty?: number;
  source?: string;
  createdBy: string;
  metadata?: Record<string, unknown> | null;
}

export interface UpdateQuestionInput {
  content?: string;
  options?: Record<string, unknown> | null;
  answer?: string;
  explanation?: string;
  difficulty?: number;
  status?: string;
}

export interface ListQuestionsInput {
  knowledgePointId?: string;
  type?: string;
  difficulty?: number;
  status?: string;
  page?: number;
  pageSize?: number;
}

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

  async createQuestion(input: CreateQuestionInput): Promise<{ id: string }> {
    const id = createId();
    const record: NewQuestion = {
      id,
      knowledgePointId: input.knowledgePointId,
      type: input.type,
      content: input.content,
      options: input.options ?? null,
      answer: input.answer,
      explanation: input.explanation,
      difficulty: input.difficulty ?? 3,
      status: "draft",
      source: input.source ?? "manual",
      createdBy: input.createdBy,
      metadata: input.metadata ?? null,
    };
    await questionsRepository.create(record);

    await this.outbox.publish(
      EVENT_TYPES.QUESTION_CREATED,
      AGGREGATE_TYPES.QUESTION,
      id,
      {
        knowledge_point_id: record.knowledgePointId,
        type: record.type,
        difficulty: record.difficulty,
        status: record.status,
        source: record.source,
        created_by: record.createdBy,
      },
    );

    return { id };
  }

  async getQuestion(id: string): Promise<Question> {
    const question = await questionsRepository.findById(id);
    if (!question) {
      throw new NotFoundError("Question", id);
    }
    return question;
  }

  async listByKnowledgePoint(knowledgePointId: string): Promise<Question[]> {
    return questionsRepository.findByKnowledgePointId(knowledgePointId);
  }

  async list(query: ListQuestionsInput): Promise<Question[]> {
    return questionsRepository.find(query);
  }

  async updateQuestion(id: string, data: UpdateQuestionInput): Promise<void> {
    const existing = await this.getQuestion(id);
    await questionsRepository.update(id, data);

    const eventType =
      data.status === "published"
        ? EVENT_TYPES.QUESTION_PUBLISHED
        : EVENT_TYPES.QUESTION_UPDATED;

    await this.outbox.publish(eventType, AGGREGATE_TYPES.QUESTION, id, {
      content: data.content ?? existing.content,
      difficulty: data.difficulty ?? existing.difficulty,
      status: data.status ?? existing.status,
    });
  }

  async deleteQuestion(id: string): Promise<void> {
    await this.getQuestion(id);
    await questionsRepository.delete(id);

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