import {
  AuthRequiredError,
  ForbiddenError as SessionForbiddenError,
  NotFoundError as SessionNotFoundError,
} from '@/server/middleware/session.js';

type DomainErrorCode =
  | 'VALIDATION_ERROR'
  | 'AUTH_REQUIRED'
  | 'FORBIDDEN'
  | 'NOT_FOUND'
  | 'CONFLICT'
  | 'PROVIDER_ERROR';

export class DomainError extends Error {
  constructor(
    public readonly code: DomainErrorCode | string,
    public readonly status: 400 | 401 | 403 | 404 | 409 | 502,
    message: string,
  ) {
    super(message);
    this.name = 'DomainError';
  }
}

export class ValidationError extends DomainError {
  constructor(message: string, code = 'VALIDATION_ERROR') {
    super(code, 400, message);
    this.name = 'ValidationError';
  }
}

export class AuthError extends DomainError {
  constructor(message = 'Authentication required', code = 'AUTH_REQUIRED') {
    super(code, 401, message);
    this.name = 'AuthError';
  }
}

export class ForbiddenError extends DomainError {
  constructor(message = 'Forbidden', code = 'FORBIDDEN') {
    super(code, 403, message);
    this.name = 'ForbiddenError';
  }
}

export class NotFoundError extends DomainError {
  constructor(message = 'Not found', code = 'NOT_FOUND') {
    super(code, 404, message);
    this.name = 'NotFoundError';
  }
}

export class ConflictError extends DomainError {
  constructor(message = 'Conflict', code = 'CONFLICT') {
    super(code, 409, message);
    this.name = 'ConflictError';
  }
}

export class ProviderError extends DomainError {
  constructor(message = 'Provider error', code = 'PROVIDER_ERROR') {
    super(code, 502, message);
    this.name = 'ProviderError';
  }
}

export function toDomainError(err: unknown): DomainError | null {
  if (err instanceof DomainError) return err;
  if (err instanceof AuthRequiredError) {
    return new AuthError(err.message, err.code);
  }
  if (err instanceof SessionForbiddenError) {
    return new ForbiddenError(err.message, err.code);
  }
  if (err instanceof SessionNotFoundError) {
    return new NotFoundError(err.message, err.code);
  }
  return null;
}

export function respondDomainError(err: DomainError): Response {
  return Response.json(
    {
      error: {
        code: err.code,
        message: err.message,
      },
    },
    { status: err.status },
  );
}
