# MediLink_API_v3.py
import time, requests, yaml, json, os, traceback

try:
    from MediLink import MediLink_ConfigLoader
except ImportError:
    import MediLink_ConfigLoader

"""
TODO At some point it might make sense to test their acknoledgment endpoint. body is transactionId.
This API is used to extract the claim acknowledgement details for the given transactionid which was 
generated for 837 requests in claim submission process. Claims Acknowledgement (277CA) will provide 
a status of claim-level acknowledgement of all claims received in the front-end processing system and 
adjudication system.
"""

class ConfigLoader:
    @staticmethod
    def load_configuration(config_path=os.path.join(os.path.dirname(__file__), '..', 'json', 'config.json'), 
                           crosswalk_path=os.path.join(os.path.dirname(__file__), '..', 'json', 'crosswalk.json')):
        return MediLink_ConfigLoader.load_configuration(config_path, crosswalk_path)

    @staticmethod
    def load_swagger_file(swagger_path):
        try:
            print("Attempting to load Swagger file: {}".format(swagger_path))
            with open(swagger_path, 'r') as swagger_file:
                if swagger_path.endswith('.yaml') or swagger_path.endswith('.yml'):
                    print("Parsing YAML file: {}".format(swagger_path))
                    swagger_data = yaml.safe_load(swagger_file)
                elif swagger_path.endswith('.json'):
                    print("Parsing JSON file: {}".format(swagger_path))
                    swagger_data = json.load(swagger_file)
                else:
                    raise ValueError("Unsupported Swagger file format.")
            print("Successfully loaded Swagger file: {}".format(swagger_path))
            return swagger_data
        except ValueError as e:
            print("Error parsing Swagger file {}: {}".format(swagger_path, e))
            MediLink_ConfigLoader.log("Error parsing Swagger file {}: {}".format(swagger_path, e), level="ERROR")
        except FileNotFoundError:
            print("Swagger file not found: {}".format(swagger_path))
            MediLink_ConfigLoader.log("Swagger file not found: {}".format(swagger_path), level="ERROR")
        except Exception as e:
            print("Unexpected error loading Swagger file {}: {}".format(swagger_path, e))
            MediLink_ConfigLoader.log("Unexpected error loading Swagger file {}: {}".format(swagger_path, e), level="ERROR")
        return None

# Function to ensure numeric type
def ensure_numeric(value):
    if isinstance(value, str):
        try:
            value = float(value)
        except ValueError:
            raise ValueError("Cannot convert {} to a numeric type".format(value))
    return value

class TokenCache:
    def __init__(self):
        self.tokens = {}

    def get(self, endpoint_name, current_time):
        token_info = self.tokens.get(endpoint_name, {})
        if token_info:
            expires_at = token_info['expires_at']
            # Log cache hit and expiration time
            log_message = "Token for {} expires at {}. Current time: {}".format(endpoint_name, expires_at, current_time)
            MediLink_ConfigLoader.log(log_message, level="DEBUG")

            if expires_at > current_time:
                return token_info['access_token']

        # Log cache miss
        log_message = "No valid token found for {}".format(endpoint_name)
        MediLink_ConfigLoader.log(log_message, level="INFO")

        return None

    def set(self, endpoint_name, access_token, expires_in, current_time):
        current_time = ensure_numeric(current_time)
        expires_in = ensure_numeric(expires_in)

        # Log the expires_in value to debug
        log_message = "Token expires in: {} seconds for {}".format(expires_in, endpoint_name)
        MediLink_ConfigLoader.log(log_message, level="INFO")

        # Adjust expiration time by subtracting a buffer of 120 seconds
        expires_at = current_time + expires_in - 120
        log_message = "Setting token for {}. Expires at: {}".format(endpoint_name, expires_at)
        MediLink_ConfigLoader.log(log_message, level="INFO")

        self.tokens[endpoint_name] = {
            'access_token': access_token,
            'expires_at': expires_at
        }

class BaseAPIClient:
    def __init__(self, config):
        self.config = config
        self.token_cache = TokenCache()

    def get_access_token(self, endpoint_name):
        raise NotImplementedError("Subclasses should implement this!")

    def make_api_call(self, endpoint_name, call_type, url_extension="", params=None, data=None, headers=None):
        raise NotImplementedError("Subclasses should implement this!")

