# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Flags used in transformation pipeline.

Flags annotated with:
* 'oof' are applicable for OOF mode
* 'default' are applicable for default mode
* 'required' must be populated for the pipeline to work
* 'optional' pipeline will work without populating them
"""

import enum
import json
import os
import sys
from typing import Any, List, Optional, Union

from absl import flags

from pathology.shared_libs.flags import secret_flag_utils
from pathology.transformation_pipeline.ingestion_lib import ingest_const


def _load_multi_string(val: Optional[str]) -> Optional[Union[List[str], str]]:
  if val is None:
    return None
  try:
    return json.loads(val)
  except json.decoder.JSONDecodeError:
    return val


def get_value(
    env_var: str,
    test_default_value: Optional[Any] = None,
    default_value: Any = None,
) -> Any:
  """Returns applicable value for flag.

  Prioritizes env_var if available, then test value, then default value.

  Args:
    env_var: Environment variable name to use.
    test_default_value: Default value to use when running tests.
    default_value: Default value to use.
  """
  if test_default_value and (
      'UNITTEST_ON_FORGE' in os.environ or 'unittest' in sys.modules
  ):
    default_value = test_default_value
  return secret_flag_utils.get_secret_or_env(env_var, default_value)


class MetadataUidValidation(enum.Enum):
  NONE = 1
  LOG_WARNING = 2
  ERROR = 3


class MetadataTagLengthValidation(enum.Enum):
  NONE = 1
  LOG_WARNING = 2
  LOG_WARNING_AND_CLIP = 3
  ERROR = 4


class UidSource(enum.Enum):
  DICOM = 1
  METADATA = 2


class Wsi2DcmCompression(enum.Enum):
  JPEG = 'jpeg'
  JPEG2000 = 'jpeg2000'
  RAW = 'raw'


class Wsi2DcmFirstLevelCompression(enum.Enum):
  NONE = None
  JPEG = Wsi2DcmCompression.JPEG.value
  JPEG2000 = Wsi2DcmCompression.JPEG2000.value
  RAW = Wsi2DcmCompression.RAW.value


class Wsi2DcmJpegCompressionSubsample(enum.Enum):
  SUBSAMPLE_444 = '444'
  SUBSAMPLE_440 = '440'
  SUBSAMPLE_442 = '442'
  SUBSAMPLE_420 = '420'


class Wsi2DcmPixelEquivalentTransform(enum.Enum):
  DISABLED = None
  HIGHEST_MAGNIFICATION = 'SVSImportPreferScannerTileingForLargestLevel'
  ALL_LEVELS = 'SVSImportPreferScannerTileingForAllLevels'


class WsiDicomExtendedDepthOfFieldDefault(enum.Enum):
  YES = 'YES'
  NO = 'NO'


class WsiDicomFocusMethod(enum.Enum):
  AUTO = 'AUTO'
  MANUAL = 'MANUAL'


TRANSFORMATION_PIPELINE_FLG = flags.DEFINE_string(
    'transformation_pipeline',
    secret_flag_utils.get_secret_or_env('TRANSFORMATION_PIPELINE', 'default'),
    '[optional|default,oof] Defines transformation pipeline to run. Must be one'
    ' of {default, oof}.',
)

EMBED_ICC_PROFILE_FLG = flags.DEFINE_boolean(
    'embed_icc_profile',
    secret_flag_utils.get_bool_secret_or_env('EMBED_ICC_PROFILE', True),
    '[optional|default] embed icc profile into dicom',
)

METADATA_BUCKET_FLG = flags.DEFINE_string(
    'metadata_bucket',
    secret_flag_utils.get_secret_or_env('METADATA_BUCKET', ''),
    '[required|default] Name of bucket non-imaging metadata is pushed to.',
)

BIG_QUERY_METADATA_TABLE_FLG = flags.DEFINE_string(
    'big_query_metadata_table',
    secret_flag_utils.get_secret_or_env('BIG_QUERY_METADATA_TABLE', ''),
    'Id of BigQuery table to ingest metadata from '
    'ex.project_id.dataset_id.table_name.',
)

DICOM_GUID_PREFIX_FLG = flags.DEFINE_string(
    'dicom_guid_prefix',
    secret_flag_utils.get_secret_or_env(
        'DICOM_GUID_PREFIX', ingest_const.DPAS_UID_PREFIX
    ),
    '[optional|default] Prefix for generated DICOM GUIDs.',
)

VIEWER_DEBUG_URL_FLG = flags.DEFINE_string(
    'viewer_debug_url',
    secret_flag_utils.get_secret_or_env('VIEWER_DEBUG_URL', ''),
    '[optional|default,oof] If defined, a debug url is logged at the end of'
    ' ingestion.',
)

DICOM_QUOTA_ERROR_RETRY_FLG = flags.DEFINE_integer(
    'dicom_quota_error_retry_sec',
    secret_flag_utils.get_secret_or_env('DICOM_QUOTA_ERROR_RETRY', '600'),
    '[optional|default,oof] Seconds to wait before retying DICOM Store'
    ' upload due to quota failure.',
)

COPY_DICOM_TO_BUCKET_URI_FLG = flags.DEFINE_string(
    'copy_dicom_to_bucket_uri',
    secret_flag_utils.get_secret_or_env('COPY_DICOM_TO_BUCKET_URI', ''),
    '[optional|default/oof] The bucket to copy generated DICOM to. If empty, '
    'the generated DICOM will not be copied.',
)

# Pub/Sub flags
PROJECT_ID_FLG = flags.DEFINE_string(
    'project_id',
    secret_flag_utils.get_secret_or_env('PROJECT_ID', ''),
    '[required|default,oof] GCP project id to listen on.',
)
GCS_SUBSCRIPTION_FLG = flags.DEFINE_string(
    'gcs_subscription',
    secret_flag_utils.get_secret_or_env('GCS_SUBSCRIPTION', None),
    '[required|default] Pub/Sub GCS subscription id to listen on. Used in'
    ' regular (default) transformation pipeline only.',
)
DICOM_STORE_SUBSCRIPTION_FLG = flags.DEFINE_string(
    'dicom_store_subscription',
    secret_flag_utils.get_secret_or_env('DICOM_STORE_SUBSCRIPTION', None),
    '[optional|default] Pub/Sub DICOM store subscription id to listen on. Used'
    'in regular (default) transformation pipeline only.',
)
OOF_SUBSCRIPTION_FLG = flags.DEFINE_string(
    'oof_subscription',
    secret_flag_utils.get_secret_or_env('OOF_SUBSCRIPTION', None),
    '[required|oof] Pub/Sub Dataflow subscription id to listen on. Used in OOF'
    ' transformation pipeline only.',
)
INGEST_COMPLETE_OOF_TRIGGER_PUBSUB_TOPIC_FLG = flags.DEFINE_string(
    'ingest_complete_oof_trigger_pubsub_topic',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.INGEST_COMPLETE_OOF_TRIGGER_PUBSUB_TOPIC, ''
    ),
    '[required|oof] Pub/Sub topic to publish to at completion of ingestion to'
    ' trigger OOF.',
)

# GCS ingestion flags
INGEST_SUCCEEDED_URI_FLG = flags.DEFINE_string(
    'ingest_succeeded_uri',
    secret_flag_utils.get_secret_or_env('INGEST_SUCCEEDED_URI', ''),
    '[required|default] Bucket/path to move input to if ingest succeeds.',
)
INGEST_FAILED_URI_FLG = flags.DEFINE_string(
    'ingest_failed_uri',
    secret_flag_utils.get_secret_or_env('INGEST_FAILED_URI', ''),
    '[required|default] Bucket/path to move input to if an error occurs.',
)
GCS_INGEST_STUDY_INSTANCE_UID_SOURCE_FLG = flags.DEFINE_enum_class(
    'gcs_ingest_study_instance_uid_source',
    get_value(env_var='GCS_INGEST_STUDY_INSTANCE_UID_SOURCE'),
    UidSource,
    '[required|default] Which StudyInstanceUID source to use in GCS ingestion.',
)
INGEST_IGNORE_ROOT_DIR_FLG = flags.DEFINE_multi_string(
    'ingest_ignore_root_dirs',
    _load_multi_string(
        secret_flag_utils.get_secret_or_env(
            'INGEST_IGNORE_ROOT_DIR', '["cloud-ingest", "storage-transfer"]'
        )
    ),
    '[optional|default] Root folders ignored in ingestion.',
)
GCS_FILE_INGEST_LIST_FLG = flags.DEFINE_multi_string(
    'gcs_file_to_ingest_list',
    _load_multi_string(
        secret_flag_utils.get_secret_or_env('GCS_FILE_INGEST_LIST', None)
    ),
    '[optional|default] Fixed list of GCS files to ingest. Client will'
    'terminate at end of ingestion.',
)
GCS_UPLOAD_IGNORE_FILE_EXTS_FLG = flags.DEFINE_list(
    'gcs_upload_ignore_file_exts',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.GCS_UPLOAD_IGNORE_FILE_EXT, ''
    ),
    '[optional|default] Comma-separated list of file extensions (e.g., ".json")'
    ' which will be ignored by ingestion if uploaded to GCS. Files without'
    ' extensions can be defined as " ".',
)
GCS_IGNORE_FILE_REGEXS_FLG = flags.DEFINE_multi_string(
    'gcs_ignore_file_regexs',
    _load_multi_string(
        secret_flag_utils.get_secret_or_env(
            ingest_const.EnvVarNames.GCS_IGNORE_FILE_REGEXS, None
        )
    ),
    '[optional|default] List of regular expression used to identify file names '
    'to ignore. The file will will be ingored if any of the regex match.',
)
GCS_IGNORE_FILE_BUCKET_FLG = flags.DEFINE_string(
    'gcs_ignore_file_bucket',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.GCS_IGNORE_FILE_BUCKET, ''
    ),
    '[optional|default] Optional name of bucket to move files which are ignored'
    ' by the transformation pipeline.',
)
FILENAME_SLIDEID_REGEX_FLG = flags.DEFINE_string(
    'wsi2dcm_filename_slideid_regex',
    secret_flag_utils.get_secret_or_env(
        'SLIDEID_REGEX',
        secret_flag_utils.get_secret_or_env(
            'METADATA_PRIMARY_KEY_REGEX',
            '^[a-zA-Z0-9]+-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)+',
        ),
    ),
    '[optional|default] Regular expression used to identify candidate metadata'
    ' primary key in filename. Default value matches 3 or more hyphen separated'
    ' alpha-numeric blocks, e.g. SR-21-2 and SR-21-2-B1-5.',
)
FILENAME_SLIDEID_SPLIT_STR_FLG = flags.DEFINE_string(
    'filename_slideid_split_str',
    secret_flag_utils.get_secret_or_env(
        'FILENAME_SLIDEID_SPLIT_STR',
        secret_flag_utils.get_secret_or_env(
            'FILENAME_METADATA_PRIMARY_KEY_SPLIT_STR', '_'
        ),
    ),
    '[optional|default] Character or string to split GCS filename to find'
    ' metadata primary key using regex defined in FILENAME_SLIDEID_REGEX_FLG.',
)
TEST_WHOLE_FILENAME_AS_SLIDEID_FLG = flags.DEFINE_boolean(
    'test_whole_filename_as_slideid',
    secret_flag_utils.get_bool_secret_or_env(
        'TEST_WHOLE_FILENAME_AS_SLIDEID',
        secret_flag_utils.get_bool_secret_or_env(
            'TEST_WHOLE_FILENAME_AS_METADATA_PRIMARY_KEY',
        ),
    ),
    '[optional|default] Include slide whole filename excluding file extension'
    ' as a candidate metadata primary key.',
)
INCLUDE_UPLOAD_BUCKET_PATH_IN_WHOLE_FILENAME_SLIDEID_FLG = flags.DEFINE_boolean(
    'include_upload_bucket_path_in_whole_filename_slideid',
    secret_flag_utils.get_bool_secret_or_env(
        'INCLUDE_UPLOAD_BUCKET_PATH_IN_WHOLE_FILENAME_SLIDEID',
        secret_flag_utils.get_bool_secret_or_env(
            'INCLUDE_UPLOAD_BUCKET_PATH_IN_WHOLE_FILENAME_METADATA_PRIMARY_KEY'
        ),
    ),
    '[optional|default] Include bucket upload path in whole filename metadata '
    'primary key. If enabled and file upload to gs://mybucket/foo/bar.svs then '
    'whole filename metadata primary key will be foo/bar. If False (default), '
    'then whole filename metadata primary key will be bar.',
)

ENABLE_CREATE_MISSING_STUDY_INSTANCE_UID_FLG = flags.DEFINE_boolean(
    'enable_create_missing_study_instance_uid',
    secret_flag_utils.get_bool_secret_or_env(
        'ENABLE_CREATE_MISSING_STUDY_INSTANCE_UID'
    ),
    '[optional|default] If True pipeline will create instance Study Instance '
    'UID if its missing. Requires metadata to define accession number.',
)

ENABLE_METADATA_FREE_INGESTION_FLG = flags.DEFINE_boolean(
    'enable_metadata_free_ingestion',
    secret_flag_utils.get_bool_secret_or_env('ENABLE_METADATA_FREE_INGESTION'),
    '[optional|default] If True pipeline will ingest images without requiring '
    'metadata. Each image will be ingested into unique study and series '
    'instance uid. The PatientID will be set to the ingested file name.',
)

METADATA_UID_VALIDATION_FLG = flags.DEFINE_enum_class(
    'metadata_uid_validation',
    get_value(
        env_var='METADATA_UID_VALIDATION',
        default_value=MetadataUidValidation.LOG_WARNING.name,
    ),
    MetadataUidValidation,
    '[optional|default] How to report errors in metadata UID formating.',
)


METADATA_TAG_LENGTH_VALIDATION_FLG = flags.DEFINE_enum_class(
    'metadata_tag_length_validation',
    get_value(
        env_var='METADATA_TAG_LENGTH_VALIDATION',
        default_value=MetadataTagLengthValidation.LOG_WARNING.name,
    ),
    MetadataTagLengthValidation,
    '[optional|default] How to handles DICOM tags which exceed the length/size '
    'limits that are defined by the DICOM standard for the tags VR code.',
)


DELETE_FILE_FROM_INGEST_AT_BUCKET_AT_INGEST_SUCCESS_OR_FAILURE_FLG = flags.DEFINE_boolean(
    'delete_file_from_ingest_or_bucket',
    secret_flag_utils.get_bool_secret_or_env(
        'DELETE_FILE_FROM_INGEST_BUCKET_AT_INGEST_SUCCESS_OR_FAILURE',
        undefined_value=True,
    ),
    '[optional|default] Set flag to False to disable file deletion from the '
    'ingestion bucket. If disabled, file will be copied to the success/failure '
    'bucket at the end of ingestion but not removed from the ingestion bucket '
    'to help de-duplicate uploads.',
)

REDIS_SERVER_IP_FLG = flags.DEFINE_string(
    'redis_server_ip',
    secret_flag_utils.get_secret_or_env('REDIS_SERVER_IP', None),
    '[optional|default] IP address of cloud memory store for redis. Used to '
    'back cross GKE redis locks.',
)

REDIS_SERVER_PORT_FLG = flags.DEFINE_integer(
    'redis_server_port',
    int(secret_flag_utils.get_secret_or_env('REDIS_SERVER_PORT', '6379')),
    '[optional|default] Port of cloud memory store for redis. Used to back '
    'cross GKE redis locks.',
)

REDIS_DB_FLG = flags.DEFINE_integer(
    'redis_db',
    int(secret_flag_utils.get_secret_or_env('REDIS_DB', '0')),
    'Redis database',
)

REDIS_USERNAME_FLG = flags.DEFINE_string(
    'redis_auth_username',
    secret_flag_utils.get_secret_or_env('REDIS_USERNAME', None),
    'Redis auth username.',
)

REDIS_AUTH_PASSWORD_FLG = flags.DEFINE_string(
    'redis_auth_password',
    secret_flag_utils.get_secret_or_env('REDIS_AUTH_PASSWORD', None),
    'Redis auth password.',
)

TRANSFORM_POD_UID_FLG = flags.DEFINE_string(
    'transform_pod_uid',
    secret_flag_utils.get_secret_or_env('MY_POD_UID', None),
    'UID of GKE pod. Do not set unless in test.',
)

TRANSFORMATION_LOCK_RETRY_FLG = flags.DEFINE_integer(
    'transformation_lock_retry',
    int(
        secret_flag_utils.get_secret_or_env('TRANSFORMATION_LOCK_RETRY', '300')
    ),
    '[optional|default] Amount of time in seconds that pipeline should wait '
    'before retrying image ingestion when an image cannot be ingested due to '
    'another instance of the pipleine holding an transformation lock.',
)

OOF_INFERENCE_CONFIG_PATH_FLG = flags.DEFINE_string(
    'oof_inference_config_path',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.OOF_INFERENCE_CONFIG_PATH, ''
    ),
    '[optional|default] Path to OOF inference config to be included in Pub/Sub '
    'messages generated at the end of ingestion to trigger inference pipeline.',
)
OOF_LEGACY_INFERENCE_PIPELINE_FLG = flags.DEFINE_boolean(
    'oof_legacy_inference_pipeline',
    secret_flag_utils.get_bool_secret_or_env(
        'OOF_LEGACY_INFERENCE_PIPELINE',
        undefined_value=True,
    ),
    '[private|default,oof] Whether to use legacy OOF inference pipeline. Used '
    'both to trigger inference pipeline in default ingestion mode and process '
    'inference pipeline output in OOF ingestion mode.',
)

# DICOM Metadata Schema flags
REQUIRE_TYPE1_DICOM_TAG_METADATA_IS_DEFINED_FLG = flags.DEFINE_boolean(
    'require_type1_dicom_tag_metadata_is_defined',
    secret_flag_utils.get_bool_secret_or_env(
        'REQUIRE_TYPE1_DICOM_TAG_METADATA_IS_DEFINED'
    ),
    '[optional|default] Require all type one tags defined in the metadata'
    ' schema have defined values; if not raise'
    ' MissingRequiredMetadataValueError exception and  fail ingestion.',
)

CREATE_NULL_TYPE2C_DICOM_TAG_IF_METADATA_IS_UNDEFINED_FLG = flags.DEFINE_boolean(
    'create_null_type2c_dicom_tag_if_metadata_if_undefined',
    secret_flag_utils.get_bool_secret_or_env(
        'CREATE_NULL_TYPE2C_DICOM_TAG_IF_METADATA_IS_UNDEFINED'
    ),
    '[optional|default] Undefined mandatory type2 tags are always initalized to'
    ' None. Flag enables automatic initialization of undefined type2c DICOM '
    ' tags to None.',
)

METADATA_PRIMARY_KEY_COLUMN_NAME_FLG = flags.DEFINE_string(
    'metadata_primary_key_column_name',
    secret_flag_utils.get_secret_or_env(
        'METADATA_PRIMARY_KEY_COLUMN_NAME', 'Bar Code Value'
    ),
    '[optional|default] Defines column name used as primary key for joining '
    'candidate imaging with BigQuery or CSV metadata.',
)

# Undefined Metadata default values

DEFAULT_ICC_PROFILE_FLG = flags.DEFINE_string(
    'default_iccprofile',
    get_value(
        env_var='DEFAULT_ICCPROFILE',
        default_value=ingest_const.ICCProfile.SRGB,
    ),
    '[optional|default] ICC Profile to embedd in wsi imaging that does not '
    'provide an ICCColor profile.',
)

THIRD_PARTY_ICC_PROFILE_DICRECTORY_FLG = flags.DEFINE_string(
    'third_party_icc_profile_directory',
    secret_flag_utils.get_secret_or_env(
        'THIRD_PARTY_ICC_PROFILE_DIRECTORY', ''
    ),
    'Directory that contains third party icc profiles.',
)

WSI_DICOM_EXTENDED_DEPTH_OF_FIELD_DEFAULT_VALUE_FLG = flags.DEFINE_enum_class(
    'wsi_dicom_extended_depth_of_field_default_value',
    get_value(
        env_var='WSI_DICOM_EXTENDED_DEPTH_OF_FIELD_DEFAULT_VALUE',
        default_value=WsiDicomExtendedDepthOfFieldDefault.NO.name,
    ),
    WsiDicomExtendedDepthOfFieldDefault,
    '[optional|default] Default metadata value for extended depth of field'
    ' DICOM tag metadata in VL Whole Slide Microscopy Images.',
)

WSI_DICOM_FOCUS_METHOD_DEFAULT_VALUE_FLG = flags.DEFINE_enum_class(
    'wsi_dicom_focus_method_default_value',
    get_value(
        env_var='WSI_DICOM_FOCUS_METHOD_DEFAULT_VALUE',
        default_value=WsiDicomFocusMethod.AUTO.name,
    ),
    WsiDicomFocusMethod,
    '[optional|default] Default metadata value for focus method DICOM tag'
    ' metadata in VL Whole Slide Microscopy Images.',
)

WSI_DICOM_SLICE_THICKNESS_DEFAULT_VALUE_FLG = flags.DEFINE_float(
    'wsi_dicom_slice_thickness_default_value',
    float(
        get_value(
            env_var='WSI_DICOM_SLICE_THICKNESS_DEFAULT_VALUE',
            default_value=12.0,
        )
    ),
    '[optional|default] Default metadata value for slice thickness (micrometer)'
    ' DICOM tag metadata in VL Whole Slide Microscopy Images. ',
)


# DICOM Store ingestion flags
DICOM_STORE_INGEST_GCS_URI_FLG = flags.DEFINE_string(
    'dicom_store_ingest_gcs_uri',
    secret_flag_utils.get_secret_or_env('DICOM_STORE_INGEST_GCS_URI', ''),
    '[optional|default] GCS URI for temporarily storing DICOM files when'
    ' ingesting from DICOM Store. Files are stored as backup before deletion'
    ' from DICOM Store.',
)

# Openslide metadata flags
ADD_OPENSLIDE_BACKGROUND_COLOR_METADATA_FLG = flags.DEFINE_boolean(
    'add_openslide_background_color_metadata',
    secret_flag_utils.get_bool_secret_or_env(
        'ADD_OPENSLIDE_BACKGROUND_COLOR_METADATA'
    ),
    '[optional|default] OpenSlide provides hooks to return WSI background color'
    ' however metadata retrieval and embedding is experimental and disabled by '
    'default. At time of writing none of the available openslide supported WSI '
    'imaging encoded this metadata.',
)

ADD_OPENSLIDE_TOTAL_PIXEL_MATRIX_ORIGIN_SEQ_FLG = flags.DEFINE_boolean(
    'add_openslide_total_pixel_matrix_origin_seq',
    secret_flag_utils.get_bool_secret_or_env(
        'ADD_OPENSLIDE_TOTAL_PIXEL_MATRIX_ORIGIN_SEQ'
    ),
    '[optional|default] Openslide provides hooks to return the slide '
    'coordinates of the imaged region however metadata retrieval and embedding '
    'is experimental and disabled by default. At time of writing none of the '
    'available openslide supported WSI imaging encoded this metadata.',
)

# WSI specific flags
INGESTION_PYRAMID_LAYER_GENERATION_CONFIG_PATH_FLG = flags.DEFINE_string(
    'ingestion_pyramid_layer_generation_config_path',
    secret_flag_utils.get_secret_or_env(
        'INGESTION_PYRAMID_LAYER_GENERATION_CONFIG_PATH', ''
    ),
    '[optional|default] Path to *.YAML or *.JSON file which defines WSI'
    ' downsampling pyramid layers to generate.',
)
WSI2DCM_DICOM_FRAME_HEIGHT_FLG = flags.DEFINE_integer(
    'wsi2dcm_dicom_frame_height',
    secret_flag_utils.get_secret_or_env('WSI2DCM_DICOM_FRAME_HEIGHT', '256'),
    '[optional|default] wsi2dcm dicom frame height.',
)
WSI2DCM_DICOM_FRAME_WIDTH_FLG = flags.DEFINE_integer(
    'wsi2dcm_dicom_frame_width',
    secret_flag_utils.get_secret_or_env('WSI2DCM_DICOM_FRAME_WIDTH', '256'),
    '[optional|default] wsi2dcm dicom frame width.',
)
WSI2DCM_COMPRESSION_FLG = flags.DEFINE_enum_class(
    'wsi2dcm_compression',
    get_value(
        env_var='WSI2DCM_COMPRESSION',
        default_value=Wsi2DcmCompression.JPEG.name,
    ),
    Wsi2DcmCompression,
    '[optional|default] wsi2dcm compression param used across all levels; '
    'Can be overridden at highest magnification by using the '
    '--first_level_compression flag.',
)
WSI2DCM_FIRST_LEVEL_COMPRESSION_FLG = flags.DEFINE_enum_class(
    'wsi2dcm_first_level_compression',
    get_value(
        env_var='WSI2DCM_FIRST_LEVEL_COMPRESSION',
        default_value=Wsi2DcmFirstLevelCompression.NONE.name,
    ),
    Wsi2DcmFirstLevelCompression,
    '[optional|default] wsi2dcm compression param to use at highest '
    'magnification level.',
)
WSI2DCM_JPEG_COMPRESSION_QUALITY_FLG = flags.DEFINE_integer(
    'wsi2dcm_jpeg_compression_quality',
    secret_flag_utils.get_secret_or_env(
        'WSI2DCM_JPEG_COMPRESSION_QUALITY', '95'
    ),
    '[optional|default] wsi2dcm jpeg compression quality range 1 - 100.',
)
WSI2DCM_JPEG_COMPRESSION_SUBSAMPLING_FLG = flags.DEFINE_enum_class(
    'wsi2dcm_jpeg_compression_subsampling',
    get_value(
        env_var='WSI2DCM_JPEG_COMPRESSION_SUBSAMPLING',
        default_value=Wsi2DcmJpegCompressionSubsample.SUBSAMPLE_444.name,
    ),
    Wsi2DcmJpegCompressionSubsample,
    '[optional|default] wsi2dcm jpeg compression subsampling.',
)
WSI2DCM_PIXEL_EQUIVALENT_TRANSFORM_FLG = flags.DEFINE_enum_class(
    'wsi2dcm_pixel_equivalent_transform',
    get_value(
        env_var='WSI2DCM_PIXEL_EQUIVALENT_TRANSFORM',
        default_value=Wsi2DcmPixelEquivalentTransform.HIGHEST_MAGNIFICATION.name,
    ),
    Wsi2DcmPixelEquivalentTransform,
    '[optional|default] Defines input image magnifications that wsi2dcm will '
    'use to perform pixel equivalent transform on.',
)
INIT_SERIES_INSTANCE_UID_FROM_METADATA_FLG = flags.DEFINE_boolean(
    'init_series_instance_uid_from_metadata',
    secret_flag_utils.get_bool_secret_or_env(
        'INIT_SERIES_INSTANCE_UID_FROM_METADATA'
    ),
    '[optional|default] Initialize series instance UID from metadata.'
    ' Recommended setting = False. If true disables auto-reingestion of rescans'
    ' into new series and correct handling of rescans would need to be handled'
    ' outside of DPAS ingestion.',
)

# Flat image specific flags
FLAT_IMAGES_VL_MICROSCOPIC_IMAGE_IOD_FLG = flags.DEFINE_boolean(
    'flat_images_vl_microscopic_image_iod',
    secret_flag_utils.get_bool_secret_or_env(
        'FLAT_IMAGES_VL_MICROSCOPIC_IMAGE_IOD'
    ),
    '[optional|default] Whether to use VL Microscopic Image IOD for ingestion'
    ' of flat images without slide coordinates. If unset, all images will use'
    ' VL Slide-Coordinates Microscopic Image IOD.',
)

# DICOM Store URL flags
DICOMWEB_URL_FLG = flags.DEFINE_string(
    'dicomweb_url',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.DICOMWEB_URL, ''
    ),
    '[required|default,oof] DICOM Store to upload primary imaging into.',
)
OOF_DICOMWEB_BASE_URL_FLG = flags.DEFINE_string(
    'oof_dicomweb_base_url',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.OOF_DICOMWEB_BASE_URL, ''
    ),
    '[required|oof] DICOM Store to upload OOF imaging into.',
)
DICOM_STORE_TO_CLEAN_FLG = flags.DEFINE_string(
    'dicom_store_to_clean',
    secret_flag_utils.get_secret_or_env(
        ingest_const.EnvVarNames.DICOM_STORE_TO_CLEAN, ''
    ),
    '[optional|oof] DICOM Store to cleanup instances used for OOF pipeline'
    ' after it completes.',
)

# Barcode flags
ZXING_CLI_FLG = flags.DEFINE_string(
    'zxing_cli',
    secret_flag_utils.get_secret_or_env('ZXING_CLI', '/zxing/cpp/build/zxing'),
    '[optional|default] Path to zxing command line tool.',
)
DISABLE_CLOUD_VISION_BARCODE_SEG_FLG = flags.DEFINE_boolean(
    'testing_disable_cloudvision',
    secret_flag_utils.get_bool_secret_or_env(
        'DISABLE_CLOUD_VISION_BARCODE_SEG',
        not (
            secret_flag_utils.get_bool_secret_or_env(
                'ENABLE_CLOUD_VISION_BARCODE_SEGMENTATION', True
            )
        ),
    ),
    '[private] Unit testing flag. Disables cloud vision.',
)

DISABLE_BARCODE_DECODER_FLG = flags.DEFINE_boolean(
    'disable_barcode_decoder',
    secret_flag_utils.get_bool_secret_or_env(
        'DISABLE_BARCODE_DECODER',
        not (
            secret_flag_utils.get_bool_secret_or_env(
                'ENABLE_BARCODE_DECODER', True
            )
        ),
    ),
    '[optional|default] Disable barcode decoder.',
)
