<?php
/* =====================================================
   File: /home/jewellersbd/public_html/erp.jewellersbd.com/api/barcode/update_barcode_item.php
   Purpose: Barcode item safe edit
   Data change: YES
   Safety:
   - NO ALTER / CREATE / DROP
   - Normal sold barcode edit block
   - 0g problem barcode edit allow
   - deleted barcode edit block
   - transfer pending/in_transit item edit block
   - price/rate/sale info update করবে না
   - existing columns অনুযায়ী update করবে
   - audit_log থাকলে entry করবে
   ===================================================== */

ini_set('display_errors', 0);
ini_set('precision', '14');
ini_set('serialize_precision', '-1');
error_reporting(E_ALL);
header('Content-Type: application/json; charset=utf-8');

require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/db.php';

function bcu_out($code, $success, $message, $data = null) {
    http_response_code($code);
    echo json_encode([
        'success' => (bool)$success,
        'status'  => (bool)$success,
        'message' => $message,
        'data'    => $data
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

if (function_exists('require_login')) {
    require_login();
} elseif (function_exists('is_logged_in') && !is_logged_in()) {
    bcu_out(401, false, 'লগইন প্রয়োজন');
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    bcu_out(405, false, 'শুধু POST অনুরোধ গ্রহণযোগ্য');
}

if (!isset($pdo) || !($pdo instanceof PDO)) {
    bcu_out(500, false, 'PDO DB connection পাওয়া যায়নি');
}

try {
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->exec("SET NAMES utf8mb4");
} catch (Throwable $e) {
    bcu_out(500, false, 'ডাটাবেজ কানেকশন সমস্যা');
}

function bcu_clean($name) {
    return preg_replace('/[^a-zA-Z0-9_]/', '', (string)$name);
}

function bcu_qi($name) {
    return '`' . str_replace('`', '', bcu_clean($name)) . '`';
}

function bcu_table_exists(PDO $pdo, $table) {
    $table = bcu_clean($table);
    if ($table === '') return false;

    $st = $pdo->query("SHOW TABLES LIKE " . $pdo->quote($table));
    return (bool)$st->fetchColumn();
}

function bcu_get_columns(PDO $pdo, $table) {
    $table = bcu_clean($table);
    if ($table === '' || !bcu_table_exists($pdo, $table)) return [];

    $rows = $pdo->query("SHOW COLUMNS FROM " . bcu_qi($table))->fetchAll(PDO::FETCH_ASSOC);
    $cols = [];

    foreach ($rows as $r) {
        if (isset($r['Field'])) {
            $cols[$r['Field']] = true;
        }
    }

    return $cols;
}

function bcu_pick_col($cols, $names) {
    foreach ($names as $n) {
        if (isset($cols[$n])) return $n;
    }
    return null;
}

function bcu_first_value($arr, $keys, $default = '') {
    foreach ($keys as $k) {
        if (array_key_exists($k, $arr) && $arr[$k] !== '' && $arr[$k] !== null) {
            return $arr[$k];
        }
    }
    return $default;
}

function bcu_first_float($arr, $keys, $default = 0) {
    foreach ($keys as $k) {
        if (array_key_exists($k, $arr) && $arr[$k] !== '' && $arr[$k] !== null) {
            return (float)$arr[$k];
        }
    }
    return (float)$default;
}

function bcu_first_int($arr, $keys, $default = 0) {
    foreach ($keys as $k) {
        if (array_key_exists($k, $arr) && $arr[$k] !== '' && $arr[$k] !== null) {
            return (int)$arr[$k];
        }
    }
    return (int)$default;
}

function bcu_user_id() {
    foreach (['user_id', 'id', 'auth_user_id'] as $k) {
        if (isset($_SESSION[$k]) && (int)$_SESSION[$k] > 0) {
            return (int)$_SESSION[$k];
        }
    }

    if (isset($_SESSION['user']) && is_array($_SESSION['user'])) {
        foreach (['id', 'user_id'] as $k) {
            if (isset($_SESSION['user'][$k]) && (int)$_SESSION['user'][$k] > 0) {
                return (int)$_SESSION['user'][$k];
            }
        }
    }

    return 0;
}

function bcu_client_ip() {
    foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'] as $k) {
        if (!empty($_SERVER[$k])) {
            $v = trim((string)$_SERVER[$k]);
            if ($k === 'HTTP_X_FORWARDED_FOR') {
                $parts = explode(',', $v);
                return trim($parts[0]);
            }
            return $v;
        }
    }
    return '';
}

function bcu_gram_from_parts($vori, $ana, $roti, $point) {
    $VORI = 11.664;

    return round(
        ((float)$vori * $VORI) +
        ((float)$ana * ($VORI / 16)) +
        ((float)$roti * ($VORI / 96)) +
        ((float)$point * ($VORI / 960)),
        3
    );
}

function bcu_gram_to_parts($gram) {
    $VORI = 11.664;
    $totalPoint = (int)round(((float)$gram / $VORI) * 960);

    $vori = intdiv($totalPoint, 960);
    $totalPoint %= 960;

    $ana = intdiv($totalPoint, 60);
    $totalPoint %= 60;

    $roti = intdiv($totalPoint, 10);
    $point = $totalPoint % 10;

    return [
        'vori'  => $vori,
        'ana'   => $ana,
        'roti'  => $roti,
        'rati'  => $roti,
        'point' => $point
    ];
}

function bcu_purity_percent($karat, $fallback = 91.667) {
    $k = strtoupper(trim((string)$karat));

    $map = [
        '24K' => 100,
        '22K' => 91.667,
        '21K' => 87.5,
        '18K' => 75,
        'OTHER' => $fallback
    ];

    return $map[$k] ?? $fallback;
}

function bcu_barcode_weight($row) {
    $w = bcu_first_float($row, [
        'gross_weight_gram',
        'gross_weight',
        'weight_gram',
        'total_weight_gram',
        'net_weight',
        'weight'
    ], 0);

    if ($w <= 0) {
        $w = bcu_gram_from_parts(
            bcu_first_float($row, ['vori', 'bhori'], 0),
            bcu_first_float($row, ['ana', 'aana'], 0),
            bcu_first_float($row, ['roti', 'rati'], 0),
            bcu_first_float($row, ['point', 'points'], 0)
        );
    }

    return round((float)$w, 3);
}

function bcu_is_sold_status($status) {
    $s = mb_strtolower(trim((string)$status), 'UTF-8');

    return in_array($s, [
        'sold',
        'sell',
        'sold_out',
        'sale_done',
        'বিক্রি',
        'বিক্রিত',
        'বিক্রি হয়েছে',
        'বিক্রি হয়েছে'
    ], true);
}

function bcu_is_transfer_busy($status) {
    $s = mb_strtolower(trim((string)$status), 'UTF-8');

    return in_array($s, [
        'pending',
        'in_transit',
        'transfer',
        'transferring'
    ], true);
}

function bcu_json_text($value) {
    return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

function bcu_add_audit(PDO $pdo, $tableName, $recordId, $action, $userId, $oldValues, $newValues, $note) {
    try {
        if (!bcu_table_exists($pdo, 'audit_log')) return;

        $cols = bcu_get_columns($pdo, 'audit_log');
        if (empty($cols)) return;

        $fields = [];
        $marks = [];
        $params = [];

        $add = function($col, $val) use (&$fields, &$marks, &$params, $cols) {
            if (isset($cols[$col])) {
                $fields[] = bcu_qi($col);
                $marks[] = '?';
                $params[] = $val;
            }
        };

        $add('table_name', $tableName);
        $add('record_id', (int)$recordId);
        $add('action', strtoupper((string)$action));

        if (isset($cols['changed_by'])) {
            $add('changed_by', (int)$userId);
        } elseif (isset($cols['user_id'])) {
            $add('user_id', (int)$userId);
        }

        if (isset($cols['old_values'])) {
            $add('old_values', bcu_json_text($oldValues));
        }

        if (isset($cols['new_values'])) {
            $add('new_values', bcu_json_text($newValues));
        }

        $add('ip_address', bcu_client_ip());
        $add('note', $note);

        if (isset($cols['changed_at'])) {
            $fields[] = bcu_qi('changed_at');
            $marks[] = 'NOW()';
        } elseif (isset($cols['created_at'])) {
            $fields[] = bcu_qi('created_at');
            $marks[] = 'NOW()';
        }

        if (empty($fields)) return;

        $sql = "INSERT INTO `audit_log` (" . implode(',', $fields) . ") VALUES (" . implode(',', $marks) . ")";
        $st = $pdo->prepare($sql);
        $st->execute($params);

    } catch (Throwable $e) {
        // audit fail হলেও মূল update fail হবে না
    }
}

function bcu_find_barcode_for_update(PDO $pdo, $data, $cols, $idCol) {
    $id = (int)bcu_first_value($data, ['id', 'barcode_id', 'barcode_stock_id', 'item_id'], 0);

    if ($id > 0) {
        $st = $pdo->prepare("SELECT * FROM `barcode_stock` WHERE " . bcu_qi($idCol) . " = ? LIMIT 1 FOR UPDATE");
        $st->execute([$id]);
        $r = $st->fetch(PDO::FETCH_ASSOC);
        if ($r) return $r;
    }

    $code = trim((string)bcu_first_value($data, ['barcode_no', 'barcode', 'barcode_code', 'code'], ''));

    if ($code !== '') {
        foreach (['barcode_no', 'barcode', 'barcode_code'] as $c) {
            if (isset($cols[$c])) {
                $st = $pdo->prepare("SELECT * FROM `barcode_stock` WHERE " . bcu_qi($c) . " = ? LIMIT 1 FOR UPDATE");
                $st->execute([$code]);
                $r = $st->fetch(PDO::FETCH_ASSOC);
                if ($r) return $r;
            }
        }
    }

    return null;
}

try {
    $raw = json_decode(file_get_contents('php://input'), true);
    if (!is_array($raw)) {
        $raw = $_POST;
    }

    if (!is_array($raw)) {
        bcu_out(400, false, 'ভুল JSON data');
    }

    $userId = bcu_user_id();

    if ($userId <= 0) {
        bcu_out(401, false, 'Login session পাওয়া যায়নি');
    }

    if (!bcu_table_exists($pdo, 'barcode_stock')) {
        bcu_out(500, false, 'barcode_stock table পাওয়া যায়নি');
    }

    $cols = bcu_get_columns($pdo, 'barcode_stock');
    $idCol = bcu_pick_col($cols, ['id', 'barcode_stock_id', 'barcode_id']);

    if (!$idCol) {
        bcu_out(500, false, 'barcode_stock ID column পাওয়া যায়নি');
    }

    $pdo->beginTransaction();

    $barcode = bcu_find_barcode_for_update($pdo, $raw, $cols, $idCol);

    if (!$barcode) {
        $pdo->rollBack();
        bcu_out(404, false, 'বারকোড আইটেম পাওয়া যায়নি');
    }

    $id = (int)$barcode[$idCol];
    $barcodeNo = trim((string)bcu_first_value($barcode, ['barcode_no', 'barcode', 'barcode_code'], ''));

    if (isset($cols['is_deleted']) && (int)($barcode['is_deleted'] ?? 0) === 1) {
        $pdo->rollBack();
        bcu_out(400, false, 'Deleted barcode edit করা যাবে না');
    }

    if (isset($cols['deleted_at']) && !empty($barcode['deleted_at'])) {
        $pdo->rollBack();
        bcu_out(400, false, 'Deleted barcode edit করা যাবে না');
    }

    if (isset($cols['transfer_status']) && bcu_is_transfer_busy($barcode['transfer_status'] ?? '')) {
        $pdo->rollBack();
        bcu_out(400, false, 'এই বারকোড transfer pending/in_transit আছে, edit করা যাবে না', [
            'id' => $id,
            'barcode_no' => $barcodeNo,
            'transfer_status' => $barcode['transfer_status'] ?? ''
        ]);
    }

    $oldWeight = bcu_barcode_weight($barcode);
    $oldStatus = (string)bcu_first_value($barcode, ['status'], 'in_stock');

    $soldByFlag = false;

    if (bcu_is_sold_status($oldStatus)) {
        $soldByFlag = true;
    }

    if (isset($cols['sale_id']) && (int)($barcode['sale_id'] ?? 0) > 0) {
        $soldByFlag = true;
    }

    if (isset($cols['sold_at']) && !empty($barcode['sold_at']) && $barcode['sold_at'] !== '0000-00-00 00:00:00') {
        $soldByFlag = true;
    }

    if (isset($cols['sold_invoice_no']) && trim((string)($barcode['sold_invoice_no'] ?? '')) !== '') {
        $soldByFlag = true;
    }

    /*
       Rule:
       - Sold + valid weight barcode edit block
       - Sold + 0g problem barcode edit allow
       - Unsold barcode edit allow
    */
    if ($soldByFlag && $oldWeight > 0) {
        $pdo->rollBack();
        bcu_out(400, false, 'বিক্রি হওয়া সঠিক বারকোড edit করা যাবে না', [
            'id' => $id,
            'barcode_no' => $barcodeNo,
            'weight' => $oldWeight,
            'status' => $oldStatus
        ]);
    }

    $itemName = trim((string)bcu_first_value($raw, ['item_name', 'name', 'product_name'], ''));
    if ($itemName === '') {
        $itemName = trim((string)bcu_first_value($barcode, ['item_name', 'name', 'product_name'], 'আইটেম নাম নেই'));
    }

    if (mb_strlen($itemName, 'UTF-8') > 255) {
        $pdo->rollBack();
        bcu_out(400, false, 'আইটেম নাম 255 অক্ষরের বেশি হতে পারবে না');
    }

    $karat = trim((string)bcu_first_value($raw, ['karat', 'purity'], ''));
    if ($karat === '') {
        $karat = trim((string)bcu_first_value($barcode, ['karat', 'purity'], '22K'));
    }

    if (mb_strlen($karat, 'UTF-8') > 20) {
        $pdo->rollBack();
        bcu_out(400, false, 'ক্যারেট value অনেক বড়');
    }

    $vori  = bcu_first_float($raw, ['vori', 'bhori'], 0);
    $ana   = bcu_first_float($raw, ['ana', 'aana'], 0);
    $roti  = bcu_first_float($raw, ['roti', 'rati'], 0);
    $point = bcu_first_float($raw, ['point', 'points'], 0);

    $gross = bcu_first_float($raw, [
        'gross_weight_gram',
        'gross_weight',
        'weight_gram',
        'total_weight_gram',
        'net_weight',
        'weight'
    ], 0);

    if ($gross <= 0) {
        $gross = bcu_gram_from_parts($vori, $ana, $roti, $point);
    }

    if ($gross <= 0) {
        $pdo->rollBack();
        bcu_out(400, false, 'সঠিক ওজন দিন');
    }

    if ($gross > 10000) {
        $pdo->rollBack();
        bcu_out(400, false, 'ওজন অস্বাভাবিক বড়, আবার চেক করুন');
    }

    if ($vori <= 0 && $ana <= 0 && $roti <= 0 && $point <= 0) {
        $parts = bcu_gram_to_parts($gross);
        $vori = $parts['vori'];
        $ana = $parts['ana'];
        $roti = $parts['roti'];
        $point = $parts['point'];
    }

    $purity = bcu_first_float($raw, ['purity_percent', 'actual_purity', 'system_purity'], bcu_purity_percent($karat));
    if ($purity <= 0) {
        $purity = bcu_purity_percent($karat);
    }

    if ($purity > 100) {
        $pdo->rollBack();
        bcu_out(400, false, 'Purity 100% এর বেশি হতে পারবে না');
    }

    $pureWeight = round($gross * ($purity / 100), 3);

    $oldLocationId = bcu_first_int($barcode, ['location_id', 'stock_location_id'], 0);
    $locationId = bcu_first_int($raw, ['location_id', 'stock_location_id'], $oldLocationId);

    if ($locationId > 0 && bcu_table_exists($pdo, 'stock_locations')) {
        $locCols = bcu_get_columns($pdo, 'stock_locations');

        $locWhere = "`id` = ?";
        if (isset($locCols['is_active'])) {
            $locWhere .= " AND (`is_active` IS NULL OR `is_active` = 1)";
        } elseif (isset($locCols['active'])) {
            $locWhere .= " AND (`active` IS NULL OR `active` = 1)";
        }

        $locQ = $pdo->prepare("SELECT COUNT(*) FROM `stock_locations` WHERE {$locWhere}");
        $locQ->execute([$locationId]);

        if ((int)$locQ->fetchColumn() !== 1) {
            $pdo->rollBack();
            bcu_out(400, false, 'সঠিক active location বাছাই করুন');
        }
    }

    $note = trim((string)bcu_first_value($raw, ['note', 'remarks'], (string)($barcode['note'] ?? '')));
    if (mb_strlen($note, 'UTF-8') > 2000) {
        $pdo->rollBack();
        bcu_out(400, false, 'নোট 2000 অক্ষরের বেশি হতে পারবে না');
    }

    $set = [];
    $params = [];

    foreach (['item_name', 'name', 'product_name'] as $c) {
        if (isset($cols[$c])) {
            $set[] = bcu_qi($c) . " = ?";
            $params[] = $itemName;
        }
    }

    foreach (['karat', 'purity'] as $c) {
        if (isset($cols[$c])) {
            $set[] = bcu_qi($c) . " = ?";
            $params[] = $karat;
        }
    }

    if (isset($cols['purity_percent'])) {
        $set[] = "`purity_percent` = ?";
        $params[] = round($purity, 3);
    }

    foreach (['location_id', 'stock_location_id'] as $c) {
        if (isset($cols[$c])) {
            $set[] = bcu_qi($c) . " = ?";
            $params[] = $locationId > 0 ? $locationId : null;
        }
    }

    $weightMap = [
        'vori' => $vori,
        'bhori' => $vori,
        'ana' => $ana,
        'aana' => $ana,
        'roti' => $roti,
        'rati' => $roti,
        'point' => $point,
        'points' => $point,

        'gross_weight_gram' => round($gross, 3),
        'gross_weight' => round($gross, 3),
        'weight' => round($gross, 3),
        'weight_gram' => round($gross, 3),
        'total_weight_gram' => round($gross, 3),
        'net_weight' => round($gross, 3),

        'pure_weight_gram' => $pureWeight,
        'pure_weight' => $pureWeight,
        'pure_gold_gram' => $pureWeight
    ];

    foreach ($weightMap as $c => $v) {
        if (isset($cols[$c])) {
            $set[] = bcu_qi($c) . " = ?";
            $params[] = $v;
        }
    }

    if (isset($cols['note'])) {
        $set[] = "`note` = ?";
        $params[] = $note;
    }

    if (isset($cols['updated_at'])) {
        $set[] = "`updated_at` = NOW()";
    }

    if (empty($set)) {
        $pdo->rollBack();
        bcu_out(500, false, 'Update করার মতো column পাওয়া যায়নি');
    }

    $params[] = $id;

    $where = bcu_qi($idCol) . " = ?";

    if (isset($cols['is_deleted'])) {
        $where .= " AND (`is_deleted` IS NULL OR `is_deleted` = 0)";
    }

    if (isset($cols['deleted_at'])) {
        $where .= " AND `deleted_at` IS NULL";
    }

    if (isset($cols['transfer_status'])) {
        $where .= " AND LOWER(TRIM(COALESCE(`transfer_status`, 'none'))) NOT IN ('pending','in_transit','transfer','transferring')";
    }

    $sql = "UPDATE `barcode_stock` SET " . implode(', ', $set) . " WHERE " . $where;
    $st = $pdo->prepare($sql);
    $st->execute($params);

    if ($st->rowCount() !== 1) {
        throw new Exception('Barcode update failed');
    }

    bcu_add_audit(
        $pdo,
        'barcode_stock',
        $id,
        'UPDATE',
        $userId,
        [
            'id' => $id,
            'barcode_no' => $barcodeNo,
            'item_name' => bcu_first_value($barcode, ['item_name', 'name', 'product_name'], ''),
            'karat' => bcu_first_value($barcode, ['karat', 'purity'], ''),
            'location_id' => $oldLocationId,
            'gross_weight_gram' => $oldWeight,
            'note' => $barcode['note'] ?? ''
        ],
        [
            'id' => $id,
            'barcode_no' => $barcodeNo,
            'item_name' => $itemName,
            'karat' => $karat,
            'location_id' => $locationId,
            'gross_weight_gram' => round($gross, 3),
            'pure_weight_gram' => $pureWeight,
            'note' => $note
        ],
        'Barcode stock item updated | ' . $barcodeNo
    );

    $pdo->commit();

    bcu_out(200, true, 'বারকোড আপডেট হয়েছে', [
        'id' => $id,
        'barcode_no' => $barcodeNo,
        'item_name' => $itemName,
        'karat' => $karat,
        'vori' => (int)$vori,
        'ana' => (int)$ana,
        'roti' => (int)$roti,
        'rati' => (int)$roti,
        'point' => (int)$point,
        'gross_weight_gram' => round($gross, 3),
        'pure_weight_gram' => $pureWeight,
        'purity_percent' => round($purity, 3),
        'location_id' => $locationId
    ]);

} catch (Throwable $e) {
    if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
        $pdo->rollBack();
    }

    bcu_out(500, false, 'সার্ভার সমস্যা: ' . $e->getMessage());
}