class APIClient(BaseAPIClient):
    def __init__(self):
        config, _ = MediLink_ConfigLoader.load_configuration()
        super().__init__(config)

    def get_access_token(self, endpoint_name):
        MediLink_ConfigLoader.log("[Get Access Token] Called for {}".format(endpoint_name), level="DEBUG")
        current_time = time.time()
        cached_token = self.token_cache.get(endpoint_name, current_time)
        
        if cached_token:
            expires_at = self.token_cache.tokens[endpoint_name]['expires_at']
            MediLink_ConfigLoader.log("Cached token expires at {}".format(expires_at), level="DEBUG")
            return cached_token
        
        # If no valid token, fetch a new one
        endpoint_config = self.config['MediLink_Config']['endpoints'][endpoint_name]
        token_url = endpoint_config['token_url']
        data = {
            'grant_type': 'client_credentials',
            'client_id': endpoint_config['client_id'],
            'client_secret': endpoint_config['client_secret']
        }

        # Add scope if specified in the configuration
        if 'scope' in endpoint_config:
            data['scope'] = endpoint_config['scope']

        headers = {'Content-Type': 'application/x-www-form-urlencoded'}

        response = requests.post(token_url, headers=headers, data=data)
        response.raise_for_status()
        token_data = response.json()
        access_token = token_data['access_token']
        expires_in = token_data.get('expires_in', 3600)

        self.token_cache.set(endpoint_name, access_token, expires_in, current_time)
        MediLink_ConfigLoader.log("Obtained NEW token for endpoint: {}".format(endpoint_name), level="INFO")
        return access_token

    def make_api_call(self, endpoint_name, call_type, url_extension="", params=None, data=None, headers=None):
        token = self.get_access_token(endpoint_name)
        if token:
            MediLink_ConfigLoader.log("[Make API Call] Token found for {}".format(endpoint_name), level="DEBUG")
        else:
            MediLink_ConfigLoader.log("[Make API Call] No token obtained for {}".format(endpoint_name), level="ERROR")
            raise ValueError("No access token available for endpoint: {}".format(endpoint_name))

        if headers is None:
            headers = {}
        headers.update({'Authorization': 'Bearer {}'.format(token), 'Accept': 'application/json'})
        base_url = self.config['MediLink_Config']['endpoints'][endpoint_name]['api_url']
        url = base_url + url_extension

        try:
            masked_headers = headers.copy()
            if 'Authorization' in masked_headers:
                masked_headers['Authorization'] = 'Bearer ***'

            def make_request():
                if call_type == 'GET':
                    return requests.get(url, headers=headers, params=params)
                elif call_type == 'POST':
                    headers['Content-Type'] = 'application/json'
                    return requests.post(url, headers=headers, json=data)
                elif call_type == 'DELETE':
                    return requests.delete(url, headers=headers)
                else:
                    raise ValueError("Unsupported call type: {}".format(call_type))

            # Make initial request
            response = make_request()

            # If we get a 5xx error, wait and retry once
            if 500 <= response.status_code < 600:
                MediLink_ConfigLoader.log(
                    "Received {} error from server for {} request to {}. Waiting 1 second before retry...".format(
                        response.status_code, call_type, url
                    ),
                    level="WARNING"
                )
                time.sleep(1)
                response = make_request()

            # Raise an HTTPError if the response was unsuccessful
            response.raise_for_status()

            return response.json()

        except requests.exceptions.HTTPError as http_err:
            # If http_err.response is None, handle it separately
            if http_err.response is None:
                log_message = (
                    "HTTPError with no response. "
                    "URL: {url}, "
                    "Method: {method}, "
                    "Params: {params}, "
                    "Data: {data}, "
                    "Headers: {masked_headers}, "
                    "Error: {error}"
                ).format(
                    url=url,
                    method=call_type,
                    params=params,
                    data=data,
                    masked_headers=masked_headers,
                    error=str(http_err)
                )
                MediLink_ConfigLoader.log(log_message, level="ERROR")
            else:
                # Extract status code and full response content
                status_code = http_err.response.status_code
                try:
                    # Try to log the JSON content if available
                    response_content = http_err.response.json()
                except ValueError:
                    # Fallback to raw text if JSON decoding fails
                    response_content = http_err.response.text

                log_message = (
                    "HTTPError: Status Code: {status}, "
                    "URL: {url}, "
                    "Method: {method}, "
                    "Params: {params}, "
                    "Data: {data}, "
                    "Headers: {masked_headers}, "
                    "Response Content: {content}"
                ).format(
                    status=status_code,
                    url=url,
                    method=call_type,
                    params=params,
                    data=data,
                    masked_headers=masked_headers,
                    content=response_content
                )
                MediLink_ConfigLoader.log(log_message, level="ERROR")
            raise

        except requests.exceptions.RequestException as req_err:
            # Log connection-related issues or other request exceptions
            log_message = (
                "RequestException: No response received. "
                "URL: {url}, "
                "Method: {method}, "
                "Params: {params}, "
                "Data: {data}, "
                "Headers: {masked_headers}, "
                "Error: {error}"
            ).format(
                url=url,
                method=call_type,
                params=params,
                data=data,
                masked_headers=masked_headers,
                error=str(req_err)
            )
            MediLink_ConfigLoader.log(log_message, level="ERROR")
            raise

        except Exception as e:
            # Capture traceback for unexpected exceptions
            tb = traceback.format_exc()
            log_message = (
                "Unexpected error: {error}. "
                "URL: {url}, "
                "Method: {method}, "
                "Params: {params}, "
                "Data: {data}, "
                "Headers: {masked_headers}. "
                "Traceback: {traceback}"
            ).format(
                error=str(e),
                url=url,
                method=call_type,
                params=params,
                data=data,
                masked_headers=masked_headers,
                traceback=tb
            )
            MediLink_ConfigLoader.log(log_message, level="ERROR")
            raise

