<?php
/**
 * 바로빌 API 설정 파일
 * 
 * ⚠️ 중요: 바로빌은 SOAP 웹서비스를 사용합니다 (REST API가 아님)
 * 
 * 사용 방법:
 * 1. apikey/barobill_cert_key.txt 파일에 CERTKEY(인증서 키)를 저장하세요
 *    - 바로빌 개발자센터에서 인증서 등록 후 발급받은 CERTKEY
 * 
 * 2. apikey/barobill_corp_num.txt 파일에 사업자번호를 저장하세요
 *    - 세금계산서를 발행할 회사의 사업자번호 (하이픈 제외)
 * 
 * 3. 테스트 환경인 경우 apikey/barobill_test_mode.txt 파일에 "test" 또는 "true"를 저장하세요
 */


// load .env file
require_once __DIR__ . '/../../lib/DotEnv.php';
(new DotEnv(__DIR__ . '/../../.env'))->load();

// 인증서 키(CERTKEY) 파일 경로
$documentRoot = getenv('DOCUMENT_ROOT');
$certKeyFile = $documentRoot . '/apikey/barobill_cert_key.txt';
$legacyApiKeyFile = $documentRoot . '/apikey/barobill_api_key.txt'; // 기존 호환성
$corpNumFile = $documentRoot . '/apikey/barobill_corp_num.txt';
$testModeFile = $documentRoot . '/apikey/barobill_test_mode.txt';

// CERTKEY 읽기 (인증서 키)
// 우선순위: barobill_cert_key.txt > barobill_api_key.txt (기존 호환성)
$barobillCertKey = '';
if (file_exists($certKeyFile)) {
    $content = trim(file_get_contents($certKeyFile));
    // 설명 텍스트가 아닌 실제 키만 추출 (대괄호 안의 내용 제외, =로 시작하는 경우 제외)
    if (!empty($content) && !preg_match('/^\[여기에/', $content) && !preg_match('/^=/', $content) && strpos($content, '바로빌 CERTKEY') === false) {
        $barobillCertKey = $content;
    }
}
// 기존 barobill_api_key.txt도 CERTKEY로 사용 (호환성)
if (empty($barobillCertKey) && file_exists($legacyApiKeyFile)) {
    $barobillCertKey = trim(file_get_contents($legacyApiKeyFile));
}

// 사업자번호 읽기
$barobillCorpNum = '';
if (file_exists($corpNumFile)) {
    $content = trim(file_get_contents($corpNumFile));
    // 설명 텍스트가 아닌 실제 사업자번호만 추출 (대괄호 안의 내용 제외)
    if (!empty($content) && !preg_match('/^\[여기에/', $content)) {
        $barobillCorpNum = $content;
        // 하이픈 제거
        $barobillCorpNum = str_replace('-', '', $barobillCorpNum);
    }
}

// 테스트 모드 확인
$isTestMode = false;
if (file_exists($testModeFile)) {
    $testMode = trim(file_get_contents($testModeFile));
    $isTestMode = (strtolower($testMode) === 'test' || strtolower($testMode) === 'true');
}

// 바로빌 SOAP 웹서비스 URL
// 문서 참고: etax/docs/barobill-api-doc/_lib/BaroService_TI.php
$barobillSoapUrl = $isTestMode 
    ? 'https://testws.baroservice.com/TI.asmx?WSDL'  // 테스트 환경
    : 'https://ws.baroservice.com/TI.asmx?WSDL';    // 운영 환경

// SOAP 클라이언트 초기화
$barobillSoapClient = null;
// 테스트 모드에서는 CERTKEY 없이도 SOAP 클라이언트 초기화 시도
if (!empty($barobillCertKey) || $isTestMode) {
    try {
        $barobillSoapClient = new SoapClient($barobillSoapUrl, [
            'trace' => true,
            'encoding' => 'UTF-8',
            'exceptions' => true,
            'connection_timeout' => 30
        ]);
    } catch (Throwable $e) {
        // SOAP 클라이언트 생성 실패 시 null 유지 (Class not found 등 Fatal Error 포함)
        error_log('바로빌 SOAP 클라이언트 생성 실패: ' . $e->getMessage());
    }
}

