<?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;

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

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

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

function detail_log($title, $data = []) {
    @file_put_contents(__DIR__ . '/project_detail_debug.log', '[' . date('Y-m-d H:i:s') . '] ' . $title . ' ' . json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND);
}

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 column_exists(PDO $pdo, $table, $column) {
    try { if (!table_exists($pdo, $table)) return false; $stmt = $pdo->prepare("SHOW COLUMNS FROM `$table` LIKE ?"); $stmt->execute([$column]); return $stmt->fetchColumn() !== false; }
    catch (Throwable $e) { return false; }
}

function fetch_one(PDO $pdo, $sql, $params = []) {
    try { $stmt = $pdo->prepare($sql); $stmt->execute($params); $row = $stmt->fetch(PDO::FETCH_ASSOC); return is_array($row) ? $row : null; }
    catch (Throwable $e) { detail_log('fetch_one_failed', ['sql' => $sql, 'error' => $e->getMessage()]); return null; }
}

function fetch_all(PDO $pdo, $sql, $params = []) {
    try { $stmt = $pdo->prepare($sql); $stmt->execute($params); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); return is_array($rows) ? $rows : []; }
    catch (Throwable $e) { detail_log('fetch_all_failed', ['sql' => $sql, 'error' => $e->getMessage()]); return []; }
}

function verify_session(PDO $pdo, $userId, $apiToken) {
    if ($userId <= 0 || trim((string)$apiToken) === '') return false;
    $user = fetch_one($pdo, 'SELECT id, api_token_hash FROM users WHERE id = ? LIMIT 1', [$userId]);
    if (!$user) return false;
    $stored = trim((string)($user['api_token_hash'] ?? ''));
    if ($stored === '') return false;
    if (preg_match('/^[a-f0-9]{64}$/i', $stored)) return hash_equals(strtolower($stored), hash('sha256', $apiToken));
    if (strpos($stored, '$2y$') === 0 || strpos($stored, '$argon2') === 0) return password_verify($apiToken, $stored);
    return false;
}

function fa_digits($value) {
    return strtr((string)$value, ['0'=>'۰','1'=>'۱','2'=>'۲','3'=>'۳','4'=>'۴','5'=>'۵','6'=>'۶','7'=>'۷','8'=>'۸','9'=>'۹']);
}

function toman_text($amount) {
    $amount = (int)$amount;
    if ($amount <= 0) return 'رایگان';
    return fa_digits(number_format($amount)) . ' تومان';
}

function clean_text($value, $fallback = '') {
    $value = trim((string)$value);
    return $value !== '' ? $value : $fallback;
}

function first_char_fa($value, $fallback = 'ف') {
    $value = trim((string)$value);
    if ($value === '') return $fallback;
    if (function_exists('mb_substr')) return mb_substr($value, 0, 1, 'UTF-8');
    return substr($value, 0, 1);
}

function gregorian_to_jalali($gy, $gm, $gd) {
    $g_d_m = [0,31,59,90,120,151,181,212,243,273,304,334];
    $gy2 = ($gm > 2) ? ($gy + 1) : $gy;
    $days = 355666 + (365 * $gy) + (int)(($gy2 + 3) / 4) - (int)(($gy2 + 99) / 100) + (int)(($gy2 + 399) / 400) + $gd + $g_d_m[$gm - 1];
    $jy = -1595 + (33 * (int)($days / 12053));
    $days %= 12053;
    $jy += 4 * (int)($days / 1461);
    $days %= 1461;
    if ($days > 365) { $jy += (int)(($days - 1) / 365); $days = ($days - 1) % 365; }
    if ($days < 186) { $jm = 1 + (int)($days / 31); $jd = 1 + ($days % 31); }
    else { $jm = 7 + (int)(($days - 186) / 30); $jd = 1 + (($days - 186) % 30); }
    return [$jy, $jm, $jd];
}

function jalali_date_text($raw) {
    $raw = trim((string)$raw);
    if ($raw === '' || $raw === '0000-00-00 00:00:00' || $raw === '0000-00-00') return '';
    $ts = strtotime($raw);
    if ($ts === false) return '';
    [$jy, $jm, $jd] = gregorian_to_jalali((int)date('Y', $ts), (int)date('n', $ts), (int)date('j', $ts));
    return fa_digits(sprintf('%04d/%02d/%02d', $jy, $jm, $jd));
}

function first_date_text($row, $keys = ['created_at','created_date','paid_at','updated_at']) {
    foreach ($keys as $key) if (array_key_exists($key, $row)) { $d = jalali_date_text($row[$key]); if ($d !== '') return $d; }
    return '';
}

function lookup_title(PDO $pdo, $table, $id, $titleColumns = ['title','name','name_fa']) {
    $id = (int)$id;
    if ($id <= 0 || !table_exists($pdo, $table)) return '';
    foreach ($titleColumns as $column) {
        if (!column_exists($pdo, $table, $column)) continue;
        $row = fetch_one($pdo, "SELECT `$column` AS title FROM `$table` WHERE id = ? LIMIT 1", [$id]);
        if ($row && trim((string)($row['title'] ?? '')) !== '') return trim((string)$row['title']);
    }
    return '';
}

