<?php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { exit; }

/*
 * DoorKar Payment API - SEP/Saman
 * نکته مهم:
 * فایل sep_redirect.php و sep_callback.php باید در مسیر public_html/doorkar باشند.
 * آدرس ثبت‌شده نزد سپ:
 * https://pnartl.ir/doorkar/sep_callback.php
 */

$DB_HOST = 'localhost';
$DB_NAME = 'pnartli1_doorkar';
$DB_USER = 'pnartli1_doorkar';
$DB_PASS = 'V[B5S(1gO,OIqPvz';

$PAYMENT_PUBLIC_BASE_URL = 'https://pnartl.ir/doorkar';
$SEP_CALLBACK_URL = $PAYMENT_PUBLIC_BASE_URL . '/sep_callback.php';
$SEP_REDIRECT_URL = $PAYMENT_PUBLIC_BASE_URL . '/sep_redirect.php';

$SEP_TERMINAL_ID = '15546670';
$SEP_TOKEN_URL = 'https://sep.shaparak.ir/onlinepg/onlinepg';
$SEP_DEFAULT_GATEWAY_URL = 'https://sep.shaparak.ir/OnlinePG/OnlinePG';
$SEP_AMOUNT_MULTIPLIER = 10; // مبلغ داخلی تومان است؛ سپ معمولاً ریال می‌خواهد. اگر پنل پذیرنده تومان خواست، 1 کن.
$MIN_BLU_PAYMENT_AMOUNT_TOMAN = 1000; // بلوپی/بلو بانک برای پرداخت‌های خیلی کوچک خطای «موردی برای پرداخت وجود ندارد» می‌دهد.

function respond($success, $data = [], $message = '') {
    echo json_encode(
        array_merge(['success' => $success, 'message' => $message], $data),
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    );
    exit;
}

function payment_debug_log($title, $data = []) {
    if (isset($data['token'])) {
        $data['token'] = substr((string)$data['token'], 0, 6) . '***';
    }
    if (isset($data['sep_json']['token'])) {
        $data['sep_json']['token'] = substr((string)$data['sep_json']['token'], 0, 6) . '***';
    }
    $line = '[' . date('Y-m-d H:i:s') . '] ' . $title . ' ' . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
    @file_put_contents(__DIR__ . '/payment_debug.log', $line, FILE_APPEND);
}

function input_data() {
    $raw = file_get_contents('php://input');
    $json = json_decode($raw, true);
    return is_array($json) ? $json : $_POST;
}

function fetch_one(PDO $pdo, $sql, $params = []) {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    return is_array($row) ? $row : null;
}

function table_column_exists(PDO $pdo, $table, $column) {
    try {
        $stmt = $pdo->prepare("SHOW COLUMNS FROM `$table` LIKE ?");
        $stmt->execute([$column]);
        return $stmt->fetchColumn() !== false;
    } catch (Throwable $e) {
        return false;
    }
}

function normalize_payment_method($method) {
    $method = trim((string)$method);
    return in_array($method, ['sep_direct', 'blu_bank'], true) ? $method : 'sep_direct';
}

