<?php

namespace App\Services;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;

class OptumPreServiceEligibilityClient
{
    private Client $http;

    public function __construct(?Client $http = null)
    {
        $this->http = $http ?: new Client();
    }

    public function checkEligibility(array $input, string $providerTaxId, string $environment = 'sandbox'): array
    {
        $cfg = config('optum.' . $environment);
        $baseUrl = $cfg['base_url'] ?? null;
        $clientId = $cfg['client_id'] ?? null;
        $clientSecret = $cfg['client_secret'] ?? null;
        Log::info('clientSecret: ' . $clientSecret);
        if (!$baseUrl || !$clientId || !$clientSecret) {
            throw new \RuntimeException("Optum config missing for environment: {$environment}");
        }

        $tokenData = $this->getToken($baseUrl, $clientId, $clientSecret);
        $accessToken = $tokenData['access_token'] ?? null;
        if (!$accessToken) {
            throw new \RuntimeException('Access token not received.');
        }

        $requestPayload = [
            'variables' => [
                'input' => $input,
            ],
            'query' => 'query CheckEligibility($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationshipCode dependentSequenceNumber individualRelationship { code description } relationshipType { code description } } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription groupName address { type street1 street2 city state country zip zip4 } stateOfIssueCode productType productId productCode payerId lineOfBusinessCode governmentProgramCode coverageType insuranceTypeCode insuranceType paidThroughDate consumerName } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId healthInsuranceExchangeId } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } } primaryCarePhysician { lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } affiliateHospitalName providerGroupName pcpSpeciality pcpStartDate pcpEndDate providerNPI providerTIN acoNetworkDescription acoNetworkId pcpHistoryList { lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } affiliateHospitalName providerGroupName pcpSpeciality pcpStartDate pcpEndDate providerNPI providerTIN acoNetworkDescription acoNetworkId } } coordinationOfBenefits { coordinationOfBenefitDetails { member { id name } policy { policyNumber groupNumber coverageType insuranceTypeCode medicareEntitlementType medicareEntitlementReason effectiveDate terminationDate verificationDate } payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } cobUpdateInformation { cobUpdateMessage cobLastVerifiedDate } disclaimer } idCardImages { side content contentType } providerNetwork { status tier speciality } serviceLevels { family { networkStatus services { service serviceCode serviceDate status planAmount remainingAmount metYearToDateAmount message { coPay { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList { placeOfService copay service startDate endDate messages } coInsuranceList { placeOfService coinsurancePercent service messages startDate endDate } } } } individual { networkStatus services { service serviceCode serviceDate status planAmount remainingAmount metYearToDateAmount message { coPay { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList { placeOfService copay service startDate endDate messages } coInsuranceList { placeOfService coinsurancePercent service messages startDate endDate } } } } vendorServices { key vendorName url phone serviceDescription serviceTypeCode } } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationshipCode dependentSequenceNumber individualRelationship { code description } relationshipType { code description } } additionalInfo { fundingType fundingArrangementDescription businessSegment sizeDefinitionDescription revenueArrangementDescription hsa cdhp cmsHId cmsPackageBenefitPlanCode cmsSegmentId cmsContractId benefitPlanId virtualVisit designatedVirtualClinicNetwork medicaidVariableCode hraBalance hraMessage hraUnavailableMessage graceMessageByState gracePaidThrough gracePeriodMonth medicareGuidelines medicareEntitlementReason medicaidEntitlement { waiverLiabilityList { startDate endDate amount amountFrequency remainingAmount metYtdAmount } patientLiabilityList { startDate endDate amount amountFrequency remainingAmount metYtdAmount } transferOfPropertyPenaltyPeriod { startDate endDate } medicaidVariables { hcfaStatus cobraIndicator spendDownTotal spendDownMet spendDownInd effectiveDate terminationDate } } } } } }',
        ];
        Log::info('requestPayload', ['requestPayload' => $requestPayload,'providerTaxId'=>$providerTaxId,'token'=>$accessToken]);
        try {
            $resp = $this->http->post($baseUrl . '/oihub/eligibility/v1/pre-service/member', [
                'headers' => [
                    'Accept' => 'application/json',
                    'Authorization' => 'Bearer ' . $accessToken,
                    'Content-Type' => 'application/json',
                    'providerTaxId' => $providerTaxId,
                ],
                'json' => $requestPayload,
            ]);

            return [
                'ok' => true,
                'request' => $requestPayload,
                'headers' => $resp->getHeaders(),
                'body' => json_decode($resp->getBody()->getContents(), true),
                'message'=>'success'
            ];
        } catch (RequestException $e) {
            $body = null;
            $headers = [];

            if ($e->hasResponse()) {
                $headers = $e->getResponse()->getHeaders();
                $body = json_decode($e->getResponse()->getBody()->getContents(), true);
            }

            return [
                'ok' => false,
                'request' => $requestPayload,
                //'headers' => $headers,
                'body' => $body ?: ['message' => $e->getMessage()],
                'message'=>@$body['message']
            ];
        }
    }

