<?php
/**
 * Open DART 기업코드 동기화 API (프록시 방식)
 * 
 * 멀티테넌시 환경 지원:
 * - 클라이언트의 IP가 아닌 서버의 IP로 Open DART API 호출
 * - Open DART에 등록된 서버 IP만 사용하므로 여러 클라이언트 지원 가능
 * 
 * 동작 흐름:
 * 클라이언트 → 회사 서버 (이 파일) → Open DART API (ZIP 다운로드) → 회사 서버 (압축 해제 및 JSON 변환) → 클라이언트
 */

header('Content-Type: application/json; charset=utf-8');

// 프록시 헬퍼 함수 로드
require_once __DIR__ . '/proxy_helper.php';

// API Key Load
$apiKeyPath = $_SERVER['DOCUMENT_ROOT'] . '/apikey/opendart.txt';
if (!file_exists($apiKeyPath)) {
    echo json_encode(['status' => 'error', 'message' => 'API Key file not found.']);
    exit;
}
$apiKey = trim(file_get_contents($apiKeyPath));

if (empty($apiKey)) {
    echo json_encode(['status' => 'error', 'message' => 'API Key is empty.']);
    exit;
}

// Data Directory
$dataDir = $_SERVER['DOCUMENT_ROOT'] . '/opendart/data';
if (!is_dir($dataDir)) {
    if (!mkdir($dataDir, 0777, true)) {
        echo json_encode(['status' => 'error', 'message' => 'Failed to create data directory.']);
        exit;
    }
}

// Check if ZipArchive extension is available
if (!class_exists('ZipArchive')) {
    echo json_encode(['status' => 'error', 'message' => 'ZipArchive extension is not available. Please enable php_zip extension.']);
    exit;
}

// Open DART URL
$url = "https://opendart.fss.or.kr/api/corpCode.xml?crtfc_key=" . $apiKey;

// Download Zip
$zipFile = $dataDir . '/corpCode.zip';

// Remove old zip file if exists
if (file_exists($zipFile)) {
    @unlink($zipFile);
}

$fp = @fopen($zipFile, 'w+');
if (!$fp) {
    echo json_encode(['status' => 'error', 'message' => 'Failed to create zip file. Check directory permissions.']);
    exit;
}

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 300); // 5 minutes timeout
curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
$effectiveUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
fclose($fp);

if ($httpCode !== 200) {
    $errorContent = '';
    if (file_exists($zipFile)) {
        $errorContent = file_get_contents($zipFile);
        @unlink($zipFile);
    }
    
    // Check if it's an IP access error from Open DART
    if ($errorContent && strpos($errorContent, '접근할 수 없는 IP') !== false || strpos($errorContent, 'Inaccessible IP') !== false) {
        // Parse XML error response
        $xml = @simplexml_load_string($errorContent);
        $errorMessage = '';
        $reportedIP = '';
        
        if ($xml && isset($xml->message)) {
            $errorMessage = (string)$xml->message;
            // Extract IP from message if present
            if (preg_match('/\(([0-9\.]+)\)/', $errorMessage, $matches)) {
                $reportedIP = $matches[1];
            }
        } else {
            $errorMessage = 'IP 접근이 거부되었습니다.';
        }
        
        // Get actual server IP
        $actualIP = getServerPublicIP();
        
        $ipErrorMsg = "Open DART IP 접근 오류: $errorMessage";
        if ($reportedIP) {
            $ipErrorMsg .= "\n\nOpen DART에서 감지한 IP: $reportedIP";
        }
        $ipErrorMsg .= "\n현재 서버의 공인 IP: $actualIP";
        $ipErrorMsg .= "\n\n해결 방법:";
        $ipErrorMsg .= "\n1. Open DART 홈페이지(https://opendart.fss.or.kr)에 로그인";
        $ipErrorMsg .= "\n2. '회원정보 > API 인증키 관리' 메뉴로 이동";
        $ipErrorMsg .= "\n3. '사용IP' 항목에 위의 '현재 서버의 공인 IP'를 등록하거나 수정";
        $ipErrorMsg .= "\n4. 변경 사항 저장 후 몇 분 대기 후 다시 시도";
        
        echo json_encode([
            'status' => 'error', 
            'message' => $ipErrorMsg,
            'error_type' => 'ip_access_denied',
            'reported_ip' => $reportedIP,
            'actual_ip' => $actualIP
        ]);
        exit;
    }
    
    $debugMsg = "HTTP Code: $httpCode";
    if ($curlError) {
        $debugMsg .= ", cURL Error: $curlError";
    }
    if ($effectiveUrl) {
        $debugMsg .= ", Effective URL: $effectiveUrl";
    }
    if ($errorContent) {
        $debugMsg .= ", Content Preview: " . substr($errorContent, 0, 500);
    }
    
    echo json_encode(['status' => 'error', 'message' => 'Failed to download data. ' . $debugMsg]);
    exit;
}