function budget_info(PDO $pdo, $row) {
    $custom = (int)($row['is_custom_budget'] ?? 0) === 1 || (int)($row['custom_budget_enabled'] ?? 0) === 1;
    if ($custom) {
        $min = (int)($row['custom_budget_min'] ?? 0);
        $max = (int)($row['custom_budget_max'] ?? 0);
        $range = 'بودجه مشخص نشده';
        if ($min > 0 && $max > 0) $range = toman_text($min) . ' تا ' . toman_text($max);
        elseif ($min > 0) $range = 'از ' . toman_text($min);
        elseif ($max > 0) $range = 'تا ' . toman_text($max);
        return ['بودجه دلخواه', $range];
    }
    $budgetId = (int)($row['budget_range_id'] ?? 0);
    $title = 'بودجه مشخص نشده';
    $range = 'بودجه مشخص نشده';
    if ($budgetId > 0 && table_exists($pdo, 'project_budget_ranges')) {
        $columns = ['id'];
        foreach (['title','name','min_budget','max_budget'] as $col) if (column_exists($pdo, 'project_budget_ranges', $col)) $columns[] = "`$col`";
        $budget = fetch_one($pdo, 'SELECT ' . implode(',', $columns) . ' FROM project_budget_ranges WHERE id = ? LIMIT 1', [$budgetId]);
        if ($budget) {
            $titleCandidate = trim((string)($budget['title'] ?? $budget['name'] ?? ''));
            if ($titleCandidate !== '') $title = $titleCandidate;
            $min = (int)($budget['min_budget'] ?? 0); $max = (int)($budget['max_budget'] ?? 0);
            if ($min > 0 && $max > 0) $range = toman_text($min) . ' تا ' . toman_text($max);
            elseif ($min > 0) $range = 'بیش از ' . toman_text($min);
            elseif ($max > 0) $range = 'تا ' . toman_text($max);
            else $range = $title;
        }
    }
    return [$title, $range];
}

function deadline_text(PDO $pdo, $row) {
    $custom = trim((string)($row['custom_deadline_text'] ?? ''));
    if ($custom !== '') return $custom;
    $deadlineId = (int)($row['deadline_option_id'] ?? 0);
    $title = lookup_title($pdo, 'project_deadline_options', $deadlineId, ['title','name']);
    return $title !== '' ? $title : 'زمان مشخص نشده';
}

function classify_project($status, $paymentStatus, $paymentAmount) {
    $s = strtolower(trim((string)$status));
    $p = strtolower(trim((string)$paymentStatus));
    $amount = (int)$paymentAmount;
    if (in_array($s, ['cancelled','canceled','deleted'], true)) return ['cancelled', 'لغو شده', '#EF4056', 'این پروژه لغو شده یا از چرخه اجرا خارج شده است.', 0];
    if (in_array($s, ['completed','done','finished'], true)) return ['completed', 'تکمیل شده', '#18A957', 'پروژه تکمیل شده و آماده آرشیو است.', 100];
    if ($amount > 0 && !in_array($p, ['paid','free','completed'], true)) {
        $label = in_array($p, ['failed','verify_failed'], true) ? 'پرداخت ناموفق' : 'در انتظار پرداخت';
        return ['draft', $label, '#F59E0B', 'برای انتشار پروژه باید پرداخت ثبت پروژه کامل شود.', 18];
    }
    if (in_array($s, ['draft','unpaid','pending_payment'], true)) return ['draft', 'پیش‌نویس', '#F59E0B', 'این پروژه هنوز برای فریلنسرها منتشر نشده است.', 12];
    if (in_array($s, ['awarded','escrow_pending'], true)) return ['active', 'انتخاب فریلنسر', '#2F5BEA', 'پیشنهاد انتخاب شده و مرحله گروگذاری باید تکمیل شود.', 55];
    if (in_array($s, ['in_progress','running'], true)) return ['active', 'در حال اجرا', '#2F5BEA', 'پروژه در حال انجام است.', 72];
    if (in_array($s, ['submitted','delivered'], true)) return ['active', 'تحویل‌شده', '#2F5BEA', 'فریلنسر کار را تحویل داده و منتظر بررسی کارفرماست.', 84];
    if (in_array($s, ['dispute'], true)) return ['active', 'اختلاف', '#EF4056', 'پرونده اختلاف باز است و مدیریت باید بررسی کند.', 65];
    return ['active', 'منتشر شده', '#2F5BEA', 'پروژه منتشر شده و آماده دریافت پیشنهاد است.', 35];
}

function payment_label($paymentStatus, $amount) {
    $p = strtolower(trim((string)$paymentStatus)); $amount = (int)$amount;
    if ($amount <= 0) return 'رایگان';
    if (in_array($p, ['paid','free','completed'], true)) return 'پرداخت شده';
    if (in_array($p, ['failed','verify_failed'], true)) return 'پرداخت ناموفق';
    if (in_array($p, ['payment_started','token_created','redirected'], true)) return 'در حال پرداخت';
    return 'در انتظار پرداخت';
}