def fetch_payer_name_from_api(client, payer_id, config, primary_endpoint='AVAILITY'):
    """
    Fetches the payer name using the provided APIClient instance.

    :param client: An instance of APIClient
    :param payer_id: The payer ID to fetch
    :param primary_endpoint: The primary endpoint to use
    :return: The payer name if found
    """
    # Ensure client is an instance of APIClient
    if not isinstance(client, APIClient):
        error_message = "Invalid client provided. Expected an instance of APIClient."
        print(error_message)
        MediLink_ConfigLoader.log(error_message, level="ERROR")
        exit(1)  # Exit the script
    
    # BUG Force AVAILITY until I can get a payer-list api from any of the other endpoints. 
    MediLink_ConfigLoader.log("[Fetch payer name from API] Overriding {} with AVAILITY.".format(primary_endpoint), level="DEBUG")
    primary_endpoint = 'AVAILITY'
    
    try:
        endpoints = config['MediLink_Config']['endpoints']
    except KeyError as e:
        error_message = "Configuration loading error in fetch_payer_name_from_api: Missing key {0}... Attempting to reload configuration.".format(e)
        # print(error_message)
        MediLink_ConfigLoader.log(error_message, level="ERROR")
        # Attempt to reload configuration if key is missing
        config, _ = MediLink_ConfigLoader.load_configuration()
        endpoints = config['MediLink_Config']['endpoints']  # Re-attempt to access endpoints
        MediLink_ConfigLoader.log("Re-loaded configuration successfully.", level="INFO")
    
    # Sanitize and validate payer_id
    if not isinstance(payer_id, str):
        payer_id = str(payer_id)
    
    payer_id = ''.join(char for char in payer_id if char.isalnum())
    
    if not payer_id:
        error_message = "Invalid payer_id in API v3: {}. Must contain a string of alphanumeric characters.".format(payer_id)
        MediLink_ConfigLoader.log(error_message, level="ERROR")
        print(error_message)
    
    # Define endpoint rotation logic
    endpoint_order = ([primary_endpoint] + 
                      [endpoint for endpoint in endpoints if endpoint != primary_endpoint]
                      if primary_endpoint in endpoints else list(endpoints.keys()))

    for endpoint_name in endpoint_order:
        try:
            endpoint_url = endpoints[endpoint_name].get('payer_list_endpoint', '/availity-payer-list')
            response = client.make_api_call(endpoint_name, 'GET', endpoint_url, {'payerId': payer_id})
            
            # Check if response exists
            if not response:
                log_message = "No response from {0} for Payer ID {1}".format(endpoint_name, payer_id)
                print(log_message)
                MediLink_ConfigLoader.log(log_message, level="ERROR")
                continue
            
            # Check if the status code is not 200
            status_code = response.get('statuscode', 200)
            if status_code != 200:
                log_message = "Invalid response status code {0} from {1} for Payer ID {2}. Message: {3}".format(
                    status_code, endpoint_name, payer_id, response.get('message', 'No message'))
                print(log_message)
                MediLink_ConfigLoader.log(log_message, level="ERROR")
                continue
            
            # Extract payers and validate the response structure
            payers = response.get('payers', [])
            if not payers:
                log_message = "No payer found at {0} for ID {1}. Response: {2}".format(endpoint_name, payer_id, response)
                print(log_message)
                MediLink_ConfigLoader.log(log_message, level="INFO")
                continue
            
            # Extract the payer name from the first payer in the list
            payer_name = payers[0].get('displayName') or payers[0].get('name')
            if not payer_name:
                log_message = "Payer name not found in the response from {0} for ID {1}. Response: {2}".format(
                    endpoint_name, payer_id, response)
                print(log_message)
                MediLink_ConfigLoader.log(log_message, level="ERROR")
                continue
            
            # Log successful payer retrieval
            log_message = "Found payer at {0} for ID {1}: {2}".format(endpoint_name, payer_id, payer_name)
            MediLink_ConfigLoader.log(log_message, level="INFO")
            return payer_name
        
        except Exception as e:
            error_message = "Error calling {0} for Payer ID {1}. Exception: {2}".format(endpoint_name, payer_id, e)
            MediLink_ConfigLoader.log(error_message, level="INFO")

    # If all endpoints fail
    final_error_message = "All endpoints exhausted for Payer ID {0}.".format(payer_id)
    print(final_error_message)
    MediLink_ConfigLoader.log(final_error_message, level="CRITICAL")
    raise ValueError(final_error_message)