// Verify downloaded file
if (!file_exists($zipFile)) {
    echo json_encode(['status' => 'error', 'message' => 'Downloaded file does not exist.']);
    exit;
}

$fileSize = filesize($zipFile);
if ($fileSize === false || $fileSize < 100) {
    // File too small, likely an error message
    $errorContent = file_get_contents($zipFile);
    @unlink($zipFile);
    echo json_encode(['status' => 'error', 'message' => 'Downloaded file is too small or invalid. Content: ' . substr($errorContent, 0, 500)]);
    exit;
}

// Check if file is actually a ZIP file (check magic bytes)
$handle = fopen($zipFile, 'rb');
$magicBytes = fread($handle, 4);
fclose($handle);

// ZIP file magic bytes: PK\x03\x04 or PK\x05\x06 (empty zip) or PK\x07\x08
if (substr($magicBytes, 0, 2) !== 'PK') {
    $errorContent = file_get_contents($zipFile);
    @unlink($zipFile);
    
    // Check if it's an XML error response from Open DART (IP access error)
    if (strpos($errorContent, '<?xml') !== false && (strpos($errorContent, '접근할 수 없는 IP') !== false || strpos($errorContent, 'Inaccessible IP') !== false)) {
        $xml = @simplexml_load_string($errorContent);
        $errorMessage = '';
        $reportedIP = '';
        
        if ($xml && isset($xml->message)) {
            $errorMessage = (string)$xml->message;
            if (preg_match('/\(([0-9\.]+)\)/', $errorMessage, $matches)) {
                $reportedIP = $matches[1];
            }
        } else {
            $errorMessage = 'IP 접근이 거부되었습니다.';
        }
        
        // Get actual server IP
        $actualIP = getServerPublicIP();
        
        $ipErrorMsg = "Open DART IP 접근 오류: $errorMessage";
        if ($reportedIP) {
            $ipErrorMsg .= "\n\nOpen DART에서 감지한 IP: $reportedIP";
        }
        $ipErrorMsg .= "\n현재 서버의 공인 IP: $actualIP";
        $ipErrorMsg .= "\n\n해결 방법:";
        $ipErrorMsg .= "\n1. Open DART 홈페이지(https://opendart.fss.or.kr)에 로그인";
        $ipErrorMsg .= "\n2. '회원정보 > API 인증키 관리' 메뉴로 이동";
        $ipErrorMsg .= "\n3. '사용IP' 항목에 위의 '현재 서버의 공인 IP'를 등록하거나 수정";
        $ipErrorMsg .= "\n4. 변경 사항 저장 후 몇 분 대기 후 다시 시도";
        
        echo json_encode([
            'status' => 'error', 
            'message' => $ipErrorMsg,
            'error_type' => 'ip_access_denied',
            'reported_ip' => $reportedIP,
            'actual_ip' => $actualIP
        ]);
        exit;
    }
    
    echo json_encode(['status' => 'error', 'message' => 'Downloaded file is not a valid ZIP file. Content: ' . substr($errorContent, 0, 500)]);
    exit;
}