function get_user_name(PDO $pdo, $userId, $fallback = 'کاربر') {
    $userId = (int)$userId;
    if ($userId <= 0 || !table_exists($pdo, 'users')) return $fallback;
    $columns = ['id'];
    foreach (['full_name','name','display_name','mobile_number','phone'] as $col) if (column_exists($pdo, 'users', $col)) $columns[] = "`$col`";
    $row = fetch_one($pdo, 'SELECT ' . implode(',', $columns) . ' FROM users WHERE id = ? LIMIT 1', [$userId]);
    if (!$row) return $fallback;
    foreach (['full_name','name','display_name','mobile_number','phone'] as $col) {
        if (isset($row[$col]) && trim((string)$row[$col]) !== '') return trim((string)$row[$col]);
    }
    return $fallback;
}

function count_project_offers(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_offers') || !column_exists($pdo, 'project_offers', 'project_id')) return 0;
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM project_offers WHERE project_id = ?');
    $stmt->execute([$projectId]);
    return (int)$stmt->fetchColumn();
}

function count_unread_project_messages(PDO $pdo, $projectId, $userId) {
    if (!table_exists($pdo, 'project_messages') || !column_exists($pdo, 'project_messages', 'project_id')) return 0;
    $userColumn = null;
    foreach (['receiver_user_id','to_user_id','user_id'] as $col) if (column_exists($pdo, 'project_messages', $col)) { $userColumn = $col; break; }
    if (!$userColumn) return 0;
    try {
        if (column_exists($pdo, 'project_messages', 'is_read')) $stmt = $pdo->prepare("SELECT COUNT(*) FROM project_messages WHERE project_id = ? AND `$userColumn` = ? AND is_read = 0");
        elseif (column_exists($pdo, 'project_messages', 'read_at')) $stmt = $pdo->prepare("SELECT COUNT(*) FROM project_messages WHERE project_id = ? AND `$userColumn` = ? AND read_at IS NULL");
        else return 0;
        $stmt->execute([$projectId, $userId]);
        return (int)$stmt->fetchColumn();
    } catch (Throwable $e) { return 0; }
}

function project_badges(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_selected_options') || !table_exists($pdo, 'project_options')) return [];
    if (!column_exists($pdo, 'project_selected_options', 'project_id') || !column_exists($pdo, 'project_selected_options', 'option_id')) return [];
    $titleExpr = column_exists($pdo, 'project_options', 'title') ? 'po.title' : "'ویژه'";
    $badgeExpr = column_exists($pdo, 'project_options', 'badge_text') ? 'po.badge_text' : "''";
    $colorExpr = column_exists($pdo, 'project_options', 'badge_color_key') ? 'po.badge_color_key' : "'featured'";
    $keyExpr = column_exists($pdo, 'project_options', 'option_key') ? 'po.option_key' : "''";
    $rows = fetch_all($pdo, "SELECT po.id, $titleExpr AS title, $badgeExpr AS badge_text, $colorExpr AS color_key, $keyExpr AS option_key FROM project_selected_options pso INNER JOIN project_options po ON po.id = pso.option_id WHERE pso.project_id = ? ORDER BY po.id ASC LIMIT 10", [$projectId]);
    $badges = [];
    foreach ($rows as $row) {
        $title = clean_text($row['badge_text'] ?? '', ''); if ($title === '') $title = clean_text($row['title'] ?? '', 'ویژه');
        $key = strtolower((string)($row['option_key'] ?? ''));
        $color = clean_text($row['color_key'] ?? '', '');
        if ($color === '') {
            if (strpos($key, 'urgent') !== false) $color = 'urgent';
            elseif (strpos($key, 'featured') !== false) $color = 'featured';
            elseif (strpos($key, 'infinity') !== false) $color = 'infinity';
            elseif (strpos($key, 'private') !== false) $color = 'private';
            else $color = 'featured';
        }
        $badges[] = ['title' => $title, 'color_key' => $color];
    }
    return $badges;
}