def get_claim_summary_by_provider(client, tin, first_service_date, last_service_date, payer_id, get_standard_error='false'):
    endpoint_name = 'UHCAPI'
    url_extension = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['claim_summary_by_provider']
    headers = {
        'tin': tin,
        'firstServiceDt': first_service_date,
        'lastServiceDt': last_service_date,
        'payerId': payer_id,
        'getStandardError': get_standard_error,
        'Accept': 'application/json'
    }
    return client.make_api_call(endpoint_name, 'GET', url_extension, params=None, data=None, headers=headers)

def get_eligibility(client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi):
    endpoint_name = 'UHCAPI'
    url_extension = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['eligibility']
    url_extension = url_extension + '?payerID={}&providerLastName={}&searchOption={}&dateOfBirth={}&memberId={}&npi={}'.format(
        payer_id, provider_last_name, search_option, date_of_birth, member_id, npi)
    return client.make_api_call(endpoint_name, 'GET', url_extension)

def get_eligibility_v3(client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi, 
                       first_name=None, last_name=None, payer_label=None, payer_name=None, service_start=None, service_end=None, 
                       middle_name=None, gender=None, ssn=None, city=None, state=None, zip=None, group_number=None, 
                       service_type_code=None, provider_first_name=None, tax_id_number=None, provider_name_id=None, 
                       corporate_tax_owner_id=None, corporate_tax_owner_name=None, organization_name=None, 
                       organization_id=None, identify_service_level_deductible=True):

    # Ensure all required parameters have values
    if not all([client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi]):
        raise ValueError("All required parameters must have values: client, payer_id, provider_last_name, search_option, date_of_birth, member_id, npi")

    # Validate payer_id
    valid_payer_ids = ["87726", "06111", "25463", "37602", "39026", "74227", "65088", "81400", "03432", "86050", "86047", "95378", "95467"]
    if payer_id not in valid_payer_ids:
        raise ValueError("Invalid payer_id: {}. Must be one of: {}".format(payer_id, ", ".join(valid_payer_ids)))
    
    endpoint_name = 'UHCAPI'
    url_extension = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['eligibility_v3']
    
    # Construct request body
    body = {
        "memberId": member_id,
        "lastName": last_name,
        "firstName": first_name,
        "dateOfBirth": date_of_birth,
        "payerID": payer_id,
        "payerLabel": payer_label,
        "payerName": payer_name,
        "serviceStart": service_start,
        "serviceEnd": service_end,
        "middleName": middle_name,
        "gender": gender,
        "ssn": ssn,
        "city": city,
        "state": state,
        "zip": zip,
        "groupNumber": group_number,
        "serviceTypeCode": service_type_code,
        "providerLastName": provider_last_name,
        "providerFirstName": provider_first_name,
        "taxIdNumber": tax_id_number,
        "providerNameID": provider_name_id,
        "npi": npi,
        "corporateTaxOwnerID": corporate_tax_owner_id,
        "corporateTaxOwnerName": corporate_tax_owner_name,
        "organizationName": organization_name,
        "organizationID": organization_id,
        "searchOption": search_option,
        "identifyServiceLevelDeductible": identify_service_level_deductible
    }
    
    # Remove None values from the body
    body = {k: v for k, v in body.items() if v is not None}

    # Log the request body
    MediLink_ConfigLoader.log("Request body: {}".format(json.dumps(body, indent=4)), level="DEBUG")

    return client.make_api_call(endpoint_name, 'POST', url_extension, params=None, data=body)