/**
 * 바로빌 SOAP 웹서비스 호출 함수
 * 
 * @param string $method SOAP 메서드명 (예: 'RegistAndIssueTaxInvoice')
 * @param array $params SOAP 메서드 파라미터
 * @return array 응답 데이터
 */
function callBarobillSOAP($method, $params = []) {
    global $barobillSoapClient, $barobillCertKey, $barobillCorpNum, $isTestMode;
    
    if (!$barobillSoapClient) {
        return [
            'success' => false,
            'error' => '바로빌 SOAP 클라이언트가 초기화되지 않았습니다. CERTKEY를 확인하세요.',
            'error_detail' => [
                'cert_key_file' => getenv('DOCUMENT_ROOT') . '/apikey/barobill_cert_key.txt',
                'soap_url' => $isTestMode ? 'https://testws.baroservice.com/TI.asmx?WSDL' : 'https://ws.baroservice.com/TI.asmx?WSDL'
            ]
        ];
    }
    
    // 테스트 모드가 아닌 경우 CERTKEY 필수
    if (empty($barobillCertKey) && !$isTestMode) {
        return [
            'success' => false,
            'error' => 'CERTKEY가 설정되지 않았습니다. apikey/barobill_cert_key.txt 파일을 확인하세요.'
        ];
    }
    
    // 테스트 모드에서 CERTKEY가 없으면 빈 문자열로 처리 (바로빌 테스트 API가 허용할 수 있음)
    if (empty($barobillCertKey) && $isTestMode) {
        $barobillCertKey = ''; // 빈 문자열로 시도
    }
    
    // 테스트 모드에서 사업자번호가 없으면 더미 사업자번호 사용
    if (empty($barobillCorpNum)) {
        if ($isTestMode) {
            // 테스트 모드: 더미 사업자번호 사용 (바로빌 테스트 API가 허용할 수 있음)
            $barobillCorpNum = '1234567890'; // 테스트용 더미 사업자번호
            error_log('바로빌 테스트 모드: 사업자번호가 없어서 더미 사업자번호를 사용합니다.');
        } else {
            // 운영 모드: 사업자번호 필수
            return [
                'success' => false,
                'error' => '사업자번호가 설정되지 않았습니다. apikey/barobill_corp_num.txt 파일을 확인하세요.'
            ];
        }
    }
    
    try {
        // CERTKEY와 CorpNum을 파라미터에 자동 추가
        if (!isset($params['CERTKEY'])) {
            $params['CERTKEY'] = $barobillCertKey;
        }
        if (!isset($params['CorpNum']) && !isset($params['CorpNum'])) {
            // CorpNum이 파라미터에 없으면 추가 (일부 메서드는 Invoice 내부에 있음)
            if (!isset($params['Invoice']['InvoicerParty']['CorpNum'])) {
                // Invoice 구조가 없으면 최상위에 추가
                if (!isset($params['CorpNum'])) {
                    $params['CorpNum'] = $barobillCorpNum;
                }
            }
        }
        
        // 디버깅: 전달되는 파라미터 로그 (민감 정보는 마스킹)
        error_log('바로빌 API 호출 - Method: ' . $method . ', CorpNum: ' . $barobillCorpNum . ', CERTKEY: ' . (empty($barobillCertKey) ? '(없음)' : substr($barobillCertKey, 0, 10) . '...'));
        
        // SOAP 메서드 호출
        $result = $barobillSoapClient->$method($params);
        
        // 결과에서 Result 속성 추출
        $resultProperty = $method . 'Result';
        if (isset($result->$resultProperty)) {
            $resultData = $result->$resultProperty;
            
            // 결과가 음수면 오류 코드
            if (is_numeric($resultData) && $resultData < 0) {
                // 오류 코드에 따른 메시지 매핑
                $errorMessages = [
                    -11101 => '사업자번호가 설정되지 않았거나 유효하지 않습니다. apikey/barobill_corp_num.txt 파일에 올바른 사업자번호를 입력하세요.',
                    -11102 => 'CERTKEY가 유효하지 않습니다. 바로빌 개발자센터에서 발급받은 CERTKEY를 확인하세요.',
                    -11103 => '인증서가 만료되었거나 유효하지 않습니다.',
                    -26001 => '발행에 필요한 공동인증서가 등록되어 있지 않습니다. 바로빌 웹사이트(https://www.barobill.co.kr)에 로그인하여 공동인증서를 등록하고, CERTKEY와 연결되어 있는지 확인하세요.',
                    -32000 => '알 수 없는 오류가 발생했습니다.',
                ];
                
                $errorMessage = isset($errorMessages[$resultData]) 
                    ? $errorMessages[$resultData] 
                    : '바로빌 API 오류 코드: ' . $resultData;
                
                // GetErrString API로 상세 오류 메시지 조회 시도 (CERTKEY가 있는 경우)
                $detailedError = null;
                if (!empty($barobillCertKey) && $barobillSoapClient) {
                    try {
                        $errStringResult = $barobillSoapClient->GetErrString([
                            'CERTKEY' => $barobillCertKey,
                            'ErrCode' => $resultData
                        ]);
                        if (isset($errStringResult->GetErrStringResult) && $errStringResult->GetErrStringResult >= 0) {
                            $detailedError = $errStringResult->GetErrStringResult;
                        }
                    } catch (Exception $e) {
                        // GetErrString 호출 실패 시 무시
                    }
                }
                
                return [
                    'success' => false,
                    'error' => $errorMessage,
                    'error_code' => $resultData,
                    'error_detail' => $detailedError ? "상세 오류: " . $detailedError : null,
                    'soap_request' => $barobillSoapClient->__getLastRequest(),
                    'soap_response' => $barobillSoapClient->__getLastResponse()
                ];
            }
            
            return [
                'success' => true,
                'data' => $resultData,
                'soap_request' => $barobillSoapClient->__getLastRequest(),
                'soap_response' => $barobillSoapClient->__getLastResponse()
            ];
        }
        
        return [
            'success' => true,
            'data' => $result,
            'soap_request' => $barobillSoapClient->__getLastRequest(),
            'soap_response' => $barobillSoapClient->__getLastResponse()
        ];
        
    } catch (SoapFault $e) {
        return [
            'success' => false,
            'error' => 'SOAP 오류: ' . $e->getMessage(),
            'error_code' => $e->getCode(),
            'error_detail' => [
                'fault_code' => $e->faultcode ?? null,
                'fault_string' => $e->faultstring ?? null,
                'soap_request' => $barobillSoapClient ? $barobillSoapClient->__getLastRequest() : null,
                'soap_response' => $barobillSoapClient ? $barobillSoapClient->__getLastResponse() : null
            ]
        ];
    } catch (Throwable $e) {
        return [
            'success' => false,
            'error' => 'API 호출 오류 (치명적): ' . $e->getMessage(),
            'error_detail' => [
                'exception_type' => get_class($e),
                'soap_request' => $barobillSoapClient ? $barobillSoapClient->__getLastRequest() : null,
                'soap_response' => $barobillSoapClient ? $barobillSoapClient->__getLastResponse() : null
            ]
        ];
    }
}

