import { randomUUID } from "node:crypto";
import { eq } from "drizzle-orm";
import { Injectable } from "@nestjs/common";
import { db } from "../config/database.js";
import { homework } from "./homework.schema.js";
import { outboxRepository } from "../shared/outbox/outbox.repository.js";
import type { Homework, NewHomework } from "./homework.schema.js";
import {
  NotFoundError,
  ValidationError,
} from "../shared/errors/application-error.js";

export interface AssignHomeworkInput {
  classId: string;
  title: string;
  description?: string;
  dueDate: Date | string;
  createdBy: string;
}

@Injectable()
export class HomeworkService {
  async assignHomework(input: AssignHomeworkInput): Promise<{ id: string }> {
    if (!input.classId || !input.title || !input.createdBy) {
      throw new ValidationError("classId, title, createdBy are required");
    }

    const id = randomUUID();
    const record: NewHomework = {
      id,
      classId: input.classId,
      title: input.title,
      description: input.description,
      // Drizzle datetime 列需要 Date 对象；HTTP 请求体里 dueDate 是 ISO 字符串。
      dueDate:
        input.dueDate instanceof Date ? input.dueDate : new Date(input.dueDate),
      status: "assigned",
      createdBy: input.createdBy,
    };

    await db.transaction(async (tx) => {
      await tx.insert(homework).values(record);
      await outboxRepository.create(
        {
          id: randomUUID(),
          aggregateId: id,
          aggregateType: "homework",
          eventType: "homework.assigned",
          payload: JSON.stringify({
            id,
            classId: input.classId,
            title: input.title,
          }),
          status: "pending",
        },
        tx,
      );
    });

    return { id };
  }

  async getHomework(id: string): Promise<Homework> {
    const [record] = await db
      .select()
      .from(homework)
      .where(eq(homework.id, id))
      .limit(1);
    if (!record) {
      throw new NotFoundError(`Homework ${id} not found`);
    }
    return record;
  }

  async listByClass(classId: string): Promise<Homework[]> {
    return db.select().from(homework).where(eq(homework.classId, classId));
  }

  async submitHomework(id: string): Promise<void> {
    const existing = await this.getHomework(id);
    if (existing.status === "submitted") {
      throw new ValidationError(`Homework ${id} already submitted`);
    }

    await db.transaction(async (tx) => {
      await tx
        .update(homework)
        .set({ status: "submitted" })
        .where(eq(homework.id, id));
      await outboxRepository.create(
        {
          id: randomUUID(),
          aggregateId: id,
          aggregateType: "homework",
          eventType: "homework.submitted",
          payload: JSON.stringify({ id }),
          status: "pending",
        },
        tx,
      );
    });
  }
}
