/**
 * 도메인별 에러 클래스
 *
 * ManduError 인터페이스 기반의 실제 Error 클래스들.
 * try-catch에서 instanceof 체크 가능.
 */

import { ErrorCode, ERROR_SUMMARIES } from "./types";
import type { ManduError, RouteContext, ErrorType } from "./types";

/**
 * Mandu 에러 베이스 클래스
 */
export abstract class ManduBaseError extends Error implements ManduError {
  abstract readonly errorType: ErrorType;
  readonly code: ErrorCode | string;
  readonly httpStatus?: number;
  readonly summary: string;
  readonly fix: { file: string; suggestion: string; line?: number };
  readonly route?: RouteContext;
  readonly timestamp: string;

  constructor(
    code: ErrorCode | string,
    message: string,
    fix: { file: string; suggestion: string; line?: number },
    options?: {
      httpStatus?: number;
      route?: RouteContext;
      cause?: unknown;
    }
  ) {
    super(message, { cause: options?.cause });
    this.name = this.constructor.name;
    this.code = code;
    this.httpStatus = options?.httpStatus;
    this.summary =
      typeof code === "string" && code in ERROR_SUMMARIES
        ? ERROR_SUMMARIES[code as ErrorCode]
        : message;
    this.fix = fix;
    this.route = options?.route;
    this.timestamp = new Date().toISOString();
  }

  /**
   * ManduError 인터페이스로 변환
   */
  toManduError(): ManduError {
    return {
      errorType: this.errorType,
      code: this.code,
      httpStatus: this.httpStatus,
      message: this.message,
      summary: this.summary,
      fix: this.fix,
      route: this.route,
      timestamp: this.timestamp,
    };
  }
}

// ============================================================
// 파일 시스템 에러
// ============================================================

/**
 * 파일 읽기/쓰기 에러
 */
export class FileError extends ManduBaseError {
  readonly errorType = "LOGIC_ERROR" as const;
  readonly filePath: string;
  readonly operation: "read" | "write" | "access" | "stat";

  constructor(
    filePath: string,
    operation: "read" | "write" | "access" | "stat",
    cause?: unknown
  ) {
    const message = `파일 ${operation} 실패: ${filePath}`;
    super(
      ErrorCode.SLOT_IMPORT_ERROR,
      message,
      {
        file: filePath,
        suggestion: `파일이 존재하고 읽기 권한이 있는지 확인하세요`,
      },
      { cause }
    );
    this.filePath = filePath;
    this.operation = operation;
  }
}

/**
 * 디렉토리 읽기 에러
 */
export class DirectoryError extends ManduBaseError {
  readonly errorType = "LOGIC_ERROR" as const;
  readonly dirPath: string;

  constructor(dirPath: string, cause?: unknown) {
    super(
      ErrorCode.SLOT_NOT_FOUND,
      `디렉토리 읽기 실패: ${dirPath}`,
      {
        file: dirPath,
        suggestion: `디렉토리가 존재하고 접근 가능한지 확인하세요`,
      },
      { cause }
    );
    this.dirPath = dirPath;
  }
}

// ============================================================
// Guard 에러
// ============================================================

/**
 * Guard 아키텍처 검사 에러
 */
export class GuardError extends ManduBaseError {
  readonly errorType = "LOGIC_ERROR" as const;
  readonly ruleId: string;

  constructor(
    ruleId: string,
    message: string,
    file: string,
    options?: {
      line?: number;
      suggestion?: string;
      cause?: unknown;
    }
  ) {
    super(
      ErrorCode.SLOT_VALIDATION_ERROR,
      message,
      {
        file,
        suggestion: options?.suggestion || "아키텍처 규칙을 확인하세요",
        line: options?.line,
      },
      { cause: options?.cause }
    );
    this.ruleId = ruleId;
  }
}

// ============================================================
// Router 에러
// ============================================================

/**
 * 라우터 에러
 */
export class RouterError extends ManduBaseError {
  readonly errorType = "FRAMEWORK_BUG" as const;

  constructor(
    message: string,
    file: string,
    options?: {
      route?: RouteContext;
      cause?: unknown;
    }
  ) {
    super(
      ErrorCode.FRAMEWORK_ROUTER_ERROR,
      message,
      {
        file,
        suggestion: "라우트 설정을 확인하세요",
      },
      { httpStatus: 500, ...options }
    );
  }
}

// ============================================================
// SSR 에러
// ============================================================

/**
 * SSR 렌더링 에러
 */
export class SSRError extends ManduBaseError {
  readonly errorType = "FRAMEWORK_BUG" as const;

  constructor(
    message: string,
    route: RouteContext,
    cause?: unknown
  ) {
    super(
      ErrorCode.FRAMEWORK_SSR_ERROR,
      message,
      {
        file: `app/${route.id}/page.tsx`,
        suggestion: "페이지 컴포넌트에서 렌더링 오류가 발생했습니다",
      },
      { httpStatus: 500, route, cause }
    );
  }
}

// ============================================================
// Contract 에러
// ============================================================

/**
 * API 계약 위반 에러
 */
export class ContractError extends ManduBaseError {
  readonly errorType = "LOGIC_ERROR" as const;

  constructor(
    message: string,
    contractFile: string,
    options?: {
      route?: RouteContext;
      cause?: unknown;
    }
  ) {
    super(
      ErrorCode.SLOT_VALIDATION_ERROR,
      message,
      {
        file: contractFile,
        suggestion: "API 계약과 실제 구현이 일치하는지 확인하세요",
      },
      { httpStatus: 400, ...options }
    );
  }
}

// ============================================================
// Security 에러
// ============================================================

/**
 * 보안 관련 에러
 */
export class SecurityError extends ManduBaseError {
  readonly errorType = "LOGIC_ERROR" as const;
  readonly securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation";

  constructor(
    securityType: "path_traversal" | "injection" | "unauthorized" | "import_violation",
    message: string,
    file?: string
  ) {
    super(
      ErrorCode.SLOT_HANDLER_ERROR,
      message,
      {
        file: file || "unknown",
        suggestion: "보안 정책을 위반하는 요청입니다",
      },
      { httpStatus: 403 }
    );
    this.securityType = securityType;
  }
}
