<?php
// usage:
//   php __CRON/cron_ikev2_consistency_check_cli.php
//   php __CRON/cron_ikev2_consistency_check_cli.php --limit=100
//   php __CRON/cron_ikev2_consistency_check_cli.php --od_id=2026031215535054
//   php __CRON/cron_ikev2_consistency_check_cli.php --apply-fix --limit=50

@chdir(__DIR__ . '/..');

include_once(__DIR__ . '/../_common.php');
include_once(G5_PATH . '/mylib/ikev2_provision.lib.php');

$limit = 50;
$onlyOdId = '';
$applyFix = false;

foreach ($argv as $arg) {
    if (strpos($arg, '--limit=') === 0) {
        $v = (int)substr($arg, 8);
        if ($v > 0) {
            $limit = $v;
        }
        continue;
    }
    if (strpos($arg, '--od_id=') === 0) {
        $onlyOdId = trim((string)substr($arg, 8));
        continue;
    }
    if ($arg === '--apply-fix') {
        $applyFix = true;
        continue;
    }
}

if (!isset($g5['g5_shop_cart_table'], $g5['g5_shop_item_table'], $g5['g5_shop_order_table'])) {
    echo json_encode(array(
        'ok' => false,
        'error' => 'missing_shop_tables',
        'ts' => date('Y-m-d H:i:s')
    ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    exit(1);
}

$where = array();
$where[] = "o.od_status IN ('입금','완료')";
$where[] = "(i.it_spec_sales_type = 'vpn-mall' OR i.ca_id LIKE '30%' OR i.ca_id LIKE '40%' OR i.ca_id2 LIKE '30%' OR i.ca_id2 LIKE '40%' OR i.ca_id3 LIKE '30%' OR i.ca_id3 LIKE '40%')";
if ($onlyOdId !== '') {
    $where[] = "c.od_id = '" . sql_escape_string($onlyOdId) . "'";
}

$sql = "SELECT c.ct_id, c.od_id, c.it_id, c.mb_id, c.ct_status,
               i.it_name, i.it_spec_remote_sw, i.it_spec_sales_type, i.it_spec_buyer_mb_id,
               o.mb_id AS od_mb_id
          FROM {$g5['g5_shop_cart_table']} c
     LEFT JOIN {$g5['g5_shop_item_table']} i ON c.it_id = i.it_id
     LEFT JOIN {$g5['g5_shop_order_table']} o ON c.od_id = o.od_id
         WHERE " . implode(' AND ', $where) . "
      ORDER BY c.ct_id DESC
         LIMIT " . (int)$limit;

$res = sql_query($sql, false);

$checked = 0;
$inconsistent = 0;
$fixApplied = 0;
$rowsOut = array();
$nowTs = time();

for ($i = 0; $row = sql_fetch_array($res); $i++) {
    if (!is_array($row)) {
        continue;
    }

    $targets = vpnlink_ikev2_extract_targets_from_item($row);
    if (count($targets) < 1) {
        continue;
    }

    $checked++;

    $odId = trim((string)$row['od_id']);
    $itId = trim((string)$row['it_id']);
    $ctId = (int)$row['ct_id'];
    $memberId = trim((string)$row['od_mb_id']);
    if ($memberId === '') {
        $memberId = trim((string)$row['mb_id']);
    }
    if ($memberId === '') {
        $memberId = trim((string)$row['it_spec_buyer_mb_id']);
    }

    $expectedExpire = vpnlink_ikev2_resolve_order_expire($odId, $itId, $ctId);
    $expectedExpireTs = false;
    $hasRemainingExpire = false;
    if ($expectedExpire !== '') {
        $expectedExpireTs = strtotime($expectedExpire);
        if ($expectedExpireTs !== false && $expectedExpireTs > 0 && $expectedExpireTs > $nowTs) {
            $hasRemainingExpire = true;
        }
    }

    $itemIssues = array();
    $targetChecks = array();

    foreach ($targets as $t) {
        $serverName = trim((string)$t['server_ip']);
        $userId = trim((string)$t['vpn_user_id']);
        $userPw = trim((string)$t['vpn_user_pw']);

        if ($serverName === '' || $memberId === '') {
            $itemIssues[] = 'missing_member_or_server';
            continue;
        }

                $vpnWhere = "mb_id = '" . sql_escape_string($memberId) . "'"
                                    . " AND server_name = '" . sql_escape_string($serverName) . "'";
                if ($userId !== '') {
                    $vpnWhere .= " AND vpn_user_id = '" . sql_escape_string($userId) . "'";
                }

                $vpnRow = sql_fetch("SELECT no, mb_id, vpn_user_id, vpn_user_pwd, vpn_id_expire, server_name, enable
                                                            FROM vpnid_list
                                                         WHERE {$vpnWhere}
                                                         ORDER BY no DESC
                                                         LIMIT 1", false);

        $issues = array();
        if (!is_array($vpnRow) || !isset($vpnRow['no'])) {
            $issues[] = 'vpnid_missing';
        } else {
            if ($hasRemainingExpire && (int)$vpnRow['enable'] !== 1 && trim((string)$row['ct_status']) !== '취소' && trim((string)$row['ct_status']) !== '반품') {
                $issues[] = 'vpnid_disabled';
            }

            $actualExpire = trim((string)$vpnRow['vpn_id_expire']);
            if ($expectedExpire !== '' && $actualExpire !== '') {
                // [FIX 2026-05-08]
                // 누적 연장 정책에서는 실제 만료일이 기대값보다 "같거나 늦은" 경우 정상이다.
                // (과거 주문 재검증 시 exact-equal 비교는 false positive를 유발)
                $actualExpireTs = strtotime($actualExpire);
                if ($expectedExpireTs !== false && $expectedExpireTs > 0 && $actualExpireTs !== false && $actualExpireTs > 0) {
                    if ($actualExpireTs < $expectedExpireTs) {
                        $issues[] = 'expire_mismatch';
                    }
                } else if ($actualExpire !== $expectedExpire) {
                    // 파싱 불가 시에만 보수적으로 문자열 비교 유지
                    $issues[] = 'expire_mismatch';
                }
            }

            $actualPw = trim((string)$vpnRow['vpn_user_pwd']);
            if ($userPw !== '' && $actualPw !== '' && $actualPw !== $userPw) {
                $issues[] = 'password_mismatch';
            }
        }

        $q = sql_fetch("SELECT final_status, status, attempt_count, fail_count, updated_at
                         FROM app_ikev2_provision_queue
                        WHERE od_id = '" . sql_escape_string($odId) . "'
                          AND it_id = '" . sql_escape_string($itId) . "'
                          AND server_ip = '" . sql_escape_string($serverName) . "'
                          AND vpn_user_id = '" . sql_escape_string($userId) . "'
                        ORDER BY queue_id DESC
                        LIMIT 1", false);

        $isActiveTarget = true;
        if ($expectedExpire !== '') {
            if ($expectedExpireTs !== false && $expectedExpireTs > 0 && $expectedExpireTs <= $nowTs) {
                $isActiveTarget = false;
            }
        }

        if ($isActiveTarget) {
            if (!is_array($q) || !isset($q['final_status'])) {
                $issues[] = 'provision_queue_missing';
            } else if (trim((string)$q['final_status']) !== 'success') {
                $issues[] = 'provision_not_success';
            }
        }

        if (count($issues) > 0) {
            $itemIssues = array_merge($itemIssues, $issues);
        }

        $targetChecks[] = array(
            'server_name' => $serverName,
            'vpn_user_id' => $userId,
            'issues' => array_values(array_unique($issues))
        );
    }

    $itemIssues = array_values(array_unique($itemIssues));
    if (count($itemIssues) > 0) {
        $inconsistent++;

        $fix = null;
        if ($applyFix) {
            $syncRet = vpnlink_vpnid_sync_upsert_by_order($odId, $itId, 'consistency_check_cli_fix');
            $queueRet = vpnlink_ikev2_queue_order($odId, 'consistency_check_cli_requeue');
            $fix = array(
                'vpnid_sync' => $syncRet,
                'ikev2_requeue' => $queueRet
            );
            $fixApplied++;
        }

        $rowsOut[] = array(
            'od_id' => $odId,
            'it_id' => $itId,
            'ct_id' => $ctId,
            'member_id' => $memberId,
            'issues' => $itemIssues,
            'expected_expire' => $expectedExpire,
            'targets' => $targetChecks,
            'fix' => $fix
        );
    }
}

echo json_encode(array(
    'ok' => true,
    'checked_items' => $checked,
    'inconsistent_items' => $inconsistent,
    'apply_fix' => $applyFix,
    'fix_applied' => $fixApplied,
    'limit' => $limit,
    'od_id_filter' => $onlyOdId,
    'rows' => $rowsOut,
    'ts' => date('Y-m-d H:i:s')
), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