/**
 * 바로빌 세금계산서 발행 (저장 + 발급)
 * 
 * 문서 참고: etax/docs/barobill-api-doc/TAXINVOICE/RegistAndIssueTaxInvoice.php
 * 
 * @param array $invoiceData 세금계산서 데이터
 * @return array 응답 데이터
 */
function issueTaxInvoice($invoiceData) {
    global $barobillCorpNum;
    
    // MgtKey 생성 (관리번호) - 유니크한 키 생성
    $mgtKey = $invoiceData['issueKey'] ?? 'MGT' . date('YmdHis') . rand(1000, 9999);
    
    // 공급가액, 부가세, 합계 계산
    $supplyAmt = 0;
    $vat = 0;
    foreach ($invoiceData['items'] ?? [] as $item) {
        $itemSupplyAmt = floatval($item['supplyAmt'] ?? 0);
        $itemVat = floatval($item['vat'] ?? 0);
        $supplyAmt += $itemSupplyAmt;
        $vat += $itemVat;
    }
    $total = $supplyAmt + $vat;
    
    // TaxType 결정: 부가세가 0원이면 영세(2) 또는 면세(3)로 설정
    // 과세(1)는 부가세가 0원 이상이어야 함
    $taxType = 1; // 기본값: 과세
    if ($vat == 0) {
        // 부가세가 0원이면 영세로 설정 (또는 면세로 설정 가능)
        $taxType = 2; // 2: 영세
    }
    
    // 바로빌 SOAP API 스펙에 맞게 데이터 변환
    // 문서 참고: etax/docs/barobill-api-doc/TAXINVOICE/RegistAndIssueTaxInvoice.php
    $taxInvoice = [
        'IssueDirection' => 1, // 1: 정발행, 2: 역발행
        'TaxInvoiceType' => 1, // 1: 세금계산서, 2: 계산서
        'ModifyCode' => '', // 수정사유코드 (신규발행시 빈값)
        'TaxType' => $taxType, // 1: 과세, 2: 영세, 3: 면세 (부가세가 0이면 영세로 설정)
        'TaxCalcType' => 1, // 1: 소계합계, 2: 항목합계
        'PurposeType' => 2, // 1: 영수, 2: 청구, 3: 없음
        'WriteDate' => date('Ymd', strtotime($invoiceData['writeDate'] ?? date('Y-m-d'))), // 작성일자 (YYYYMMDD)
        'AmountTotal' => number_format($supplyAmt, 0, '', ''), // 공급가액 합계
        'TaxTotal' => number_format($vat, 0, '', ''), // 부가세 합계
        'TotalAmount' => number_format($total, 0, '', ''), // 합계금액
        'Cash' => '0', // 현금
        'ChkBill' => '0', // 어음
        'Note' => '0', // 외상
        'Credit' => number_format($total, 0, '', ''), // 외상미수금 (합계금액과 일치해야 함)
        'Remark1' => $invoiceData['memo'] ?? '', // 비고1
        'Remark2' => '', // 비고2
        'Remark3' => '', // 비고3
        'Kwon' => '', // 권
        'Ho' => '', // 호
        'SerialNum' => '', // 일련번호
        'InvoicerParty' => [
            'MgtNum' => $mgtKey, // 관리번호
            'CorpNum' => $barobillCorpNum, // 발행자 사업자번호 (CERTKEY와 연결된 사업자번호 사용)
            'TaxRegID' => '', // 종사업장번호
            'CorpName' => $invoiceData['supplierName'] ?? '', // 상호
            'CEOName' => $invoiceData['supplierCeo'] ?? '', // 대표자명
            'Addr' => $invoiceData['supplierAddr'] ?? '', // 주소
            'BizType' => '', // 업태
            'BizClass' => '', // 종목
            'ContactID' => $invoiceData['supplierContactId'] ?? 'cbx0913', // 담당자 아이디 (바로빌 웹페이지 ID)
            'ContactName' => $invoiceData['supplierContact'] ?? '', // 담당자명
            'TEL' => $invoiceData['supplierTel'] ?? '', // 전화번호
            'HP' => '', // 휴대폰
            'Email' => $invoiceData['supplierEmail'] ?? '', // 이메일
        ],
        'InvoiceeParty' => [
            'MgtNum' => '', // 관리번호
            'CorpNum' => str_replace('-', '', $invoiceData['recipientBizno'] ?? ''), // 사업자번호
            'TaxRegID' => '', // 종사업장번호
            'CorpName' => $invoiceData['recipientName'] ?? '', // 상호
            'CEOName' => $invoiceData['recipientCeo'] ?? '', // 대표자명
            'Addr' => $invoiceData['recipientAddr'] ?? '', // 주소
            'BizType' => '', // 업태
            'BizClass' => '', // 종목
            'ContactID' => '', // 담당자 아이디
            'ContactName' => $invoiceData['recipientContact'] ?? '', // 담당자명
            'TEL' => $invoiceData['recipientTel'] ?? '', // 전화번호
            'HP' => '', // 휴대폰
            'Email' => $invoiceData['recipientEmail'] ?? '', // 이메일
        ],
        'BrokerParty' => [], // 위수탁 거래시에만 사용
        'TaxInvoiceTradeLineItems' => [
            'TaxInvoiceTradeLineItem' => []
        ]
    ];
    
    // 품목 데이터 변환
    foreach ($invoiceData['items'] ?? [] as $item) {
        $taxInvoice['TaxInvoiceTradeLineItems']['TaxInvoiceTradeLineItem'][] = [
            'PurchaseExpiry' => '', // 공제기한
            'Name' => $item['name'] ?? '', // 품명
            'Information' => $item['spec'] ?? '', // 규격
            'ChargeableUnit' => $item['qty'] ?? '1', // 수량
            'UnitPrice' => number_format(floatval($item['unitPrice'] ?? 0), 0, '', ''), // 단가
            'Amount' => number_format(floatval($item['supplyAmt'] ?? 0), 0, '', ''), // 공급가액
            'Tax' => number_format(floatval($item['vat'] ?? 0), 0, '', ''), // 부가세
            'Description' => $item['description'] ?? '', // 비고
        ];
    }
    
    // SOAP 메서드 호출
    $params = [
        'CorpNum' => $barobillCorpNum, // 발행자 사업자번호
        'Invoice' => $taxInvoice,
        'SendSMS' => false, // SMS 발송 여부
        'ForceIssue' => false, // 강제발행 여부
        'MailTitle' => '', // 이메일 제목
    ];
    
    return callBarobillSOAP('RegistAndIssueTaxInvoice', $params);
}