def is_test_mode(client, body, endpoint_type):
    """
    Checks if Test Mode is enabled in the client's configuration and simulates the response if it is.

    :param client: An instance of APIClient
    :param body: The intended request body
    :param endpoint_type: The type of endpoint being accessed ('claim_submission' or 'claim_details')
    :return: A dummy response simulating the real API call if Test Mode is enabled, otherwise None
    """
    if client.config.get("MediLink_Config", {}).get("TestMode", True):
        print("Test Mode is enabled! API Call not executed.")
        print("\nIntended request body:", body)
        MediLink_ConfigLoader.log("Test Mode is enabled! Simulating 1 second delay for API response for {}.".format(endpoint_type), level="INFO")
        time.sleep(1)
        MediLink_ConfigLoader.log("Intended request body: {}".format(body), level="INFO")

        if endpoint_type == 'claim_submission':
            dummy_response = {
                "transactionId": "CS07180420240328013411240",  # This is the tID for the sandbox Claim Acknowledgement endpoint.
                "x12ResponseData": "ISA*00* *00* *ZZ*TEST1234567890 *33*TEST *210101*0101*^*00501*000000001*0*P*:~GS*HC*TEST1234567890*TEST*20210101*0101*1*X*005010X222A1~ST*837*000000001*005010X222A1~BHT*0019*00*00001*20210101*0101*CH~NM1*41*2*TEST SUBMITTER*****46*TEST~PER*IC*TEST CONTACT*TE*1234567890~NM1*40*2*TEST RECEIVER*****46*TEST~HL*1**20*1~NM1*85*2*TEST PROVIDER*****XX*1234567890~N3*TEST ADDRESS~N4*TEST CITY*TEST STATE*12345~REF*EI*123456789~PER*IC*TEST PROVIDER*TE*1234567890~NM1*87*2~N3*TEST ADDRESS~N4*TEST CITY*TEST STATE*12345~HL*2*1*22*0~SBR*P*18*TEST GROUP******CI~NM1*IL*1*TEST PATIENT****MI*123456789~N3*TEST ADDRESS~N4*TEST CITY*TEST STATE*12345~DMG*D8*19800101*M~NM1*PR*2*TEST INSURANCE*****PI*12345~CLM*TESTCLAIM*100***12:B:1*Y*A*Y*Y*P~REF*D9*TESTREFERENCE~HI*ABK:TEST~NM1*DN*1*TEST DOCTOR****XX*1234567890~LX*1~SV1*HC:TEST*100*UN*1***1~DTP*472*RD8*20210101-20210101~REF*6R*TESTREFERENCE~SE*30*000000001~GE*1*1~IEA*1*000000001~",
                "responseType": "dummy_response_837999",
                "message": "Test Mode: Claim validated and sent for further processing"
            }
        elif endpoint_type == 'claim_details':
            dummy_response = {
                "responseType": "dummy_response_277CA-CH",
                "x12ResponseData": "ISA*00* *00*  *ZZ*841162764 *ZZ*UB920086 *240318*0921*^*00501*000165687*0*T*:~GS*HN*841162764*UB920086*20240318*0921*0165687*X*005010X214~ST*277*000000006*005010X214~…………….. SE*116*000000006~GE*1*0165687~IEA*1*000165687~",
                "statuscode": "000",
                "message:": ""
            }
        return dummy_response
    return None

