export enum CoreEduErrorCode {
  VALIDATION_ERROR = "CORE_EDU_VALIDATION_ERROR",
  NOT_FOUND = "CORE_EDU_NOT_FOUND",
  UNAUTHORIZED = "CORE_EDU_UNAUTHORIZED",
  FORBIDDEN = "CORE_EDU_FORBIDDEN",
  CONFLICT = "CORE_EDU_CONFLICT",
  INTERNAL_ERROR = "CORE_EDU_INTERNAL_ERROR",
  EXAM_NOT_FOUND = "CORE_EDU_EXAM_NOT_FOUND",
  HOMEWORK_NOT_FOUND = "CORE_EDU_HOMEWORK_NOT_FOUND",
  GRADE_NOT_FOUND = "CORE_EDU_GRADE_NOT_FOUND",
  OUTBOX_PUBLISH_FAILED = "CORE_EDU_OUTBOX_PUBLISH_FAILED",
}

export class ApplicationError extends Error {
  readonly code: CoreEduErrorCode;
  readonly statusCode: number;
  readonly details?: unknown;
  traceId?: string;

  constructor(
    code: CoreEduErrorCode,
    message: string,
    statusCode: number = 500,
    details?: unknown,
  ) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
    this.statusCode = statusCode;
    this.details = details;
  }

  toJSON(): Record<string, unknown> {
    return {
      success: false,
      error: {
        code: this.code,
        message: this.message,
        details: this.details,
        traceId: this.traceId,
      },
    };
  }
}

export class ValidationError extends ApplicationError {
  constructor(message: string, details?: unknown) {
    super(CoreEduErrorCode.VALIDATION_ERROR, message, 400, details);
  }
}

export class NotFoundError extends ApplicationError {
  constructor(message: string, details?: unknown) {
    super(CoreEduErrorCode.NOT_FOUND, message, 404, details);
  }
}

export class UnauthorizedError extends ApplicationError {
  constructor(message: string = "Unauthorized") {
    super(CoreEduErrorCode.UNAUTHORIZED, message, 401);
  }
}

export class ForbiddenError extends ApplicationError {
  constructor(message: string = "Forbidden") {
    super(CoreEduErrorCode.FORBIDDEN, message, 403);
  }
}

export class PermissionDeniedError extends ApplicationError {
  constructor(permission: string) {
    super(CoreEduErrorCode.FORBIDDEN, `Permission denied: ${permission}`, 403, {
      permission,
    });
  }
}

export class ConflictError extends ApplicationError {
  constructor(message: string, details?: unknown) {
    super(CoreEduErrorCode.CONFLICT, message, 409, details);
  }
}

export class InternalError extends ApplicationError {
  constructor(message: string = "Internal server error", details?: unknown) {
    super(CoreEduErrorCode.INTERNAL_ERROR, message, 500, details);
  }
}