function verify_session(PDO $pdo, $userId, $apiToken) {
    if ($userId <= 0 || trim((string)$apiToken) === '') return null;

    $stmt = $pdo->prepare("SELECT id, user_type, mobile_number, api_token_hash FROM users WHERE id=? LIMIT 1");
    $stmt->execute([$userId]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    if (!$user) return null;

    $stored = trim((string)($user['api_token_hash'] ?? ''));
    if ($stored === '') return null;

    $sha = hash('sha256', $apiToken);
    if (hash_equals($stored, $sha) || password_verify($apiToken, $stored)) return $user;

    return null;
}

function normalize_mobile($mobile) {
    $m = preg_replace('/\D+/', '', (string)$mobile);
    if (strpos($m, '98') === 0 && strlen($m) === 12) $m = substr($m, 2);
    if (strpos($m, '0') === 0 && strlen($m) === 11) $m = substr($m, 1);
    return $m;
}

function create_res_num($projectId) {
    return 'DKP' . $projectId . date('ymdHis') . random_int(100, 999);
}

function request_sep_token($payload, $tokenUrl) {
    $headers = [];
    $ch = curl_init($tokenUrl);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Accept: application/json'],
        CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADERFUNCTION => function($curl, $header) use (&$headers) {
            $len = strlen($header);
            $parts = explode(':', $header, 2);
            if (count($parts) === 2) {
                $headers[strtolower(trim($parts[0]))] = trim($parts[1]);
            }
            return $len;
        },
        CURLOPT_CONNECTTIMEOUT => 15,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_USERAGENT => 'DoorKar-Merchant/1.0',
        CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
    ]);

    $body = curl_exec($ch);
    $error = curl_error($ch);
    $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $json = json_decode((string)$body, true);
    return [
        'http_code' => $httpCode,
        'body' => $body,
        'json' => is_array($json) ? $json : null,
        'error' => $error,
        'headers' => $headers
    ];
}

try {
    $pdo = new PDO(
        "mysql:host={$DB_HOST};dbname={$DB_NAME};charset=utf8mb4",
        $DB_USER,
        $DB_PASS,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );
} catch (Throwable $e) {
    payment_debug_log('db_connection_failed', ['error' => $e->getMessage()]);
    respond(false, [], 'اتصال به دیتابیس برقرار نشد');
}