function project_options(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_selected_options') || !table_exists($pdo, 'project_options')) return [];
    if (!column_exists($pdo, 'project_selected_options', 'project_id') || !column_exists($pdo, 'project_selected_options', 'option_id')) return [];

    $titleExpr = column_exists($pdo, 'project_options', 'title') ? 'po.title' : "'ویژگی پروژه'";
    $descExpr = column_exists($pdo, 'project_options', 'description') ? 'po.description' : "''";
    $priceSelect = column_exists($pdo, 'project_options', 'price') ? 'po.price' : '0';
    $originalSelect = column_exists($pdo, 'project_options', 'original_price') ? 'po.original_price' : $priceSelect;
    $discountSelect = column_exists($pdo, 'project_options', 'discount_price') ? 'po.discount_price' : '0';
    $storedPriceSelect = column_exists($pdo, 'project_selected_options', 'price_at_submit')
        ? 'pso.price_at_submit'
        : (column_exists($pdo, 'project_selected_options', 'price_amount') ? 'pso.price_amount' : '0');

    $rows = fetch_all($pdo, "
        SELECT po.id,
               $titleExpr AS title,
               $descExpr AS description,
               $priceSelect AS catalog_price,
               $originalSelect AS catalog_original_price,
               $discountSelect AS catalog_discount_price,
               $storedPriceSelect AS stored_price
        FROM project_selected_options pso
        INNER JOIN project_options po ON po.id = pso.option_id
        WHERE pso.project_id = ?
        ORDER BY po.id ASC
        LIMIT 20
    ", [$projectId]);

    $out = [];
    foreach ($rows as $row) {
        $base = (int)($row['catalog_price'] ?? 0);
        $original = (int)($row['catalog_original_price'] ?? 0);
        if ($original <= 0) $original = $base;
        $discount = (int)($row['catalog_discount_price'] ?? 0);
        $storedPrice = (int)($row['stored_price'] ?? 0);
        $catalogDisplayPrice = ($discount > 0 && $original > 0 && $discount < $original) ? $discount : $original;
        // در جزئیات پروژه قیمت واقعی ویژگی نمایش داده می‌شود.
        // اگر موقع ویرایش همان ویژگی رایگان محاسبه شده باشد، اینجا رایگان نشان داده نمی‌شود.
        $displayPrice = $storedPrice > 0 ? $storedPrice : $catalogDisplayPrice;
        $displayPrice = max(0, (int)$displayPrice);
        $out[] = [
            'id' => (int)$row['id'],
            'title' => clean_text($row['title'] ?? '', 'ویژگی پروژه'),
            'description' => clean_text($row['description'] ?? '', ''),
            'price' => $displayPrice,
            'price_text' => toman_text($displayPrice),
        ];
    }
    return $out;
}

function project_skills(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_skills') || !column_exists($pdo, 'project_skills', 'project_id')) return [];
    $skillTable = table_exists($pdo, 'skills') ? 'skills' : '';
    if ($skillTable === '' || !column_exists($pdo, 'project_skills', 'skill_id')) return [];
    $titleCol = null;
    foreach (['name_fa','title','name'] as $col) if (column_exists($pdo, 'skills', $col)) { $titleCol = $col; break; }
    if (!$titleCol) return [];
    $rows = fetch_all($pdo, "SELECT s.id, s.`$titleCol` AS title FROM project_skills ps INNER JOIN skills s ON s.id = ps.skill_id WHERE ps.project_id = ? ORDER BY s.`$titleCol` ASC LIMIT 30", [$projectId]);
    $out = [];
    foreach ($rows as $row) $out[] = ['id' => (int)$row['id'], 'title' => clean_text($row['title'] ?? '', 'مهارت')];
    return $out;
}

function file_size_text($size) {
    $size = (int)$size;
    if ($size <= 0) return '';
    if ($size >= 1024 * 1024) return fa_digits((string)round($size / 1024 / 1024, 1)) . ' مگابایت';
    if ($size >= 1024) return fa_digits((string)round($size / 1024, 1)) . ' کیلوبایت';
    return fa_digits((string)$size) . ' بایت';
}

function project_files(PDO $pdo, $projectId, $row) {
    $out = [];
    $seen = [];

    if (table_exists($pdo, 'project_attachments') && column_exists($pdo, 'project_attachments', 'project_id')) {
        $nameExpr = column_exists($pdo, 'project_attachments', 'original_name') ? 'original_name' : (column_exists($pdo, 'project_attachments', 'file_name') ? 'file_name' : "''");
        $urlExpr = column_exists($pdo, 'project_attachments', 'file_url') ? 'file_url' : (column_exists($pdo, 'project_attachments', 'file_path') ? 'file_path' : "''");
        $mimeExpr = column_exists($pdo, 'project_attachments', 'mime_type') ? 'mime_type' : "''";
        $sizeExpr = column_exists($pdo, 'project_attachments', 'file_size') ? 'file_size' : '0';
        $rows = fetch_all($pdo, "SELECT $nameExpr AS name, $urlExpr AS url, $mimeExpr AS mime_type, $sizeExpr AS file_size FROM project_attachments WHERE project_id = ? ORDER BY id ASC LIMIT 20", [$projectId]);
        foreach ($rows as $f) {
            $url = clean_text($f['url'] ?? '', '');
            $name = clean_text($f['name'] ?? '', 'فایل پیوست');
            if ($url !== '' && !preg_match('~^https?://~i', $url)) $url = 'https://pnartl.ir/doorkar/' . ltrim($url, '/');
            $key = $url !== '' ? $url : $name;
            if (isset($seen[$key])) continue;
            $seen[$key] = true;
            $size = (int)($f['file_size'] ?? 0);
            $out[] = [
                'name' => $name,
                'url' => $url,
                'mime_type' => clean_text($f['mime_type'] ?? '', ''),
                'size' => $size,
                'size_text' => file_size_text($size),
            ];
        }
    }

    $raw = trim((string)($row['attachment_json'] ?? ''));
    if ($raw !== '') {
        $json = json_decode($raw, true);
        if (is_array($json)) {
            foreach ($json as $item) {
                if (!is_array($item)) continue;
                $url = clean_text($item['url'] ?? '', '');
                $name = clean_text($item['name'] ?? $item['filename'] ?? '', 'فایل پیوست');
                if ($url !== '' && !preg_match('~^https?://~i', $url)) $url = 'https://pnartl.ir/doorkar/' . ltrim($url, '/');
                $key = $url !== '' ? $url : $name;
                if (isset($seen[$key])) continue;
                $seen[$key] = true;
                $size = (int)($item['size'] ?? $item['file_size'] ?? 0);
                $out[] = [
                    'name' => $name,
                    'url' => $url,
                    'mime_type' => clean_text($item['mime_type'] ?? '', ''),
                    'size' => $size,
                    'size_text' => file_size_text($size),
                ];
            }
        }
    }

    return $out;
}

function project_offers(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_offers') || !column_exists($pdo, 'project_offers', 'project_id')) return [];
    $order = column_exists($pdo, 'project_offers', 'status')
        ? "ORDER BY CASE WHEN status IN ('accepted','selected','awarded') THEN 0 ELSE 1 END, id DESC"
        : "ORDER BY id DESC";
    $rows = fetch_all($pdo, "SELECT * FROM project_offers WHERE project_id = ? $order LIMIT 100", [$projectId]);
    $out = [];
    foreach ($rows as $row) {
        $freelancerId = 0;
        foreach (['freelancer_user_id','freelancer_id','user_id'] as $col) if (isset($row[$col])) { $freelancerId = (int)$row[$col]; break; }
        $name = get_user_name($pdo, $freelancerId, 'فریلنسر');
        $amount = 0;
        foreach (['amount','offer_amount','price','bid_amount'] as $col) if (isset($row[$col])) { $amount = (int)$row[$col]; break; }
        $delivery = '';
        foreach (['delivery_text','delivery_time','duration','deadline_text'] as $col) if (isset($row[$col]) && trim((string)$row[$col]) !== '') { $delivery = trim((string)$row[$col]); break; }
        $body = '';
        foreach (['proposal_text','description','message','body'] as $col) if (isset($row[$col]) && trim((string)$row[$col]) !== '') { $body = trim((string)$row[$col]); break; }
        $status = strtolower(clean_text($row['status'] ?? '', 'pending'));
        $isSelected = in_array($status, ['accepted','selected','awarded'], true);
        if ($isSelected) $statusLabel = 'انتخاب شده';
        elseif (in_array($status, ['rejected','declined'], true)) $statusLabel = 'رد شده';
        else $statusLabel = 'در انتظار بررسی';
        $out[] = [
            'id' => (int)($row['id'] ?? 0),
            'freelancer_user_id' => $freelancerId,
            'freelancer_name' => $name,
            'freelancer_initial' => first_char_fa($name, 'ف'),
            'amount' => $amount,
            'amount_text' => toman_text($amount),
            'delivery_text' => $delivery !== '' ? $delivery : 'زمان نامشخص',
            'proposal_text' => $body !== '' ? $body : 'متن پیشنهاد ثبت نشده است.',
            'status' => $status,
            'status_label' => $statusLabel,
            'is_selected' => $isSelected,
            'rating_text' => 'بدون امتیاز',
            'created_text' => first_date_text($row),
        ];
    }
    return $out;
}

function project_messages(PDO $pdo, $projectId, $currentUserId) {
    if (!table_exists($pdo, 'project_messages') || !column_exists($pdo, 'project_messages', 'project_id')) return [];
    $rows = fetch_all($pdo, 'SELECT * FROM project_messages WHERE project_id = ? ORDER BY id DESC LIMIT 80', [$projectId]);
    $out = [];
    foreach (array_reverse($rows) as $row) {
        $senderId = 0;
        foreach (['sender_user_id','from_user_id','user_id'] as $col) if (isset($row[$col])) { $senderId = (int)$row[$col]; break; }
        $body = '';
        foreach (['body','message','text','content'] as $col) if (isset($row[$col]) && trim((string)$row[$col]) !== '') { $body = trim((string)$row[$col]); break; }
        $type = clean_text($row['message_type'] ?? $row['type'] ?? '', 'text');
        $out[] = [
            'id' => (int)($row['id'] ?? 0),
            'sender_user_id' => $senderId,
            'sender_name' => $type === 'system' ? 'پیام سیستمی' : get_user_name($pdo, $senderId, 'کاربر'),
            'body' => $body,
            'message_type' => $type,
            'is_me' => $senderId > 0 && $senderId === (int)$currentUserId,
            'created_text' => first_date_text($row),
        ];
    }
    return $out;
}

function project_payments(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_payments') || !column_exists($pdo, 'project_payments', 'project_id')) return [];
    $rows = fetch_all($pdo, 'SELECT * FROM project_payments WHERE project_id = ? ORDER BY id DESC LIMIT 50', [$projectId]);
    $out = [];
    foreach ($rows as $row) {
        $status = strtolower(clean_text($row['status'] ?? '', ''));
        $amount = (int)($row['amount'] ?? 0);
        $out[] = [
            'id' => (int)($row['id'] ?? 0),
            'status' => $status,
            'status_label' => $status === 'paid' ? 'پرداخت موفق' : ($status === 'failed' || $status === 'verify_failed' ? 'پرداخت ناموفق' : 'در حال پرداخت'),
            'amount' => $amount,
            'amount_text' => toman_text($amount),
            'res_num' => clean_text($row['res_num'] ?? '', ''),
            'ref_num' => clean_text($row['ref_num'] ?? '', ''),
            'trace_no' => clean_text($row['trace_no'] ?? '', ''),
            'created_text' => first_date_text($row),
        ];
    }
    return $out;
}

function project_escrows(PDO $pdo, $projectId) {
    if (!table_exists($pdo, 'project_escrows') || !column_exists($pdo, 'project_escrows', 'project_id')) return [[], 0, 0];
    $rows = fetch_all($pdo, 'SELECT * FROM project_escrows WHERE project_id = ? ORDER BY id DESC LIMIT 50', [$projectId]);
    $out = []; $total = 0; $percentTotal = 0;
    foreach ($rows as $row) {
        $amount = 0;
        foreach (['escrow_amount','held_amount','amount'] as $col) if (isset($row[$col])) { $amount = (int)$row[$col]; break; }
        $percent = 0;
        foreach (['escrow_percent','percent','percentage'] as $col) if (isset($row[$col])) { $percent = (int)$row[$col]; break; }
        $status = strtolower(clean_text($row['status'] ?? '', 'held'));
        $active = in_array($status, ['held','active','pending','paid'], true);
        if ($active) { $total += $amount; $percentTotal += max(0, $percent); }
        if (in_array($status, ['held','active','paid'], true)) $statusLabel = 'گروگذاری‌شده';
        elseif ($status === 'pending') $statusLabel = 'در انتظار پرداخت/تأیید';
        elseif (in_array($status, ['released','paid_out'], true)) $statusLabel = 'آزاد شده';
        elseif (in_array($status, ['failed','cancelled','canceled'], true)) $statusLabel = 'ناموفق/لغو شده';
        else $statusLabel = 'ثبت شده';
        $out[] = [
            'id' => (int)($row['id'] ?? 0),
            'offer_id' => (int)($row['offer_id'] ?? 0),
            'amount' => $amount,
            'amount_text' => toman_text($amount),
            'percent' => $percent,
            'percent_text' => $percent > 0 ? fa_digits($percent) . '٪' : '',
            'status' => $status,
            'status_label' => $statusLabel,
            'created_text' => first_date_text($row),
        ];
    }
    return [$out, $total, min(100, $percentTotal)];
}

function selected_offer_from_list($offers) {
    foreach ($offers as $offer) {
        if (!empty($offer['is_selected'])) return $offer;
    }
    return null;
}

function ensure_project_escrows_table(PDO $pdo) {
    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS project_escrows (
            id INT AUTO_INCREMENT PRIMARY KEY,
            project_id INT NOT NULL,
            offer_id INT NULL,
            employer_user_id INT NULL,
            freelancer_user_id INT NULL,
            escrow_amount BIGINT NOT NULL DEFAULT 0,
            escrow_percent INT NOT NULL DEFAULT 0,
            status VARCHAR(32) NOT NULL DEFAULT 'pending',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            INDEX idx_project_id (project_id),
            INDEX idx_offer_id (offer_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    } catch (Throwable $e) {
        detail_log('ensure_project_escrows_failed', ['error' => $e->getMessage()]);
    }
}

function offer_amount_from_row($row) {
    foreach (['amount','offer_amount','price','bid_amount'] as $col) {
        if (isset($row[$col]) && (int)$row[$col] > 0) return (int)$row[$col];
    }
    return 0;
}

function offer_freelancer_id_from_row($row) {
    foreach (['freelancer_user_id','freelancer_id','user_id'] as $col) {
        if (isset($row[$col]) && (int)$row[$col] > 0) return (int)$row[$col];
    }
    return 0;
}

function insert_system_project_message(PDO $pdo, $projectId, $body) {
    if (!table_exists($pdo, 'project_messages') || !column_exists($pdo, 'project_messages', 'project_id')) return;
    $cols = ['project_id'];
    $vals = [$projectId];
    foreach ([
        'sender_user_id' => 0,
        'from_user_id' => 0,
        'message_type' => 'system',
        'type' => 'system',
        'body' => $body,
        'message' => $body,
        'text' => $body,
        'content' => $body,
        'created_at' => date('Y-m-d H:i:s'),
    ] as $col => $val) {
        if (column_exists($pdo, 'project_messages', $col)) { $cols[] = $col; $vals[] = $val; }
    }
    try {
        $placeholders = implode(',', array_fill(0, count($cols), '?'));
        $quoted = '`' . implode('`,`', $cols) . '`';
        $pdo->prepare("INSERT INTO project_messages ($quoted) VALUES ($placeholders)")->execute($vals);
    } catch (Throwable $e) {
        detail_log('insert_system_project_message_failed', ['error' => $e->getMessage()]);
    }
}

function add_optional_project_update(PDO $pdo, &$sets, &$params, $column, $value) {
    if (column_exists($pdo, 'projects', $column)) { $sets[] = "`$column` = ?"; $params[] = $value; }
}

function award_offer_with_escrow(PDO $pdo, $projectId, $userId, $offerId, $percent) {
    if (!table_exists($pdo, 'project_offers') || !column_exists($pdo, 'project_offers', 'project_id')) respond(false, [], 'جدول پیشنهادها پیدا نشد');
    if (!column_exists($pdo, 'project_offers', 'status')) respond(false, [], 'ستون status در جدول پیشنهادها وجود ندارد');
    ensure_project_escrows_table($pdo);
    if (!table_exists($pdo, 'project_escrows') || !column_exists($pdo, 'project_escrows', 'project_id')) respond(false, [], 'جدول گروگذاری آماده نیست');

    $allowedPercents = [25, 50, 75, 100];
    if (!in_array((int)$percent, $allowedPercents, true)) respond(false, [], 'درصد گروگذاری معتبر نیست');

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

    $offer = fetch_one($pdo, 'SELECT * FROM project_offers WHERE id = ? AND project_id = ? LIMIT 1', [$offerId, $projectId]);
    if (!$offer) respond(false, [], 'پیشنهاد انتخابی پیدا نشد');

    $amount = offer_amount_from_row($offer);
    if ($amount <= 0) respond(false, [], 'مبلغ پیشنهاد معتبر نیست');
    $freelancerId = offer_freelancer_id_from_row($offer);
    $escrowAmount = (int)ceil($amount * ((int)$percent) / 100);

    try {
        $pdo->beginTransaction();

        $pdo->prepare("UPDATE project_offers SET status = 'rejected' WHERE project_id = ? AND id <> ? AND status NOT IN ('accepted','selected','awarded')")
            ->execute([$projectId, $offerId]);

        $offerSets = ["status = 'accepted'"];
        $offerParams = [];
        if (column_exists($pdo, 'project_offers', 'accepted_at')) $offerSets[] = "accepted_at = NOW()";
        if (column_exists($pdo, 'project_offers', 'updated_at')) $offerSets[] = "updated_at = NOW()";
        $offerParams[] = $offerId;
        $offerParams[] = $projectId;
        $pdo->prepare('UPDATE project_offers SET ' . implode(', ', $offerSets) . ' WHERE id = ? AND project_id = ? LIMIT 1')->execute($offerParams);

        $sets = [];
        $params = [];
        add_optional_project_update($pdo, $sets, $params, 'status', 'escrow_pending');
        add_optional_project_update($pdo, $sets, $params, 'selected_offer_id', $offerId);
        add_optional_project_update($pdo, $sets, $params, 'accepted_offer_id', $offerId);
        add_optional_project_update($pdo, $sets, $params, 'freelancer_user_id', $freelancerId);
        add_optional_project_update($pdo, $sets, $params, 'selected_freelancer_user_id', $freelancerId);
        add_optional_project_update($pdo, $sets, $params, 'awarded_freelancer_user_id', $freelancerId);
        if (column_exists($pdo, 'projects', 'updated_at')) $sets[] = 'updated_at = NOW()';
        if ($sets) {
            $params[] = $projectId;
            $pdo->prepare('UPDATE projects SET ' . implode(', ', $sets) . ' WHERE id = ? LIMIT 1')->execute($params);
        }

        $escrowCols = ['project_id'];
        $escrowVals = [$projectId];
        foreach ([
            'offer_id' => $offerId,
            'employer_user_id' => $userId,
            'freelancer_user_id' => $freelancerId,
            'escrow_amount' => $escrowAmount,
            'held_amount' => $escrowAmount,
            'amount' => $escrowAmount,
            'escrow_percent' => (int)$percent,
            'percent' => (int)$percent,
            'percentage' => (int)$percent,
            'status' => 'pending',
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ] as $col => $val) {
            if (column_exists($pdo, 'project_escrows', $col)) { $escrowCols[] = $col; $escrowVals[] = $val; }
        }
        $placeholders = implode(',', array_fill(0, count($escrowCols), '?'));
        $quoted = '`' . implode('`,`', $escrowCols) . '`';
        $pdo->prepare("INSERT INTO project_escrows ($quoted) VALUES ($placeholders)")->execute($escrowVals);

        $freelancerName = get_user_name($pdo, $freelancerId, 'فریلنسر');
        insert_system_project_message($pdo, $projectId, 'پیشنهاد ' . $freelancerName . ' انتخاب شد و گروگذاری ' . fa_digits((int)$percent) . '٪ به مبلغ ' . toman_text($escrowAmount) . ' ثبت شد.');

        $pdo->commit();
        respond(true, [
            'project_id' => $projectId,
            'offer_id' => $offerId,
            'escrow_percent' => (int)$percent,
            'escrow_amount' => $escrowAmount,
            'escrow_amount_text' => toman_text($escrowAmount),
        ], 'پیشنهاد انتخاب شد و گروگذاری ثبت شد');
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        detail_log('award_offer_with_escrow_failed', ['error' => $e->getMessage(), 'project_id' => $projectId, 'offer_id' => $offerId]);
        respond(false, [], 'خطا در انتخاب پیشنهاد و ثبت گروگذاری');
    }
}

function timeline_for($group, $statusLabel, $paymentPaid, $offersCount, $escrowTotal) {
    return [
        ['title' => 'ثبت پروژه', 'subtitle' => 'مشخصات پروژه ثبت شده است.', 'done' => true],
        ['title' => 'پرداخت ثبت پروژه', 'subtitle' => $paymentPaid ? 'پرداخت ثبت پروژه کامل شده است.' : 'برای انتشار، پرداخت باید کامل شود.', 'done' => $paymentPaid],
        ['title' => 'دریافت پیشنهاد', 'subtitle' => $offersCount > 0 ? fa_digits($offersCount) . ' پیشنهاد دریافت شده است.' : 'هنوز پیشنهادی ثبت نشده است.', 'done' => $offersCount > 0],
        ['title' => 'انتخاب فریلنسر', 'subtitle' => 'در فاز بعد از تب پیشنهادها انجام می‌شود.', 'done' => in_array($statusLabel, ['انتخاب فریلنسر','در حال اجرا','تحویل‌شده','تکمیل شده'], true)],
        ['title' => 'گروگذاری', 'subtitle' => $escrowTotal > 0 ? 'مبلغ ' . toman_text($escrowTotal) . ' گروگذاری شده است.' : 'بعد از انتخاب پیشنهاد، گروگذاری فعال می‌شود.', 'done' => $escrowTotal > 0],
        ['title' => 'تکمیل پروژه', 'subtitle' => 'پس از تحویل و آزادسازی نهایی تکمیل می‌شود.', 'done' => $group === 'completed'],
    ];
}

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

$input = input_json();
$action = trim((string)($input['action'] ?? ''));
$userId = (int)($input['user_id'] ?? 0);
$apiToken = trim((string)($input['api_token'] ?? ''));
$projectId = (int)($input['project_id'] ?? 0);

if (!verify_session($pdo, $userId, $apiToken)) respond(false, [], 'نشست ورود معتبر نیست؛ دوباره وارد حساب شو');
if ($projectId <= 0) respond(false, [], 'شناسه پروژه معتبر نیست');
if (!table_exists($pdo, 'projects')) respond(false, [], 'جدول پروژه‌ها هنوز ساخته نشده است');
if (!column_exists($pdo, 'projects', 'employer_user_id')) respond(false, [], 'ساختار جدول projects ناقص است');

if ($action === 'award_offer_with_escrow') {
    $offerId = (int)($input['offer_id'] ?? 0);
    $percent = (int)($input['escrow_percent'] ?? 0);
    if ($offerId <= 0) respond(false, [], 'شناسه پیشنهاد معتبر نیست');
    award_offer_with_escrow($pdo, $projectId, $userId, $offerId, $percent);
}

if ($action !== 'get_project_detail') respond(false, [], 'درخواست نامعتبر است');

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

$title = clean_text($row['title'] ?? '', 'پروژه بدون عنوان');
$description = clean_text($row['description'] ?? '', '');
$status = clean_text($row['status'] ?? '', 'draft');
$paymentStatus = clean_text($row['payment_status'] ?? '', '');
$paymentAmount = (int)($row['payment_amount'] ?? 0);
[$group, $statusLabel, $statusColor, $statusHint, $progress] = classify_project($status, $paymentStatus, $paymentAmount);
$serviceTitle = lookup_title($pdo, 'project_service_types', (int)($row['service_type_id'] ?? 0), ['title','name']);
if ($serviceTitle === '') $serviceTitle = 'سرویس نامشخص';
[$budgetTitle, $budgetRangeText] = budget_info($pdo, $row);
$offers = project_offers($pdo, $projectId);
$selectedOffer = selected_offer_from_list($offers);
$messages = project_messages($pdo, $projectId, $userId);
$payments = project_payments($pdo, $projectId);
[$escrows, $escrowTotal, $escrowPercentTotal] = project_escrows($pdo, $projectId);
$paymentPaid = $paymentAmount <= 0 || in_array(strtolower($paymentStatus), ['paid','free','completed'], true);
$canPayAgain = $paymentAmount > 0 && !$paymentPaid;

$project = [
    'id' => $projectId,
    'title' => $title,
    'description' => $description !== '' ? $description : 'توضیحی برای این پروژه ثبت نشده است.',
    'service_title' => $serviceTitle,
    'budget_title' => $budgetTitle,
    'budget_range_text' => $budgetRangeText,
    'budget_text' => $budgetRangeText !== 'بودجه مشخص نشده' ? $budgetRangeText : $budgetTitle,
    'deadline_text' => deadline_text($pdo, $row),
    'created_text' => first_date_text($row),
    'status' => $status,
    'status_group' => $group,
    'status_label' => $statusLabel,
    'status_color' => $statusColor,
    'status_hint' => $statusHint,
    'payment_status' => $paymentStatus,
    'payment_label' => payment_label($paymentStatus, $paymentAmount),
    'payment_amount' => $paymentAmount,
    'offers_count' => count($offers),
    'unread_messages' => count_unread_project_messages($pdo, $projectId, $userId),
    'escrow_amount' => $escrowTotal,
    'escrow_percent_total' => $escrowPercentTotal,
    'progress_percent' => $progress,
    'can_pay_again' => $canPayAgain,
    'can_edit' => $group === 'draft',
    'has_selected_offer' => $selectedOffer !== null,
];

respond(true, [
    'project' => $project,
    'skills' => project_skills($pdo, $projectId),
    'badges' => project_badges($pdo, $projectId),
    'options' => project_options($pdo, $projectId),
    'files' => project_files($pdo, $projectId, $row),
    'offers' => $offers,
    'selected_offer' => $selectedOffer,
    'messages' => $messages,
    'payments' => $payments,
    'escrows' => $escrows,
    'escrow_total' => $escrowTotal,
    'escrow_percent_total' => $escrowPercentTotal,
    'timeline' => timeline_for($group, $statusLabel, $paymentPaid, count($offers), $escrowTotal),
], 'جزئیات پروژه دریافت شد');