// Unzip
$zip = new ZipArchive;
$zipResult = $zip->open($zipFile);

if ($zipResult !== TRUE) {
    $errorMessages = [
        ZipArchive::ER_OK => 'No error',
        ZipArchive::ER_MULTIDISK => 'Multi-disk zip archives not supported',
        ZipArchive::ER_RENAME => 'Renaming temporary file failed',
        ZipArchive::ER_CLOSE => 'Closing zip archive failed',
        ZipArchive::ER_SEEK => 'Seek error',
        ZipArchive::ER_READ => 'Read error',
        ZipArchive::ER_WRITE => 'Write error',
        ZipArchive::ER_CRC => 'CRC error',
        ZipArchive::ER_ZIPCLOSED => 'Containing zip archive was closed',
        ZipArchive::ER_NOENT => 'No such file',
        ZipArchive::ER_EXISTS => 'File already exists',
        ZipArchive::ER_OPEN => 'Can\'t open file',
        ZipArchive::ER_TMPOPEN => 'Failure to create temporary file',
        ZipArchive::ER_ZLIB => 'Zlib error',
        ZipArchive::ER_MEMORY => 'Memory allocation failure',
        ZipArchive::ER_CHANGED => 'Entry has been changed',
        ZipArchive::ER_COMPNOTSUPP => 'Compression method not supported',
        ZipArchive::ER_EOF => 'Premature EOF',
        ZipArchive::ER_INVAL => 'Invalid argument',
        ZipArchive::ER_NOZIP => 'Not a zip archive',
        ZipArchive::ER_INTERNAL => 'Internal error',
        ZipArchive::ER_INCONS => 'Zip archive inconsistent',
        ZipArchive::ER_REMOVE => 'Can\'t remove file',
        ZipArchive::ER_DELETED => 'Entry has been deleted',
    ];
    
    $errorMsg = isset($errorMessages[$zipResult]) ? $errorMessages[$zipResult] : "Unknown error (Code: $zipResult)";
    echo json_encode(['status' => 'error', 'message' => 'Failed to unzip file. ' . $errorMsg . ' (Error Code: ' . $zipResult . ')']);
    exit;
}

// Extract to data directory
if (!$zip->extractTo($dataDir)) {
    $zip->close();
    echo json_encode(['status' => 'error', 'message' => 'Failed to extract files from zip. Check directory permissions.']);
    exit;
}

$zip->close();

// Parse XML
$xmlFile = $dataDir . '/CORPCODE.xml';
if (!file_exists($xmlFile)) {
    echo json_encode(['status' => 'error', 'message' => 'XML file not found in zip.']);
    exit;
}

$xml = simplexml_load_file($xmlFile);
$jsonArray = [];

foreach ($xml->list as $item) {
    $corp_code = (string)$item->corp_code;
    $corp_name = (string)$item->corp_name;
    $stock_code = (string)$item->stock_code; // optional
    $modify_date = (string)$item->modify_date;

    $jsonArray[] = [
        'corp_code' => $corp_code,
        'corp_name' => $corp_name,
        'stock_code' => $stock_code,
        'modify_date' => $modify_date
    ];
}

// Save to JSON
$jsonFile = $dataDir . '/corp_codes.json';
if (file_put_contents($jsonFile, json_encode($jsonArray, JSON_UNESCAPED_UNICODE))) {
    echo json_encode([
        'status' => 'success', 
        'message' => 'Data synced successfully.', 
        'count' => count($jsonArray),
        'timestamp' => date('Y-m-d H:i:s')
    ]);
} else {
    echo json_encode(['status' => 'error', 'message' => 'Failed to save JSON data.']);
}
?>
