text: from __future__ import annotations
  
  import json
  from typing import (
      Any,
      Callable,
      Mapping,
      Sequence,
      TypeVar,
  )
  
  from .types import BaseOutputHandler, PaginatedResult, FieldSpec
  
  _json_opts: Mapping[str, Any] = {"indent": 2}
  
  T = TypeVar('T')
  
  
  class JsonOutputHandler(BaseOutputHandler):
  
      def print_item(
          self,
          item: Mapping[str, Any] | None,
          fields: Sequence[FieldSpec],
      ) -> None:
          if item is None:
              print(json.dumps({
                  "count": 0,
                  "total_count": 0,
                  "items": [],
              }))
              return
          field_map = {f.field_name: f for f in fields}
          print(json.dumps(
              {
                  "count": 1,
                  "total_count": 1,
                  "items": [
                      {
                          field_map[k].alt_name: field_map[k].formatter.format_json(v, field_map[k])
                          for k, v in item.items()
                      },
                  ],
              },
              **_json_opts,
          ))
  
      def print_items(
          self,
          items: Sequence[Mapping[str, Any]],
          fields: Sequence[FieldSpec],
      ) -> None:
          field_map = {f.field_name: f for f in fields}
          print(json.dumps(
              {
                  "count": len(items),
                  "total_count": len(items),
                  "items": [
                      {
                          field_map[k].alt_name: field_map[k].formatter.format_json(v, field_map[k])
                          for k, v in item.items()
                      } for item in items
                  ],
              },
              **_json_opts,
          ))
  
      def print_list(
          self,
          items: Sequence[Mapping[str, Any]],
          fields: Sequence[FieldSpec],
          *,
          is_scalar: bool = False,
      ) -> None:
          if is_scalar:
              assert len(fields) == 1
              item_list = [
                  {
                      fields[0].alt_name: fields[0].formatter.format_json(item, fields[0]),
                  }
                  for item in items
              ]
          else:
              field_map = {f.field_name: f for f in fields}
              item_list = [
                  {
                      field_map[k].alt_name: field_map[k].formatter.format_json(v, field_map[k])
                      for k, v in item.items()
                  }
                  for item in items
              ]
          print(json.dumps(
              {
                  "count": len(items),
                  "total_count": len(items),
                  "items": item_list,
              },
              **_json_opts,
          ))
  
      def print_paginated_list(
          self,
          fetch_func: Callable[[int, int], PaginatedResult],
          initial_page_offset: int,
          page_size: int = None,
      ) -> None:
          page_size = page_size or 20
          result = fetch_func(initial_page_offset, page_size)
          field_map = {f.field_name: f for f in result.fields}
          print(json.dumps(
              {
                  "count": len(result.items),
                  "total_count": result.total_count,
                  "items": [
                      {
                          field_map[k].alt_name: field_map[k].formatter.format_json(v, field_map[k])
                          for k, v in item.items()
                      }
                      for item in result.items
                  ],
              },
              **_json_opts,
          ))
  
      def print_error(
          self,
          error: Exception,
      ) -> None:
          print(json.dumps(
              {
                  "error": str(error),
              },
              **_json_opts,
          ))
  
      def print_fail(
          self,
          message: str,
      ) -> None:
          print(json.dumps(
              {
                  "error": message,
              },
              **_json_opts,
          ))
  