def submit_uhc_claim(client, x12_request_data):
    """
    Submits a UHC claim and retrieves the claim acknowledgement details.

    This function first submits the claim using the provided x12 837p data. If the client is in Test Mode, 
    it returns a simulated response. If Test Mode is not enabled, it submits the claim and then retrieves 
    the claim acknowledgement details using the transaction ID from the initial response.

    :param client: An instance of APIClient
    :param x12_request_data: The x12 837p data as a string
    :return: The final response containing the claim acknowledgement details or a dummy response if in Test Mode
    """
    endpoint_name = 'UHCAPI'
    claim_submission_url = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['claim_submission']
    claim_details_url = client.config['MediLink_Config']['endpoints'][endpoint_name]['additional_endpoints']['claim_details']

    # Headers for the request
    headers = {'Content-Type': 'application/json'} 

    # Request body for claim submission
    claim_body = {'x12RequestData': x12_request_data}

    # Check if Test Mode is enabled and return simulated response if so
    test_mode_response = is_test_mode(client, claim_body, 'claim_submission')
    if test_mode_response:
        return test_mode_response
    
    # Make the API call to submit the claim
    try:
        submission_response = client.make_api_call(endpoint_name, 'POST', claim_submission_url, data=claim_body, headers=headers)
        
        # Extract the transaction ID from the submission response
        transaction_id = submission_response.get('transactionId')
        if not transaction_id:
            raise ValueError("transactionId not found in the submission response")
        
        # Prepare the request body for the claim acknowledgement retrieval
        acknowledgement_body = {'transactionId': transaction_id}

        # Check if Test Mode is enabled and return simulated response if so
        test_mode_response = is_test_mode(client, acknowledgement_body, 'claim_details')
        if test_mode_response:
            return test_mode_response

        # Make the API call to retrieve the claim acknowledgement details
        acknowledgement_response = client.make_api_call(endpoint_name, 'POST', claim_details_url, data=acknowledgement_body, headers=headers)
        return acknowledgement_response

    except Exception as e:
        print("Error during claim processing: {}".format(e))
        raise

