export class AppError extends Error {
  readonly code: string;
  readonly isRetryable: boolean;

  constructor(code: string, message: string, options?: { cause?: unknown; isRetryable?: boolean }) {
    super(message, { cause: options?.cause });
    this.name = this.constructor.name;
    this.code = code;
    this.isRetryable = options?.isRetryable ?? false;
  }

  toJSON(): Record<string, unknown> {
    return {
      name: this.name,
      code: this.code,
      message: this.message,
      isRetryable: this.isRetryable,
      cause: this.cause instanceof Error ? this.cause.message : this.cause,
    };
  }
}

export class JiraApiError extends AppError {
  constructor(message: string, options?: { cause?: unknown }) {
    super("JIRA_API_ERROR", message, { ...options, isRetryable: true });
  }
}

export class AgentError extends AppError {
  constructor(message: string, options?: { cause?: unknown; isRetryable?: boolean }) {
    super("AGENT_ERROR", message, {
      isRetryable: true,
      ...options,
    });
  }
}

export class GitHubApiError extends AppError {
  constructor(message: string, options?: { cause?: unknown }) {
    super("GITHUB_API_ERROR", message, { ...options, isRetryable: true });
  }
}

export class RepoOperationError extends AppError {
  constructor(message: string, options?: { cause?: unknown }) {
    super("REPO_OPERATION_ERROR", message, { ...options, isRetryable: false });
  }
}

export class SafetyViolationError extends AppError {
  constructor(message: string) {
    super("SAFETY_VIOLATION", message, { isRetryable: false });
  }
}

export class BuildFailureError extends AppError {
  readonly output: string;

  constructor(message: string, output: string) {
    super("BUILD_FAILURE", message, { isRetryable: true });
    this.output = output;
  }
}

export class JobTimeoutError extends AppError {
  constructor(message: string) {
    super("JOB_TIMEOUT", message, { isRetryable: false });
  }
}

export class RepoSelectionError extends AppError {
  constructor(message: string) {
    super("REPO_SELECTION_ERROR", message, { isRetryable: false });
  }
}

export class JobAbortedError extends AppError {
  constructor(message: string) {
    super("JOB_ABORTED", message, { isRetryable: false });
  }
}