    private function getToken(string $baseUrl, string $clientId, string $clientSecret): array
    {
        $resp = $this->http->post($baseUrl . '/apip/auth/sntl/v1/token', [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/x-www-form-urlencoded',
            ],
            'form_params' => [
                'grant_type' => 'client_credentials',
                'client_id' => $clientId,
                'client_secret' => $clientSecret,
            ],
        ]);

        return json_decode($resp->getBody()->getContents(), true) ?: [];
    }

    private static function eligibilityQuery(): string
    {
        // Exact (tested) GraphQL query from optum-eligibility.php, stored safely.
        return 'query CheckEligibility($input: EligibilityInput!) { checkEligibility(input: $input) { eligibility { eligibilityInfo { trnId member { memberId firstName lastName middleName suffix dateOfBirth gender relationshipCode dependentSequenceNumber individualRelationship { code description } relationshipType { code description } } contact { addresses { type street1 street2 city state country zip zip4 } } insuranceInfo { policyNumber eligibilityStartDate eligibilityEndDate planStartDate planEndDate policyStatus planTypeDescription groupName address { type street1 street2 city state country zip zip4 } stateOfIssueCode productType productId productCode payerId lineOfBusinessCode governmentProgramCode coverageType insuranceTypeCode insuranceType paidThroughDate consumerName } associatedIds { alternateId medicaidRecipientId exchangeMemberId alternateSubscriberId hicNumber mbiNumber subscriberMemberFacingIdentifier survivingSpouseId subscriberId memberReplacementId legacyMemberId healthInsuranceExchangeId } planLevels { level family { networkStatus planAmount planAmountFrequency remainingAmount } individual { networkStatus planAmount planAmountFrequency remainingAmount } } delegatedInfo { entity payerId contact { phone fax email } addresses { type street1 street2 city state country zip zip4 } } } primaryCarePhysician { lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } affiliateHospitalName providerGroupName pcpSpeciality pcpStartDate pcpEndDate providerNPI providerTIN acoNetworkDescription acoNetworkId pcpHistoryList { lastName firstName middleName phoneNumber address { type street1 street2 city state country zip zip4 } affiliateHospitalName providerGroupName pcpSpeciality pcpStartDate pcpEndDate providerNPI providerTIN acoNetworkDescription acoNetworkId } } coordinationOfBenefits { coordinationOfBenefitDetails { member { id name } policy { policyNumber groupNumber coverageType insuranceTypeCode medicareEntitlementType medicareEntitlementReason effectiveDate terminationDate verificationDate } payer { name phoneNumber address { type street1 street2 city state country zip zip4 } } cobPrimacy { indicator description message } } cobUpdateInformation { cobUpdateMessage cobLastVerifiedDate } disclaimer } idCardImages { side content contentType } providerNetwork { status tier speciality } serviceLevels { family { networkStatus services { service serviceCode serviceDate status planAmount remainingAmount metYearToDateAmount message { coPay { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList { placeOfService copay service startDate endDate messages } coInsuranceList { placeOfService coinsurancePercent service messages startDate endDate } } } } individual { networkStatus services { service serviceCode serviceDate status planAmount remainingAmount metYearToDateAmount message { coPay { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coInsurance { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } deductible { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsAllowed { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } benefitsRemaining { isSingleMessageDetail isViewDetail messages subMessages { service status copay msg startDate endDate minCopay minCopayMsg maxCopay maxCopayMsg isPrimaryIndicator } limitationInfo { lmtPeriod lmtType lmtOccurPerPeriod lmtDollarPerPeriod messages } isMultipleCopaysFound isMultipleCoinsuranceFound } coPayList { placeOfService copay service startDate endDate messages } coInsuranceList { placeOfService coinsurancePercent service messages startDate endDate } } } } vendorServices { key vendorName url phone serviceDescription serviceTypeCode } } otherBeneficiaries { memberId firstName lastName middleName suffix dateOfBirth gender relationshipCode dependentSequenceNumber individualRelationship { code description } relationshipType { code description } } additionalInfo { fundingType fundingArrangementDescription businessSegment sizeDefinitionDescription revenueArrangementDescription hsa cdhp cmsHId cmsPackageBenefitPlanCode cmsSegmentId cmsContractId benefitPlanId virtualVisit designatedVirtualClinicNetwork medicaidVariableCode hraBalance hraMessage hraUnavailableMessage graceMessageByState gracePaidThrough gracePeriodMonth medicareGuidelines medicareEntitlementReason medicaidEntitlement { waiverLiabilityList { startDate endDate amount amountFrequency remainingAmount metYtdAmount } patientLiabilityList { startDate endDate amount amountFrequency remainingAmount metYtdAmount } transferOfPropertyPenaltyPeriod { startDate endDate } medicaidVariables { hcfaStatus cobraIndicator spendDownTotal spendDownMet spendDownInd effectiveDate terminationDate } } } } } }';
    }
}