if __name__ == "__main__":
    client = APIClient()
    
    # Define a configuration to enable or disable tests
    test_config = {
        'test_fetch_payer_name': True,
        'test_claim_summary': False,
        'test_eligibility': False,
        'test_eligibility_v3': False,
        'test_claim_submission': False,
    }
    
    try:
        api_test_cases = client.config['MediLink_Config']['API Test Case']
        
        # Test 1: Fetch Payer Name
        if test_config.get('test_fetch_payer_name', False):
            try:
                for case in api_test_cases:
                    payer_name = fetch_payer_name_from_api(client, case['payer_id'], client.config)
                    print("*** TEST API: Payer Name: {}".format(payer_name))
            except Exception as e:
                print("*** TEST API: Error in Fetch Payer Name Test: {}".format(e))
        
        # Test 2: Get Claim Summary
        if test_config.get('test_claim_summary', False):
            try:
                for case in api_test_cases:
                    claim_summary = get_claim_summary_by_provider(client, case['provider_tin'], '05/01/2024', '06/23/2024', case['payer_id'])
                    print("TEST API: Claim Summary: {}".format(claim_summary))
            except Exception as e:
                print("TEST API: Error in Claim Summary Test: {}".format(e))
        
        # Test 3: Get Eligibility
        if test_config.get('test_eligibility', False):
            try:
                for case in api_test_cases:
                    eligibility = get_eligibility(client, case['payer_id'], case['provider_last_name'], case['search_option'], 
                                                  case['date_of_birth'], case['member_id'], case['npi'])
                    print("TEST API: Eligibility: {}".format(eligibility))
            except Exception as e:
                print("TEST API: Error in Eligibility Test: {}".format(e))

        # Test 4: Get Eligibility v3
        if test_config.get('test_eligibility_v3', False):
            try:
                for case in api_test_cases:
                    eligibility_v3 = get_eligibility_v3(client, payer_id=case['payer_id'], provider_last_name=case['provider_last_name'], 
                                                        search_option=case['search_option'], date_of_birth=case['date_of_birth'], 
                                                        member_id=case['member_id'], npi=case['npi'])
                    print("TEST API: Eligibility v3: {}".format(eligibility_v3))
            except Exception as e:
                print("TEST API: Error in Eligibility v3 Test: {}".format(e))

        """
        # Example of iterating over multiple patients (if needed)
        patients = [
            {'payer_id': '87726', 'provider_last_name': 'VIDA', 'search_option': 'MemberIDDateOfBirth', 'date_of_birth': '1980-01-01', 'member_id': '123456789', 'npi': '9876543210'},
            {'payer_id': '87726', 'provider_last_name': 'SMITH', 'search_option': 'MemberIDDateOfBirth', 'date_of_birth': '1970-02-02', 'member_id': '987654321', 'npi': '1234567890'},
            # Add more patients as needed
        ]

        for patient in patients:
            try:
                eligibility = get_eligibility(client, patient['payer_id'], patient['provider_last_name'], patient['search_option'], patient['date_of_birth'], patient['member_id'], patient['npi'])
                print("Eligibility for {}: {}".format(patient['provider_last_name'], eligibility))
            except Exception as e:
                print("Error in getting eligibility for {}: {}".format(patient['provider_last_name'], e))
        """
        # Test 5: UHC Claim Submission
        if test_config.get('test_claim_submission', False):
            try:
                x12_request_data = (
                    "ISA*00* *00* *ZZ*BRT219991205 *33*87726 *170417*1344*^*00501*019160001*0*P*:~GS*HC*BRT219991205*B2BRTA*20170417*134455*19160001*X*005010X222A1~ST*837*000000001*005010X222A1~BHT*0019*00*00001*20170417*134455*CH~NM1*41*2*B00099999819*****46*BB2B~PER*IC*NO NAME*TE*1234567890~NM1*40*2*TIGER*****46*87726~HL*1**20*1~NM1*85*2*XYZ ADDRESS*****XX*1073511762~N3*123 CITY#680~N4*STATE*TG*98765~REF*EI*943319804~PER*IC*XYZ ADDRESS*TE*8008738385*TE*9142862043*FX*1234567890~NM1*87*2~N3*PO BOX 277500~N4*STATE*TS*303847000~HL*2*1*22*0~SBR*P*18*701648******CI~NM1*IL*1*FNAME*LNAME****MI*00123456789~N3*2020 CITY~N4*STATE*TG*80001~DMG*D8*19820220*M~NM1*PR*2*PROVIDER XYZ*****PI*87726~\nCLM*TOSRTA-SPL1*471***12:B:1*Y*A*Y*Y*P~REF*D9*H4HZMH0R4P0104~HI*ABK:Z12~NM1*DN*1*DN*SKO****XX*1255589300~LX*1~SV1*HC:73525*471*UN*1***1~DTP*472*RD8*0190701-20190701~REF*6R*2190476543Z1~SE*30*000000001~GE*1*19160001~IEA*1*019160001~"
                )
                response = submit_uhc_claim(client, x12_request_data)
                print("\nTEST API: Claim Submission Response:\n", response)
            except Exception as e:
                print("\nTEST API: Error in Claim Submission Test:\n", e)
    
    except Exception as e:
        print("TEST API: Unexpected Error: {}".format(e))