try {
    $input = input_data();
    $action = trim((string)($input['action'] ?? ''));
    $userId = (int)($input['user_id'] ?? 0);
    $apiToken = trim((string)($input['api_token'] ?? ''));

    $user = verify_session($pdo, $userId, $apiToken);
    if (!$user) respond(false, [], 'نشست ورود معتبر نیست؛ دوباره وارد حساب شو');

    if ($action === 'start_project_payment') {
        $projectId = (int)($input['project_id'] ?? 0);
        if ($projectId <= 0) respond(false, [], 'شناسه پروژه معتبر نیست');
        $paymentMethod = normalize_payment_method($input['payment_method'] ?? 'sep_direct');
        $gatewayMode = $paymentMethod === 'blu_bank' ? 'neo' : 'direct';
        $returnScreen = trim((string)($input['return_screen'] ?? $input['source_screen'] ?? 'create_project'));
        if (!in_array($returnScreen, ['create_project', 'project_management'], true)) {
            $returnScreen = 'create_project';
        }

        $project = fetch_one($pdo, "SELECT * FROM projects WHERE id=? AND employer_user_id=? LIMIT 1", [$projectId, $userId]);
        if (!$project) respond(false, [], 'پروژه پیدا نشد');

        $amount = (int)($project['payment_amount'] ?? 0);
        if ($amount <= 0) {
            respond(true, ['payment_required' => false, 'project_id' => $projectId], 'این پروژه مبلغ پرداختی ندارد');
        }

        if ($paymentMethod === 'blu_bank' && $amount > 0 && $amount < (int)$GLOBALS['MIN_BLU_PAYMENT_AMOUNT_TOMAN']) {
            payment_debug_log('blu_payment_amount_too_low', [
                'project_id' => $projectId,
                'amount_toman' => $amount,
                'amount_sent_to_sep' => $amount * (int)$GLOBALS['SEP_AMOUNT_MULTIPLIER'],
                'minimum_toman' => (int)$GLOBALS['MIN_BLU_PAYMENT_AMOUNT_TOMAN'],
                'payment_method' => $paymentMethod,
            ]);

            respond(false, [
                'sep_error_code' => 'BLU_MIN_AMOUNT',
                'sep_error' => 'مبلغ نهایی برای پرداخت با بلو بانک کمتر از حداقل قابل پرداخت است. کد تخفیف را حذف کن یا درگاه مستقیم را انتخاب کن.',
                'minimum_amount' => (int)$GLOBALS['MIN_BLU_PAYMENT_AMOUNT_TOMAN'],
                'amount' => $amount,
            ], 'مبلغ برای پرداخت با بلو بانک کافی نیست');
        }

        if (($project['payment_status'] ?? '') === 'paid') {
            respond(true, ['payment_required' => false, 'project_id' => $projectId, 'paid' => true], 'پرداخت این پروژه قبلاً انجام شده است');
        }

        $resNum = create_res_num($projectId);
        $sepAmount = $amount * $GLOBALS['SEP_AMOUNT_MULTIPLIER'];
        $redirectUrl = $GLOBALS['SEP_CALLBACK_URL'];
        $cellNumber = normalize_mobile($user['mobile_number'] ?? '');

        $sepPayload = [
            'action' => 'token',
            'TerminalId' => (int)$GLOBALS['SEP_TERMINAL_ID'],
            'Amount' => (int)$sepAmount,
            'ResNum' => (string)$resNum,
            'RedirectUrl' => (string)$redirectUrl,
            'TokenExpiryInMin' => 20,
        ];
        if ($cellNumber !== '') $sepPayload['CellNumber'] = $cellNumber;

        payment_debug_log('sep_token_request', [
            'project_id' => $projectId,
            'amount_toman' => $amount,
            'amount_sent_to_sep' => $sepAmount,
            'res_num' => $resNum,
            'redirect_url' => $redirectUrl,
            'payment_method' => $paymentMethod,
            'gateway_mode' => $gatewayMode,
            'return_screen' => $returnScreen,
            'server_addr' => $_SERVER['SERVER_ADDR'] ?? '',
            'server_name' => $_SERVER['SERVER_NAME'] ?? '',
            'http_host' => $_SERVER['HTTP_HOST'] ?? '',
        ]);

        $sepResponse = request_sep_token($sepPayload, $GLOBALS['SEP_TOKEN_URL']);
        $sepJson = $sepResponse['json'];

        payment_debug_log('sep_token_response', [
            'project_id' => $projectId,
            'amount_toman' => $amount,
            'amount_sent_to_sep' => $sepAmount,
            'res_num' => $resNum,
            'redirect_url' => $redirectUrl,
            'payment_method' => $paymentMethod,
            'gateway_mode' => $gatewayMode,
            'return_screen' => $returnScreen,
            'http_code' => $sepResponse['http_code'],
            'curl_error' => $sepResponse['error'],
            'sep_json' => $sepJson,
            'headers' => $sepResponse['headers'],
        ]);

        if (!$sepJson || (int)($sepJson['status'] ?? -1) !== 1 || trim((string)($sepJson['token'] ?? '')) === '') {
            $sepErrorCode = is_array($sepJson) ? (string)($sepJson['errorCode'] ?? '') : '';
            $sepErrorDesc = is_array($sepJson) ? (string)($sepJson['errorDesc'] ?? '') : '';
            if ($sepErrorDesc === '') {
                $sepErrorDesc = $sepResponse['error'] ?: 'پاسخ معتبر از سامان دریافت نشد';
            }
            respond(false, [
                'sep_error' => $sepErrorDesc,
                'sep_error_code' => $sepErrorCode,
                'sep_http_code' => $sepResponse['http_code'],
                'redirect_url_sent' => $redirectUrl,
            ], 'دریافت توکن پرداخت ناموفق بود');
        }

        $token = trim((string)$sepJson['token']);

        // برای پرداخت مستقیم، عمداً کاربر را از sep_redirect.php با SendToken می‌فرستیم
        // تا صفحه انتخاب بلوپی/پرداخت مستقیم نمایش داده نشود.
        // برای پرداخت بلو بانک، طبق مستند neo-pg باید آدرس X-IPG-Url از header پاسخ توکن خوانده شود.
        $neoGatewayUrl = trim((string)(
            $sepResponse['headers']['x-ipg-url']
            ?? $sepResponse['headers']['X-IPG-Url']
            ?? $sepResponse['headers']['url-ipg-x']
            ?? ''
        ));

        if ($paymentMethod === 'blu_bank') {
            if ($neoGatewayUrl === '') {
                payment_debug_log('blu_gateway_not_active_or_missing_header', [
                    'project_id' => $projectId,
                    'res_num' => $resNum,
                    'headers' => $sepResponse['headers'],
                    'token_response' => $sepJson,
                ]);

                respond(false, [
                    'sep_error_code' => 'BLU_GATEWAY_NOT_ACTIVE',
                    'sep_error' => 'درگاه بلو بانک/بلوپی برای این ترمینال از سمت سپ فعال نیست یا آدرس X-IPG-Url در پاسخ توکن دریافت نشد.',
                    'headers' => $sepResponse['headers'],
                ], 'پرداخت با بلو بانک فعلاً برای این ترمینال فعال نیست');
            }

            $gatewayUrl = $neoGatewayUrl;
        } else {
            $gatewayUrl = $GLOBALS['SEP_DEFAULT_GATEWAY_URL'];
        }

        $columns = ['project_id', 'user_id', 'terminal_id', 'res_num', 'amount', 'token', 'gateway_url', 'status', 'token_response'];
        $values = [$projectId, $userId, $GLOBALS['SEP_TERMINAL_ID'], $resNum, $amount, $token, $gatewayUrl, 'token_created', json_encode(['request' => $sepPayload, 'response' => $sepJson, 'headers' => $sepResponse['headers'], 'return_screen' => $returnScreen, 'source_screen' => $returnScreen], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)];

        if (table_column_exists($pdo, 'project_payments', 'payment_method')) {
            $columns[] = 'payment_method';
            $values[] = $paymentMethod;
        }
        if (table_column_exists($pdo, 'project_payments', 'gateway_mode')) {
            $columns[] = 'gateway_mode';
            $values[] = $gatewayMode;
        }

        $quotedColumns = array_map(fn($c) => "`$c`", $columns);
        $placeholders = implode(', ', array_fill(0, count($columns), '?'));
        $stmt = $pdo->prepare("INSERT INTO project_payments (" . implode(', ', $quotedColumns) . ") VALUES ($placeholders)");
        $stmt->execute($values);
        $paymentId = (int)$pdo->lastInsertId();

        if (table_column_exists($pdo, 'projects', 'payment_method')) {
            $pdo->prepare("UPDATE projects SET payment_id=?, payment_status='payment_started', status='draft', payment_method=? WHERE id=? LIMIT 1")
                ->execute([$paymentId, $paymentMethod, $projectId]);
        } else {
            $pdo->prepare("UPDATE projects SET payment_id=?, payment_status='payment_started', status='draft' WHERE id=? LIMIT 1")
                ->execute([$paymentId, $projectId]);
        }

        respond(true, [
            'payment_required' => true,
            'project_id' => $projectId,
            'payment_id' => $paymentId,
            'amount' => $amount,
            'res_num' => $resNum,
            'payment_method' => $paymentMethod,
            'gateway_mode' => $gatewayMode,
            'return_screen' => $returnScreen,
            'payment_url' => $GLOBALS['SEP_REDIRECT_URL'] . '?payment_id=' . $paymentId,
        ], 'لینک پرداخت آماده شد');
    }

    if ($action === 'check_project_payment') {
        $projectId = (int)($input['project_id'] ?? 0);
        $project = fetch_one(
            $pdo,
            "SELECT id, payment_status, payment_id, payment_ref_num, payment_trace_no, payment_amount FROM projects WHERE id=? AND employer_user_id=? LIMIT 1",
            [$projectId, $userId]
        );
        if (!$project) respond(false, [], 'پروژه پیدا نشد');
        respond(true, $project, 'وضعیت پرداخت دریافت شد');
    }

    respond(false, [], 'درخواست نامعتبر است');
} catch (Throwable $e) {
    payment_debug_log('payment_api_exception', [
        'message' => $e->getMessage(),
        'file' => $e->getFile(),
        'line' => $e->getLine(),
    ]);
    respond(false, [], 'خطای داخلی پرداخت رخ داد؛ payment_debug.log را بررسی کن');
}
