<?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 Create Project API - v11 / Preview + Coupon + Payment Method
|--------------------------------------------------------------------------
| مهم:
| 1) رمز دیتابیس را خودت داخل $DB_PASS بگذار.
| 2) قیمت ایجاد پروژه دیگر داخل اندروید ثابت نیست.
| 3) قیمت از جدول app_settings با کلید project_creation_fee خوانده می‌شود.
| 4) اگر مقدار project_creation_fee را 0 بگذاری، ثبت پروژه رایگان می‌شود و درگاه باز نمی‌شود.
| 5) کد تخفیف از جدول project_coupons پشتیبانی می‌شود: fixed یا percent.
*/

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

$BASE_URL = 'https://pnartl.ir/doorkar';
$DEFAULT_PROJECT_CREATION_FEE = 0; // فقط fallback است؛ مقدار اصلی از app_settings خوانده می‌شود.

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

function is_multipart_request() {
    $ct = $_SERVER['CONTENT_TYPE'] ?? $_SERVER['HTTP_CONTENT_TYPE'] ?? '';
    return stripos($ct, 'multipart/form-data') !== false;
}

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

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 fetch_all(PDO $pdo, $sql, $params = []) {
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

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

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 get_setting_int(PDO $pdo, $key, $defaultValue = 0) {
    if (!table_exists($pdo, 'app_settings')) return (int)$defaultValue;
    try {
        $row = fetch_one($pdo, "SELECT setting_value FROM app_settings WHERE setting_key = ? LIMIT 1", [$key]);
        if (!$row) return (int)$defaultValue;
        return max(0, (int)($row['setting_value'] ?? $defaultValue));
    } catch (Throwable $e) {
        return (int)$defaultValue;
    }
}

function normalize_coupon_code($code) {
    $code = strtoupper(trim((string)$code));
    $code = preg_replace('/[^A-Z0-9_\\-]/', '', $code);
    return mb_substr($code, 0, 40);
}

function calculate_coupon_discount_amount($coupon, $subtotal) {
    $subtotal = max(0, (int)$subtotal);
    if (!$coupon || $subtotal <= 0) return 0;

    $minOrder = max(0, (int)($coupon['min_order_amount'] ?? 0));
    if ($minOrder > 0 && $subtotal < $minOrder) return 0;

    $type = strtolower(trim((string)($coupon['discount_type'] ?? 'fixed')));
    $value = max(0, (int)($coupon['discount_value'] ?? 0));

    if ($type === 'percent' || $type === 'percentage') {
        $raw = (int)floor($subtotal * min(100, $value) / 100);
    } else {
        $raw = $value;
    }

    $maxDiscount = max(0, (int)($coupon['max_discount_amount'] ?? 0));
    if ($maxDiscount > 0) $raw = min($raw, $maxDiscount);

    return max(0, min($raw, $subtotal));
}

function validate_coupon_for_order(PDO $pdo, $code, $subtotal) {
    $code = normalize_coupon_code($code);
    $subtotal = max(0, (int)$subtotal);

    if ($code === '') {
        return [false, null, 0, 'کد تخفیف وارد نشده است'];
    }
    if (!table_exists($pdo, 'project_coupons')) {
        return [false, null, 0, 'سامانه کد تخفیف هنوز روی سرور فعال نشده است'];
    }

    $coupon = fetch_one($pdo, "SELECT * FROM project_coupons WHERE code = ? LIMIT 1", [$code]);
    if (!$coupon) return [false, null, 0, 'کد تخفیف پیدا نشد'];

    if ((int)($coupon['is_active'] ?? 0) !== 1) {
        return [false, null, 0, 'این کد تخفیف غیرفعال است'];
    }

    $startsAt = trim((string)($coupon['starts_at'] ?? ''));
    if ($startsAt !== '' && strtotime($startsAt) !== false && time() < strtotime($startsAt)) {
        return [false, null, 0, 'زمان استفاده از این کد تخفیف هنوز شروع نشده است'];
    }

    $expiresAt = trim((string)($coupon['expires_at'] ?? ''));
    if ($expiresAt !== '' && strtotime($expiresAt) !== false && time() > strtotime($expiresAt)) {
        return [false, null, 0, 'مهلت استفاده از این کد تخفیف تمام شده است'];
    }

    $usageLimit = max(0, (int)($coupon['usage_limit'] ?? 0));
    $usedCount = max(0, (int)($coupon['used_count'] ?? 0));
    if ($usageLimit > 0 && $usedCount >= $usageLimit) {
        return [false, null, 0, 'ظرفیت استفاده از این کد تخفیف تکمیل شده است'];
    }

    $minOrder = max(0, (int)($coupon['min_order_amount'] ?? 0));
    if ($minOrder > 0 && $subtotal < $minOrder) {
        return [false, $coupon, 0, 'حداقل مبلغ سفارش برای این کد ' . number_format($minOrder) . ' تومان است'];
    }

    $discount = calculate_coupon_discount_amount($coupon, $subtotal);
    if ($discount <= 0) return [false, $coupon, 0, 'این کد برای سفارش فعلی تخفیفی ایجاد نمی‌کند'];

    return [true, $coupon, $discount, 'کد تخفیف با موفقیت اعمال شد'];
}

function verify_session(PDO $pdo, $userId, $apiToken) {
    if ($userId <= 0 || trim((string)$apiToken) === '') return null;
    $user = fetch_one($pdo, "SELECT id, mobile_number, user_type, api_token_hash FROM users WHERE id = ? LIMIT 1", [$userId]);
    if (!$user) return null;

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

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

function ensure_employer($user) {
    $type = strtolower(trim((string)($user['user_type'] ?? '')));
    return in_array($type, ['employer', 'client', 'karfarma'], true) || strpos($type, 'کارفرما') !== false;
}

function as_bool($value) {
    if (is_bool($value)) return $value;
    $v = strtolower(trim((string)$value));
    return in_array($v, ['1', 'true', 'yes', 'on'], true);
}

function as_array_value($value) {
    if (is_string($value)) {
        $decoded = json_decode($value, true);
        if (is_array($decoded)) return $decoded;
    }
    return is_array($value) ? $value : [];
}

function as_int_array($value) {
    if (is_string($value)) {
        $decoded = json_decode($value, true);
        if (is_array($decoded)) $value = $decoded;
        else {
            $parts = preg_split('/[,،|;]+/u', $value);
            $value = is_array($parts) ? $parts : [];
        }
    }

    if (!is_array($value)) return [];

    $out = [];
    foreach ($value as $item) {
        $id = (int)$item;
        if ($id > 0) $out[] = $id;
    }
    return array_values(array_unique($out));
}

function split_option_keys($raw) {
    $raw = trim((string)$raw);
    if ($raw === '') return [];
    $parts = preg_split('/[,،|;]+/u', $raw);
    $out = [];
    foreach ($parts as $part) {
        $key = trim((string)$part);
        if ($key !== '') $out[] = $key;
    }
    return array_values(array_unique($out));
}


function normalize_selected_project_options(PDO $pdo, $rawOptionIds, $alreadyPaid = false, $paidOptionMap = []) {
    $optionIds = as_int_array($rawOptionIds);
    $priceMap = [];
    $optionsTotal = 0;
    $bundleChildIds = [];

    if (count($optionIds) <= 0 || !table_exists($pdo, 'project_options')) {
        return [[], [], 0, []];
    }

    $allOptions = fetch_all($pdo, "SELECT * FROM project_options WHERE is_active = 1");
    $byId = [];
    $byKey = [];

    foreach ($allOptions as $row) {
        $id = (int)($row['id'] ?? 0);
        $key = trim((string)($row['option_key'] ?? ''));
        if ($id <= 0) continue;
        $byId[$id] = $row;
        if ($key !== '') $byKey[$key] = $row;
    }

    $selectedMap = [];
    foreach ($optionIds as $id) {
        if (isset($byId[$id])) $selectedMap[$id] = true;
    }

    foreach (array_keys($selectedMap) as $id) {
        $row = $byId[$id] ?? null;
        if (!$row) continue;

        $type = trim((string)($row['option_type'] ?? 'single'));
        $key = trim((string)($row['option_key'] ?? ''));
        $includedKeys = split_option_keys($row['included_option_keys'] ?? '');

        if (!$includedKeys && in_array($key, ['urgent_featured_bundle', 'featured_urgent_bundle'], true)) {
            $includedKeys = ['urgent_project', 'featured_project'];
        }

        $includedIds = as_int_array($row['included_option_ids'] ?? []);

        if ($type === 'bundle' || $includedKeys || $includedIds) {
            foreach ($includedKeys as $childKey) {
                if (isset($byKey[$childKey])) {
                    $childId = (int)$byKey[$childKey]['id'];
                    $bundleChildIds[$childId] = true;
                }
            }
            foreach ($includedIds as $childId) {
                if (isset($byId[$childId])) $bundleChildIds[(int)$childId] = true;
            }
        }
    }

    // اگر بسته انتخاب شده باشد، فقط خود بسته در دیتابیس ذخیره می‌شود.
    // گزینه‌های زیرمجموعه فقط در UI فعال/قفل نمایش داده می‌شوند و دوباره به عنوان برچسب جدا ذخیره نمی‌شوند.
    foreach (array_keys($bundleChildIds) as $childId) {
        if (isset($selectedMap[$childId])) unset($selectedMap[$childId]);
    }

    $storedIds = array_values(array_map('intval', array_keys($selectedMap)));
    sort($storedIds);

    foreach ($storedIds as $id) {
        if (!isset($byId[$id])) continue;
        $row = $byId[$id];
        $base = (int)($row['price'] ?? 0);
        $original = (int)($row['original_price'] ?? 0);
        if ($original <= 0) $original = $base;
        $discount = (int)($row['discount_price'] ?? 0);
        $final = ($discount > 0 && $discount < $original) ? $discount : $original;

        if ($alreadyPaid && isset($paidOptionMap[$id])) $final = 0;

        $priceMap[$id] = max(0, (int)$final);
        $optionsTotal += max(0, (int)$final);
    }

    return [$storedIds, $priceMap, $optionsTotal, array_keys($bundleChildIds)];
}

function sanitize_file_name($name) {
    $name = trim((string)$name);
    if ($name === '') $name = 'attachment';
    $name = preg_replace('/[^A-Za-z0-9_\-.\x{0600}-\x{06FF} ]/u', '_', $name);
    return mb_substr($name, 0, 160);
}

function normalize_uploaded_files($fieldName) {
    if (!isset($_FILES[$fieldName])) return [];
    $f = $_FILES[$fieldName];
    $files = [];

    if (is_array($f['name'])) {
        for ($i = 0; $i < count($f['name']); $i++) {
            $files[] = [
                'name' => $f['name'][$i],
                'type' => $f['type'][$i] ?? 'application/octet-stream',
                'tmp_name' => $f['tmp_name'][$i],
                'error' => $f['error'][$i],
                'size' => $f['size'][$i],
            ];
        }
    } else {
        $files[] = $f;
    }

    return $files;
}

function save_project_files(PDO $pdo, $projectId, $baseUrl) {
    if (!table_exists($pdo, 'project_attachments')) return [];

    $files = normalize_uploaded_files('attachments');
    if (!$files) return [];

    $baseDir = __DIR__ . '/uploads/project_attachments/' . $projectId;
    if (!is_dir($baseDir)) @mkdir($baseDir, 0755, true);

    $saved = [];
    $insertStmt = $pdo->prepare("
        INSERT INTO project_attachments
        (project_id, original_name, stored_name, file_path, file_url, mime_type, file_size)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    ");

    foreach ($files as $file) {
        if ((int)($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) continue;

        $size = (int)($file['size'] ?? 0);
        if ($size <= 0 || $size > 15 * 1024 * 1024) continue;

        $originalName = sanitize_file_name($file['name'] ?? 'attachment');
        $ext = pathinfo($originalName, PATHINFO_EXTENSION);
        $safeExt = $ext !== '' ? ('.' . strtolower($ext)) : '';
        $storedName = bin2hex(random_bytes(12)) . $safeExt;
        $targetPath = $baseDir . '/' . $storedName;

        if (!move_uploaded_file($file['tmp_name'], $targetPath)) continue;

        $relativePath = 'uploads/project_attachments/' . $projectId . '/' . $storedName;
        $fileUrl = rtrim($baseUrl, '/') . '/' . $relativePath;
        $mime = trim((string)($file['type'] ?? 'application/octet-stream'));

        $insertStmt->execute([$projectId, $originalName, $storedName, $relativePath, $fileUrl, $mime, $size]);

        $saved[] = [
            'name' => $originalName,
            'path' => $relativePath,
            'url' => $fileUrl,
            'mime_type' => $mime,
            'size' => $size,
        ];
    }

    return $saved;
}

function project_edit_files(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_attachments') || !table_column_exists($pdo, 'project_attachments', 'project_id')) return [];
    $idExpr = table_column_exists($pdo, 'project_attachments', 'id') ? 'id' : '0';
    $nameExpr = table_column_exists($pdo, 'project_attachments', 'original_name') ? 'original_name' : (table_column_exists($pdo, 'project_attachments', 'file_name') ? 'file_name' : "''");
    $urlExpr = table_column_exists($pdo, 'project_attachments', 'file_url') ? 'file_url' : (table_column_exists($pdo, 'project_attachments', 'file_path') ? 'file_path' : "''");
    $sizeExpr = table_column_exists($pdo, 'project_attachments', 'file_size') ? 'file_size' : '0';
    $mimeExpr = table_column_exists($pdo, 'project_attachments', 'mime_type') ? 'mime_type' : "''";
    $rows = fetch_all($pdo, "SELECT $idExpr AS id, $nameExpr AS name, $urlExpr AS url, $sizeExpr AS file_size, $mimeExpr AS mime_type FROM project_attachments WHERE project_id = ? ORDER BY id ASC LIMIT 30", [$projectId]);
    $out = [];
    foreach ($rows as $row) {
        $url = trim((string)($row['url'] ?? ''));
        if ($url !== '' && !preg_match('~^https?://~i', $url)) $url = 'https://pnartl.ir/doorkar/' . ltrim($url, '/');
        $size = (int)($row['file_size'] ?? 0);
        $out[] = [
            'id' => (int)($row['id'] ?? 0),
            'name' => trim((string)($row['name'] ?? 'فایل پیوست')) ?: 'فایل پیوست',
            'url' => $url,
            'mime_type' => trim((string)($row['mime_type'] ?? '')),
            'file_size' => $size,
            'size_text' => $size > 0 ? round($size / 1024, 1) . ' KB' : 'فایل قبلی',
        ];
    }
    return $out;
}

function sync_project_existing_attachments(PDO $pdo, $projectId, $keepIds) {
    if (!table_exists($pdo, 'project_attachments') || !table_column_exists($pdo, 'project_attachments', 'project_id') || !table_column_exists($pdo, 'project_attachments', 'id')) return;
    $keep = [];
    foreach (as_int_array($keepIds) as $id) if ($id > 0) $keep[$id] = true;
    $pathExpr = table_column_exists($pdo, 'project_attachments', 'file_path') ? 'file_path' : "''";
    $rows = fetch_all($pdo, "SELECT id, $pathExpr AS file_path FROM project_attachments WHERE project_id = ?", [$projectId]);
    foreach ($rows as $row) {
        $id = (int)($row['id'] ?? 0);
        if ($id <= 0 || isset($keep[$id])) continue;
        $path = trim((string)($row['file_path'] ?? ''));
        if ($path !== '') {
            $full = __DIR__ . '/' . ltrim($path, '/');
            if (is_file($full)) @unlink($full);
        }
        $pdo->prepare("DELETE FROM project_attachments WHERE id = ? AND project_id = ? LIMIT 1")->execute([$id, $projectId]);
    }
}

function select_if_column(PDO $pdo, $table, $column, $fallbackSql) {
    return table_column_exists($pdo, $table, $column) ? $column : $fallbackSql;
}

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) {
    respond(false, [], 'اتصال به دیتابیس برقرار نشد');
}

$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, [], 'نشست ورود معتبر نیست؛ دوباره وارد حساب شو');

$projectCreationFee = get_setting_int($pdo, 'project_creation_fee', $DEFAULT_PROJECT_CREATION_FEE);

if ($action === 'get_create_project_config') {
    $serviceTypes = fetch_all($pdo, "
        SELECT id, title, description, icon_key
        FROM project_service_types
        WHERE is_active = 1
        ORDER BY sort_order ASC, id ASC
    ");

    $skills = fetch_all($pdo, "
        SELECT id, name_fa
        FROM skills
        WHERE is_active = 1
        ORDER BY id ASC
        LIMIT 120
    ");

    $budgetRanges = fetch_all($pdo, "
        SELECT id, title, min_budget, max_budget, description
        FROM project_budget_ranges
        WHERE is_active = 1
        ORDER BY sort_order ASC, id ASC
    ");

    $deadlineOptions = fetch_all($pdo, "
        SELECT id, title, description, meta
        FROM project_deadline_options
        WHERE is_active = 1
        ORDER BY sort_order ASC, id ASC
    ");

    $projectOptions = [];
    if (table_exists($pdo, 'project_options')) {
        $priceSelect = select_if_column($pdo, 'project_options', 'price', '0 AS price');
        $originalSelect = select_if_column($pdo, 'project_options', 'original_price', "$priceSelect AS original_price");
        $discountSelect = select_if_column($pdo, 'project_options', 'discount_price', '0 AS discount_price');
        $typeSelect = select_if_column($pdo, 'project_options', 'option_type', "'single' AS option_type");
        $includedKeysSelect = select_if_column($pdo, 'project_options', 'included_option_keys', "'' AS included_option_keys");
        $includedIdsSelect = select_if_column($pdo, 'project_options', 'included_option_ids', "'' AS included_option_ids");
        $badgeTextSelect = select_if_column($pdo, 'project_options', 'badge_text', "'' AS badge_text");
        $badgeIconSelect = select_if_column($pdo, 'project_options', 'badge_icon', "'' AS badge_icon");
        $badgeColorSelect = select_if_column($pdo, 'project_options', 'badge_color_key', "'' AS badge_color_key");
        $sortOrder = table_column_exists($pdo, 'project_options', 'sort_order') ? 'sort_order ASC,' : '';

        $projectOptions = fetch_all($pdo, "
            SELECT
                id,
                option_key,
                title,
                description,
                option_group,
                $typeSelect,
                $priceSelect,
                $originalSelect,
                $discountSelect,
                $includedKeysSelect,
                $includedIdsSelect,
                $badgeTextSelect,
                $badgeIconSelect,
                $badgeColorSelect
            FROM project_options
            WHERE is_active = 1
            ORDER BY $sortOrder id ASC
        ");
    }

    respond(true, [
        'service_types' => $serviceTypes,
        'skills' => $skills,
        'budget_ranges' => $budgetRanges,
        'deadline_options' => $deadlineOptions,
        'project_options' => $projectOptions,
        'invoice' => [
            'project_creation_fee' => $projectCreationFee,
            'currency' => 'toman',
        ],
        'payment_methods' => [
            ['key' => 'sep_direct', 'title' => 'پرداخت مستقیم با کارت بانکی', 'is_default' => true],
            ['key' => 'blu_bank', 'title' => 'پرداخت با بلو بانک', 'is_default' => false],
        ],
    ]);
}


if ($action === 'validate_coupon') {
    $code = normalize_coupon_code($input['coupon_code'] ?? '');
    $subtotal = max(0, (int)($input['subtotal'] ?? 0));

    [$ok, $coupon, $discount, $couponMessage] = validate_coupon_for_order($pdo, $code, $subtotal);
    if (!$ok) {
        respond(false, [
            'discount_amount' => $discount,
            'coupon' => $coupon ? [
                'code' => $coupon['code'] ?? $code,
                'title' => $coupon['title'] ?? '',
                'discount_type' => $coupon['discount_type'] ?? 'fixed',
                'discount_value' => (int)($coupon['discount_value'] ?? 0),
                'max_discount_amount' => (int)($coupon['max_discount_amount'] ?? 0),
                'min_order_amount' => (int)($coupon['min_order_amount'] ?? 0),
            ] : null,
        ], $couponMessage);
    }

    respond(true, [
        'discount_amount' => $discount,
        'payable_amount' => max(0, $subtotal - $discount),
        'coupon' => [
            'code' => $coupon['code'] ?? $code,
            'title' => $coupon['title'] ?? '',
            'discount_type' => $coupon['discount_type'] ?? 'fixed',
            'discount_value' => (int)($coupon['discount_value'] ?? 0),
            'max_discount_amount' => (int)($coupon['max_discount_amount'] ?? 0),
            'min_order_amount' => (int)($coupon['min_order_amount'] ?? 0),
        ],
    ], $couponMessage);
}


if ($action === 'get_project_for_edit') {
    if (!ensure_employer($user)) respond(false, [], 'فقط حساب کارفرما می‌تواند پروژه را ویرایش کند');
    $projectId = (int)($input['project_id'] ?? 0);
    if ($projectId <= 0) respond(false, [], 'شناسه پروژه معتبر نیست');
    if (!table_exists($pdo, 'projects')) respond(false, [], 'جدول پروژه‌ها پیدا نشد');

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

    $skillIds = [];
    if (table_exists($pdo, 'project_skills') && table_column_exists($pdo, 'project_skills', 'project_id') && table_column_exists($pdo, 'project_skills', 'skill_id')) {
        $rows = fetch_all($pdo, "SELECT skill_id FROM project_skills WHERE project_id = ?", [$projectId]);
        foreach ($rows as $r) $skillIds[] = (int)$r['skill_id'];
    }

    $optionIds = [];
    if (table_exists($pdo, 'project_selected_options') && table_column_exists($pdo, 'project_selected_options', 'project_id') && table_column_exists($pdo, 'project_selected_options', 'option_id')) {
        $rows = fetch_all($pdo, "SELECT option_id FROM project_selected_options WHERE project_id = ?", [$projectId]);
        foreach ($rows as $r) $optionIds[] = (int)$r['option_id'];
    } else {
        $optionIds = as_int_array($project['options_json'] ?? '[]');
    }

    $paymentStatus = strtolower(trim((string)($project['payment_status'] ?? '')));
    $paymentAmount = (int)($project['payment_amount'] ?? 0);
    $alreadyPaid = $paymentAmount <= 0 || in_array($paymentStatus, ['paid', 'free', 'completed'], true);

    respond(true, [
        'project' => [
            'id' => $projectId,
            'title' => (string)($project['title'] ?? ''),
            'description' => (string)($project['description'] ?? ''),
            'service_type_id' => (int)($project['service_type_id'] ?? 0),
            'skill_ids' => array_values(array_unique($skillIds)),
            'budget_range_id' => (int)($project['budget_range_id'] ?? 0),
            'custom_budget_enabled' => (int)($project['is_custom_budget'] ?? 0) === 1,
            'custom_budget_min' => (string)($project['custom_budget_min'] ?? ''),
            'custom_budget_max' => (string)($project['custom_budget_max'] ?? ''),
            'deadline_option_id' => (int)($project['deadline_option_id'] ?? 0),
            'custom_deadline_text' => (string)($project['custom_deadline_text'] ?? ''),
            'option_ids' => array_values(array_unique($optionIds)),
            'paid_option_ids' => $alreadyPaid ? array_values(array_unique($optionIds)) : [],
            'payment_status' => (string)($project['payment_status'] ?? ''),
            'payment_amount' => $paymentAmount,
            'already_paid' => $alreadyPaid,
            'attachments' => project_edit_files($pdo, $projectId),
        ]
    ], 'اطلاعات پروژه برای ویرایش دریافت شد');
}

if ($action === 'update_project') {
    if (!ensure_employer($user)) respond(false, [], 'فقط حساب کارفرما می‌تواند پروژه را ویرایش کند');

    $projectId = (int)($input['editing_project_id'] ?? $input['project_id'] ?? 0);
    if ($projectId <= 0) respond(false, [], 'شناسه پروژه برای ویرایش معتبر نیست');

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

    $serviceTypeId = (int)($input['service_type_id'] ?? 0);
    $title = trim((string)($input['title'] ?? ''));
    $description = trim((string)($input['description'] ?? ''));
    $skillIds = as_int_array($input['skill_ids'] ?? []);
    $optionIds = as_int_array($input['option_ids'] ?? []);
    $budgetRangeId = (int)($input['budget_range_id'] ?? 0);
    $customBudgetEnabled = as_bool($input['custom_budget_enabled'] ?? false);
    $customBudgetMin = (int)($input['custom_budget_min'] ?? 0);
    $customBudgetMax = (int)($input['custom_budget_max'] ?? 0);
    $deadlineOptionId = (int)($input['deadline_option_id'] ?? 0);
    $customDeadlineText = trim((string)($input['custom_deadline_text'] ?? ''));
    $couponCode = normalize_coupon_code($input['coupon_code'] ?? '');
    $paymentMethod = trim((string)($input['payment_method'] ?? 'sep_direct'));
    if (!in_array($paymentMethod, ['sep_direct', 'blu_bank'], true)) $paymentMethod = 'sep_direct';

    if ($serviceTypeId <= 0) respond(false, [], 'نوع سرویس پروژه را انتخاب کن');
    if (mb_strlen($title) < 5) respond(false, [], 'عنوان پروژه کوتاه است');
    if (mb_strlen($description) < 20) respond(false, [], 'توضیحات پروژه کوتاه است');
    if (count($skillIds) < 1) respond(false, [], 'حداقل یک مهارت انتخاب کن');
    if (count($skillIds) > 10) respond(false, [], 'حداکثر ۱۰ مهارت مجاز است');
    if ($deadlineOptionId <= 0) respond(false, [], 'زمان انجام پروژه را انتخاب کن');

    if ($customBudgetEnabled) {
        if ($customBudgetMin <= 0 || $customBudgetMax <= 0 || $customBudgetMax < $customBudgetMin) respond(false, [], 'بودجه دلخواه معتبر نیست');
        $budgetRangeId = null;
    } else {
        if ($budgetRangeId <= 0) respond(false, [], 'بازه بودجه پروژه را انتخاب کن');
    }

    $paymentStatusOld = strtolower(trim((string)($existingProject['payment_status'] ?? '')));
    $oldPaymentAmount = (int)($existingProject['payment_amount'] ?? 0);
    $alreadyPaid = $oldPaymentAmount <= 0 || in_array($paymentStatusOld, ['paid', 'free', 'completed'], true);

    $existingOptionIds = [];
    $existingOptionPrices = [];
    if (table_exists($pdo, 'project_selected_options') && table_column_exists($pdo, 'project_selected_options', 'project_id') && table_column_exists($pdo, 'project_selected_options', 'option_id')) {
        $priceCol = table_column_exists($pdo, 'project_selected_options', 'price_at_submit') ? 'price_at_submit' : (table_column_exists($pdo, 'project_selected_options', 'price_amount') ? 'price_amount' : null);
        $priceSelect = $priceCol ? ", `$priceCol` AS stored_price" : ", 0 AS stored_price";
        $rows = fetch_all($pdo, "SELECT option_id $priceSelect FROM project_selected_options WHERE project_id = ?", [$projectId]);
        foreach ($rows as $r) {
            $id = (int)$r['option_id'];
            $existingOptionIds[$id] = true;
            $existingOptionPrices[$id] = max(0, (int)($r['stored_price'] ?? 0));
        }
    } else {
        foreach (as_int_array($existingProject['options_json'] ?? '[]') as $id) {
            $existingOptionIds[$id] = true;
            $existingOptionPrices[$id] = 0;
        }
    }

    $creationFee = $alreadyPaid ? 0 : $projectCreationFee;
    [$optionIds, $priceMap, $optionsTotal, $bundleChildIds] = normalize_selected_project_options($pdo, $optionIds, $alreadyPaid, $existingOptionIds);

    $subtotalAmount = max(0, $creationFee + $optionsTotal);
    $couponDiscount = 0;
    $couponData = null;
    if ($couponCode !== '' && $subtotalAmount > 0) {
        [$couponOk, $couponRow, $couponDiscountAmount, $couponMessage] = validate_coupon_for_order($pdo, $couponCode, $subtotalAmount);
        if (!$couponOk) respond(false, [], $couponMessage);
        $couponDiscount = max(0, (int)$couponDiscountAmount);
        $couponData = $couponRow;
    }

    $payableAmount = max(0, $subtotalAmount - $couponDiscount);
    $paymentRequired = $payableAmount > 0;
    $projectStatus = $paymentRequired ? (string)($existingProject['status'] ?? 'draft') : (in_array(strtolower((string)($existingProject['status'] ?? '')), ['draft','unpaid','pending_payment'], true) ? 'open' : (string)($existingProject['status'] ?? 'open'));
    $paymentStatus = $paymentRequired ? 'pending_payment' : ($alreadyPaid ? (string)($existingProject['payment_status'] ?? 'paid') : 'free');

    // در ویرایش پروژه‌ای که قبلاً پرداخت شده، مبلغ قابل پرداخت برای این ویرایش ممکن است صفر باشد،
    // اما نباید مبلغ ثبت‌شده پروژه در جزئیات به «رایگان» تبدیل شود.
    // بنابراین فقط وقتی واقعاً پرداخت جدید لازم است، payment_amount را به مبلغ جدید تغییر می‌دهیم.
    // در غیر این صورت مبلغ قبلی پرداخت‌شده حفظ می‌شود.
    $projectPaymentAmountToStore = $paymentRequired ? $payableAmount : ($alreadyPaid ? $oldPaymentAmount : 0);

    $invoice = [
        'edit_mode' => true,
        'previous_project_id' => $projectId,
        'creation_fee' => $creationFee,
        'options_total' => $optionsTotal,
        'subtotal_amount' => $subtotalAmount,
        'coupon_code' => $couponCode,
        'coupon_discount' => $couponDiscount,
        'payable_amount' => $payableAmount,
        'payment_method' => $paymentMethod,
        'currency' => 'toman',
    ];

    try {
        $pdo->beginTransaction();
        $sets = [
            'service_type_id = ?', 'title = ?', 'description = ?', 'budget_range_id = ?', 'is_custom_budget = ?', 'custom_budget_min = ?', 'custom_budget_max = ?', 'deadline_option_id = ?', 'options_json = ?', 'invoice_json = ?', 'status = ?', 'payment_status = ?', 'payment_amount = ?'
        ];
        $params = [$serviceTypeId, $title, $description, $budgetRangeId, $customBudgetEnabled ? 1 : 0, $customBudgetEnabled ? $customBudgetMin : null, $customBudgetEnabled ? $customBudgetMax : null, $deadlineOptionId, json_encode($optionIds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), json_encode($invoice, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $projectStatus, $paymentStatus, $projectPaymentAmountToStore];
        if (table_column_exists($pdo, 'projects', 'custom_deadline_text')) { $sets[] = 'custom_deadline_text = ?'; $params[] = $customDeadlineText; }
        foreach ([
            'coupon_code' => $couponCode,
            'coupon_discount_type' => $couponData['discount_type'] ?? '',
            'coupon_discount_value' => (int)($couponData['discount_value'] ?? 0),
            'coupon_discount_amount' => $couponDiscount,
            'payment_method' => $paymentMethod,
        ] as $col => $val) {
            if (table_column_exists($pdo, 'projects', $col)) { $sets[] = "`$col` = ?"; $params[] = $val; }
        }
        $params[] = $projectId;
        $pdo->prepare("UPDATE projects SET " . implode(', ', $sets) . " WHERE id = ? LIMIT 1")->execute($params);

        $keepAttachmentIds = as_int_array($input['existing_attachment_ids'] ?? '[]');
        sync_project_existing_attachments($pdo, $projectId, $keepAttachmentIds);
        $savedFiles = save_project_files($pdo, $projectId, $BASE_URL);
        $allFilesAfterEdit = project_edit_files($pdo, $projectId);
        if (count($allFilesAfterEdit) > 0 && table_column_exists($pdo, 'projects', 'attachment_json')) {
            $pdo->prepare("UPDATE projects SET attachment_json = ? WHERE id = ? LIMIT 1")->execute([json_encode($allFilesAfterEdit, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $projectId]);
        }

        if (table_exists($pdo, 'project_skills')) {
            $pdo->prepare("DELETE FROM project_skills WHERE project_id = ?")->execute([$projectId]);
            $skillStmt = $pdo->prepare("INSERT IGNORE INTO project_skills (project_id, skill_id) VALUES (?, ?)");
            foreach ($skillIds as $skillId) $skillStmt->execute([$projectId, $skillId]);
        }

        if (table_exists($pdo, 'project_selected_options')) {
            $pdo->prepare("DELETE FROM project_selected_options WHERE project_id = ?")->execute([$projectId]);
            if (count($optionIds) > 0) {
                $priceColumn = table_column_exists($pdo, 'project_selected_options', 'price_at_submit') ? 'price_at_submit' : 'price_amount';
                $optionStmt = $pdo->prepare("INSERT IGNORE INTO project_selected_options (project_id, option_id, `$priceColumn`) VALUES (?, ?, ?)");
                foreach ($optionIds as $optionId) {
                    $displayPrice = $priceMap[$optionId] ?? 0;
                    if (isset($existingOptionIds[$optionId]) && isset($existingOptionPrices[$optionId]) && $existingOptionPrices[$optionId] > 0) {
                        $displayPrice = $existingOptionPrices[$optionId];
                    }
                    $optionStmt->execute([$projectId, $optionId, $displayPrice]);
                }
            }
        }

        $pdo->commit();
        respond(true, [
            'project_id' => $projectId,
            'status' => $projectStatus,
            'payment_status' => $paymentStatus,
            'payment_required' => $paymentRequired,
            'subtotal_amount' => $subtotalAmount,
            'coupon_code' => $couponCode,
            'coupon_discount' => $couponDiscount,
            'payable_amount' => $payableAmount,
            'payment_method' => $paymentMethod,
            'edit_mode' => true,
            'attachments' => $allFilesAfterEdit,
        ], $paymentRequired ? 'تغییرات ذخیره شد؛ برای فعال شدن موارد جدید پرداخت را انجام بده' : 'تغییرات پروژه ذخیره شد');
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        respond(false, [], 'خطا در ذخیره ویرایش پروژه');
    }
}

if ($action === 'submit_project') {
    if (!ensure_employer($user)) respond(false, [], 'فقط حساب کارفرما می‌تواند پروژه ثبت کند');

    $serviceTypeId = (int)($input['service_type_id'] ?? 0);
    $title = trim((string)($input['title'] ?? ''));
    $description = trim((string)($input['description'] ?? ''));
    $skillIds = as_int_array($input['skill_ids'] ?? []);
    $optionIds = as_int_array($input['option_ids'] ?? []);
    $budgetRangeId = (int)($input['budget_range_id'] ?? 0);
    $customBudgetEnabled = as_bool($input['custom_budget_enabled'] ?? false);
    $customBudgetMin = (int)($input['custom_budget_min'] ?? 0);
    $customBudgetMax = (int)($input['custom_budget_max'] ?? 0);
    $deadlineOptionId = (int)($input['deadline_option_id'] ?? 0);
    $customDeadlineText = trim((string)($input['custom_deadline_text'] ?? ''));
    $couponCode = normalize_coupon_code($input['coupon_code'] ?? '');
    $paymentMethod = trim((string)($input['payment_method'] ?? 'sep_direct'));
    if (!in_array($paymentMethod, ['sep_direct', 'blu_bank'], true)) $paymentMethod = 'sep_direct';

    if ($serviceTypeId <= 0) respond(false, [], 'نوع سرویس پروژه را انتخاب کن');
    if (mb_strlen($title) < 5) respond(false, [], 'عنوان پروژه کوتاه است');
    if (mb_strlen($description) < 20) respond(false, [], 'توضیحات پروژه کوتاه است');
    if (count($skillIds) < 1) respond(false, [], 'حداقل یک مهارت انتخاب کن');
    if (count($skillIds) > 10) respond(false, [], 'حداکثر ۱۰ مهارت مجاز است');
    if ($deadlineOptionId <= 0) respond(false, [], 'زمان انجام پروژه را انتخاب کن');

    if ($customBudgetEnabled) {
        if ($customBudgetMin <= 0 || $customBudgetMax <= 0 || $customBudgetMax < $customBudgetMin) {
            respond(false, [], 'بودجه دلخواه معتبر نیست');
        }
        $budgetRangeId = null;
    } else {
        if ($budgetRangeId <= 0) respond(false, [], 'بازه بودجه پروژه را انتخاب کن');
    }

    $creationFee = $projectCreationFee;
    [$optionIds, $priceMap, $optionsTotal, $bundleChildIds] = normalize_selected_project_options($pdo, $optionIds, false, []);

    $subtotalAmount = max(0, $creationFee + $optionsTotal);
    $couponDiscount = 0;
    $couponData = null;
    if ($couponCode !== '') {
        [$couponOk, $couponRow, $couponDiscountAmount, $couponMessage] = validate_coupon_for_order($pdo, $couponCode, $subtotalAmount);
        if (!$couponOk) respond(false, [], $couponMessage);
        $couponDiscount = max(0, (int)$couponDiscountAmount);
        $couponData = $couponRow;
    }

    $payableAmount = max(0, $subtotalAmount - $couponDiscount);
    $paymentRequired = $payableAmount > 0;
    $projectStatus = $paymentRequired ? 'draft' : 'open';
    $paymentStatus = $paymentRequired ? 'pending_payment' : 'free';

    $invoice = [
        'creation_selected' => true,
        'creation_fee' => $creationFee,
        'options_total' => $optionsTotal,
        'subtotal_amount' => $subtotalAmount,
        'coupon_code' => $couponCode,
        'coupon_discount' => $couponDiscount,
        'payable_amount' => $payableAmount,
        'payment_method' => $paymentMethod,
        'currency' => 'toman',
    ];

    try {
        $pdo->beginTransaction();

        $hasCustomDeadline = table_column_exists($pdo, 'projects', 'custom_deadline_text');

        if ($hasCustomDeadline) {
            $stmt = $pdo->prepare("
                INSERT INTO projects
                (employer_user_id, service_type_id, title, description, attachment_json, budget_range_id, is_custom_budget, custom_budget_min, custom_budget_max, deadline_option_id, custom_deadline_text, options_json, invoice_json, status, payment_status, payment_amount)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $userId,
                $serviceTypeId,
                $title,
                $description,
                json_encode([], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                $budgetRangeId,
                $customBudgetEnabled ? 1 : 0,
                $customBudgetEnabled ? $customBudgetMin : null,
                $customBudgetEnabled ? $customBudgetMax : null,
                $deadlineOptionId,
                $customDeadlineText,
                json_encode($optionIds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                json_encode($invoice, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                $projectStatus,
                $paymentStatus,
                $payableAmount,
            ]);
        } else {
            $stmt = $pdo->prepare("
                INSERT INTO projects
                (employer_user_id, service_type_id, title, description, attachment_json, budget_range_id, is_custom_budget, custom_budget_min, custom_budget_max, deadline_option_id, options_json, invoice_json, status, payment_status, payment_amount)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $userId,
                $serviceTypeId,
                $title,
                $description,
                json_encode([], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                $budgetRangeId,
                $customBudgetEnabled ? 1 : 0,
                $customBudgetEnabled ? $customBudgetMin : null,
                $customBudgetEnabled ? $customBudgetMax : null,
                $deadlineOptionId,
                json_encode($optionIds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                json_encode($invoice, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                $projectStatus,
                $paymentStatus,
                $payableAmount,
            ]);
        }

        $projectId = (int)$pdo->lastInsertId();

        $optionalUpdates = [];
        $optionalParams = [];
        foreach ([
            'coupon_code' => $couponCode,
            'coupon_discount_type' => $couponData['discount_type'] ?? '',
            'coupon_discount_value' => (int)($couponData['discount_value'] ?? 0),
            'coupon_discount_amount' => $couponDiscount,
            'payment_method' => $paymentMethod,
        ] as $col => $val) {
            if (table_column_exists($pdo, 'projects', $col)) {
                $optionalUpdates[] = "`$col` = ?";
                $optionalParams[] = $val;
            }
        }
        if ($optionalUpdates) {
            $optionalParams[] = $projectId;
            $pdo->prepare("UPDATE projects SET " . implode(', ', $optionalUpdates) . " WHERE id = ? LIMIT 1")
                ->execute($optionalParams);
        }

        $savedFiles = save_project_files($pdo, $projectId, $BASE_URL);
        if (count($savedFiles) > 0 && table_column_exists($pdo, 'projects', 'attachment_json')) {
            $update = $pdo->prepare("UPDATE projects SET attachment_json = ? WHERE id = ? LIMIT 1");
            $update->execute([
                json_encode($savedFiles, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                $projectId,
            ]);
        }

        if (table_exists($pdo, 'project_skills')) {
            $skillStmt = $pdo->prepare("INSERT IGNORE INTO project_skills (project_id, skill_id) VALUES (?, ?)");
            foreach ($skillIds as $skillId) {
                $skillStmt->execute([$projectId, $skillId]);
            }
        }

        if (count($optionIds) > 0 && table_exists($pdo, 'project_selected_options')) {
            $priceColumn = table_column_exists($pdo, 'project_selected_options', 'price_at_submit') ? 'price_at_submit' : 'price_amount';
            $optionStmt = $pdo->prepare("INSERT IGNORE INTO project_selected_options (project_id, option_id, `$priceColumn`) VALUES (?, ?, ?)");
            foreach ($optionIds as $optionId) {
                $optionStmt->execute([$projectId, $optionId, $priceMap[$optionId] ?? 0]);
            }
        }

        $pdo->commit();

        respond(true, [
            'project_id' => $projectId,
            'status' => $projectStatus,
            'payment_status' => $paymentStatus,
            'payment_required' => $paymentRequired,
            'subtotal_amount' => $subtotalAmount,
            'coupon_code' => $couponCode,
            'coupon_discount' => $couponDiscount,
            'payable_amount' => $payableAmount,
            'payment_method' => $paymentMethod,
            'attachments' => $savedFiles,
        ], $paymentRequired ? 'پروژه ثبت شد؛ برای فعال‌سازی پرداخت را انجام بده' : 'پروژه با موفقیت ثبت شد');

    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        // برای امنیت، جزئیات خطای دیتابیس را به کاربر نمایش نمی‌دهیم.
        respond(false, [], 'خطا در ثبت پروژه');
    }
}

respond(false, [], 'درخواست نامعتبر است');