/**
 * 바로빌 세금계산서 조회
 * 
 * 문서 참고: etax/docs/barobill-api-doc/TAXINVOICE/GetTaxInvoice.php
 * 
 * @param string $mgtKey 관리번호 (MgtKey)
 * @return array 응답 데이터
 */
function getTaxInvoice($mgtKey) {
    global $barobillCorpNum;
    
    $params = [
        'CorpNum' => $barobillCorpNum,
        'MgtKey' => $mgtKey
    ];
    
    return callBarobillSOAP('GetTaxInvoice', $params);
}

/**
 * 바로빌 세금계산서 상태 조회
 * 
 * 문서 참고: etax/docs/barobill-api-doc/TAXINVOICE/GetTaxInvoiceStateEX.php
 * 
 * @param string $mgtKey 관리번호 (MgtKey)
 * @return array 응답 데이터
 */
function getTaxInvoiceState($mgtKey) {
    global $barobillCorpNum;
    
    $params = [
        'CorpNum' => $barobillCorpNum,
        'MgtKey' => $mgtKey
    ];
    
    return callBarobillSOAP('GetTaxInvoiceStateEX', $params);
}

/**
 * 바로빌 세금계산서 국세청 전송
 * 
 * 문서 참고: etax/docs/barobill-api-doc/TAXINVOICE/SendToNTS.php
 * 
 * @param string $mgtKey 관리번호 (MgtKey)
 * @return array 응답 데이터
 */
function sendToNTS($mgtKey) {
    global $barobillCorpNum;
    
    $params = [
        'CorpNum' => $barobillCorpNum,
        'MgtKey' => $mgtKey
    ];
    
    return callBarobillSOAP('SendToNTS', $params);
}

?>

