<?php
// cPanel path: /home/jewellersbd/public_html/erp.jewellersbd.com/api/stock_transfer/confirm_transfer.php
// Purpose: Confirm / Reject stock transfer
// Data change: YES
// Safety:
// - transaction + FOR UPDATE lock
// - pending transfer only
// - sold/deleted stock block
// - confirm: barcode_stock.location_id = to_location_id, transfer_status = none
// - reject: barcode_stock.location_id same থাকবে, transfer_status = none
// - stock_transfers status 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';

if (file_exists(__DIR__ . '/../../config/response.php')) {
    require_once __DIR__ . '/../../config/response.php';
}

if (function_exists('require_login')) {
    require_login();
} elseif (function_exists('is_logged_in') && !is_logged_in()) {
    http_response_code(401);
    echo json_encode(['success' => false, 'status' => false, 'message' => 'লগইন প্রয়োজন'], JSON_UNESCAPED_UNICODE);
    exit;
}

function send_json($arr, $code = 200)
{
    http_response_code($code);
    echo json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

if (!isset($pdo) || !($pdo instanceof PDO)) {
    send_json(['success' => false, 'status' => false, 'message' => 'PDO DB connection পাওয়া যায়নি'], 500);
}

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

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

function qi($name)
{
    return '`' . str_replace('`', '', clean_name($name)) . '`';
}

function table_exists(PDO $pdo, $table)
{
    $table = clean_name($table);
    if ($table === '') return false;

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

function get_columns(PDO $pdo, $table)
{
    $table = clean_name($table);
    if ($table === '' || !table_exists($pdo, $table)) return [];

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

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

    return $cols;
}

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

    return $default;
}

function current_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 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 json_text($value)
{
    return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

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

        $cols = 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[] = 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', json_text($oldValues));
        }

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

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

        if (isset($cols['changed_at'])) {
            $fields[] = qi('changed_at');
            $marks[] = 'NOW()';
        } elseif (isset($cols['created_at'])) {
            $fields[] = 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 হলেও main transfer rollback হবে না।
    }
}

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

    return in_array($s, ['', 'in_stock', 'stock', 'available', 'ready'], true);
}

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

    return in_array($s, [
        'sold', 'sell', 'sold_out', 'sale_done',
        'deleted', 'cancelled', 'canceled', 'void', 'trash', 'trashed',
        'বিক্রি', 'বিক্রিত', 'বিক্রি হয়েছে', 'বিক্রি হয়েছে', 'বাতিল'
    ], true);
}

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

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

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        send_json(['success' => false, 'status' => false, 'message' => 'শুধু POST request allowed'], 405);
    }

    if (!table_exists($pdo, 'stock_transfers')) {
        send_json(['success' => false, 'status' => false, 'message' => 'stock_transfers table পাওয়া যায়নি'], 500);
    }

    if (!table_exists($pdo, 'barcode_stock')) {
        send_json(['success' => false, 'status' => false, 'message' => 'barcode_stock table পাওয়া যায়নি'], 500);
    }

    $rawJson = file_get_contents('php://input');
    $raw = json_decode($rawJson, true);

    if (!is_array($raw)) {
        $raw = $_POST;
    }

    if (!is_array($raw)) {
        send_json(['success' => false, 'status' => false, 'message' => 'ভুল JSON data'], 400);
    }

    $transferId = (int)($raw['id'] ?? $raw['transfer_id'] ?? 0);
    $action = trim((string)($raw['action'] ?? ''));
    $reason = trim((string)($raw['reason'] ?? $raw['rejected_reason'] ?? ''));

    $userId = current_user_id();

    if ($userId <= 0) {
        send_json(['success' => false, 'status' => false, 'message' => 'Login session পাওয়া যায়নি'], 401);
    }

    if ($transferId <= 0) {
        send_json(['success' => false, 'status' => false, 'message' => 'Transfer ID দরকার'], 400);
    }

    if (!in_array($action, ['confirm', 'reject'], true)) {
        send_json(['success' => false, 'status' => false, 'message' => 'Action confirm অথবা reject হতে হবে'], 400);
    }

    if ($action === 'reject' && $reason === '') {
        $reason = 'Rejected by user';
    }

    if (mb_strlen($reason, 'UTF-8') > 500) {
        send_json(['success' => false, 'status' => false, 'message' => 'কারণ 500 অক্ষরের বেশি হতে পারবে না'], 400);
    }

    $bsCols = get_columns($pdo, 'barcode_stock');
    $trCols = get_columns($pdo, 'stock_transfers');

    foreach (['id', 'barcode_stock_id', 'from_location_id', 'to_location_id', 'status'] as $c) {
        if (!isset($trCols[$c])) {
            send_json(['success' => false, 'status' => false, 'message' => 'stock_transfers.' . $c . ' column পাওয়া যায়নি'], 500);
        }
    }

    foreach (['id', 'location_id', 'transfer_status'] as $c) {
        if (!isset($bsCols[$c])) {
            send_json(['success' => false, 'status' => false, 'message' => 'barcode_stock.' . $c . ' column পাওয়া যায়নি'], 500);
        }
    }

    $pdo->beginTransaction();

    $tQ = $pdo->prepare("
        SELECT
            st.*,
            bs.`id` AS stock_id,
            bs.`location_id` AS current_location_id,
            bs.`transfer_status` AS barcode_transfer_status,
            " . (isset($bsCols['barcode']) ? "bs.`barcode`" : (isset($bsCols['barcode_no']) ? "bs.`barcode_no` AS barcode" : "'' AS barcode")) . ",
            " . (isset($bsCols['status']) ? "bs.`status` AS stock_status" : "'in_stock' AS stock_status") . ",
            " . (isset($bsCols['is_deleted']) ? "bs.`is_deleted` AS stock_is_deleted" : "0 AS stock_is_deleted") . ",
            " . (isset($bsCols['deleted_at']) ? "bs.`deleted_at` AS stock_deleted_at" : "NULL AS stock_deleted_at") . ",
            " . (isset($bsCols['sale_id']) ? "bs.`sale_id` AS stock_sale_id" : "0 AS stock_sale_id") . ",
            " . (isset($bsCols['sold_at']) ? "bs.`sold_at` AS stock_sold_at" : "NULL AS stock_sold_at") . ",
            " . (isset($bsCols['sold_invoice_no']) ? "bs.`sold_invoice_no` AS stock_sold_invoice_no" : "'' AS stock_sold_invoice_no") . "
        FROM `stock_transfers` st
        JOIN `barcode_stock` bs ON bs.`id` = st.`barcode_stock_id`
        WHERE st.`id` = ?
        FOR UPDATE
    ");
    $tQ->execute([$transferId]);
    $transfer = $tQ->fetch(PDO::FETCH_ASSOC);

    if (!$transfer) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই transfer পাওয়া যায়নি'], 404);
    }

    $transferStatus = mb_strtolower(trim((string)($transfer['status'] ?? '')), 'UTF-8');

    if ($transferStatus !== 'pending') {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই transfer ইতিমধ্যে প্রসেস হয়ে গেছে'], 400);
    }

    $barcode = trim((string)($transfer['barcode'] ?? ''));
    $label = $barcode !== '' ? $barcode : 'Stock #' . (int)$transfer['barcode_stock_id'];

    $stockStatus = (string)($transfer['stock_status'] ?? 'in_stock');

    if (is_sold_or_deleted_status($stockStatus) || !is_stock_status_ok($stockStatus)) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock এখন আর available নেই'], 400);
    }

    if ((int)($transfer['stock_is_deleted'] ?? 0) !== 0) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock deleted অবস্থায় আছে'], 400);
    }

    if (!empty($transfer['stock_deleted_at'])) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock deleted অবস্থায় আছে'], 400);
    }

    if ((int)($transfer['stock_sale_id'] ?? 0) > 0) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock already sold'], 400);
    }

    if (!empty($transfer['stock_sold_at']) && $transfer['stock_sold_at'] !== '0000-00-00 00:00:00') {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock already sold'], 400);
    }

    if (trim((string)($transfer['stock_sold_invoice_no'] ?? '')) !== '') {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock already sold'], 400);
    }

    if (!is_transfer_in_transit($transfer['barcode_transfer_status'] ?? '')) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'এই stock transfer অবস্থায় নেই'], 400);
    }

    $currentLocationId = (int)$transfer['current_location_id'];
    $fromLocationId = (int)$transfer['from_location_id'];
    $toLocationId = (int)$transfer['to_location_id'];
    $stockId = (int)$transfer['barcode_stock_id'];
    $transferCode = (string)($transfer['transfer_code'] ?? ('TRF-' . $transferId));

    if ($currentLocationId !== $fromLocationId) {
        $pdo->rollBack();
        send_json(['success' => false, 'status' => false, 'message' => 'Stock location mismatch পাওয়া গেছে'], 400);
    }

    if ($action === 'confirm') {
        $setParts = [
            "`location_id` = ?",
            "`transfer_status` = ?"
        ];

        $updParams = [
            $toLocationId,
            'none'
        ];

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

        $whereParts = [
            "`id` = ?",
            "`location_id` = ?",
            "LOWER(TRIM(COALESCE(`transfer_status`, ''))) IN ('in_transit','pending')"
        ];

        $updParams[] = $stockId;
        $updParams[] = $fromLocationId;

        if (isset($bsCols['status'])) {
            $whereParts[] = "LOWER(TRIM(COALESCE(`status`, ''))) IN ('', 'in_stock', 'stock', 'available', 'ready')";
        }

        if (isset($bsCols['is_deleted'])) {
            $whereParts[] = "(`is_deleted` IS NULL OR `is_deleted` = 0)";
        }

        if (isset($bsCols['deleted_at'])) {
            $whereParts[] = "`deleted_at` IS NULL";
        }

        $updStockSql = "
            UPDATE `barcode_stock`
            SET " . implode(', ', $setParts) . "
            WHERE " . implode(' AND ', $whereParts) . "
        ";

        $updStock = $pdo->prepare($updStockSql);
        $updStock->execute($updParams);

        if ($updStock->rowCount() !== 1) {
            throw new Exception('Stock receive update failed');
        }

        $setT = ["`status` = ?"];
        $paramsT = ['confirmed'];

        if (isset($trCols['confirmed_by'])) {
            $setT[] = "`confirmed_by` = ?";
            $paramsT[] = $userId;
        }

        if (isset($trCols['confirmed_at'])) {
            $setT[] = "`confirmed_at` = NOW()";
        }

        if (isset($trCols['rejected_reason'])) {
            $setT[] = "`rejected_reason` = NULL";
        }

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

        $paramsT[] = $transferId;

        $updTransfer = $pdo->prepare("
            UPDATE `stock_transfers`
            SET " . implode(', ', $setT) . "
            WHERE `id` = ?
              AND LOWER(TRIM(COALESCE(`status`, ''))) = 'pending'
        ");
        $updTransfer->execute($paramsT);

        if ($updTransfer->rowCount() !== 1) {
            throw new Exception('Transfer status update failed');
        }

        add_audit_log(
            $pdo,
            'barcode_stock',
            $stockId,
            'UPDATE',
            $userId,
            [
                'location_id' => $fromLocationId,
                'transfer_status' => $transfer['barcode_transfer_status']
            ],
            [
                'location_id' => $toLocationId,
                'transfer_status' => 'none',
                'transfer_code' => $transferCode
            ],
            "Stock transfer confirmed | {$transferCode} | {$label}"
        );

        add_audit_log(
            $pdo,
            'stock_transfers',
            $transferId,
            'UPDATE',
            $userId,
            [
                'status' => 'pending'
            ],
            [
                'status' => 'confirmed',
                'confirmed_by' => $userId
            ],
            "Transfer confirmed | {$transferCode} | {$label}"
        );

        $msg = '✅ Transfer সফলভাবে গ্রহণ করা হয়েছে';

    } else {
        $setParts = [
            "`transfer_status` = ?"
        ];

        $updParams = [
            'none'
        ];

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

        $whereParts = [
            "`id` = ?",
            "`location_id` = ?",
            "LOWER(TRIM(COALESCE(`transfer_status`, ''))) IN ('in_transit','pending')"
        ];

        $updParams[] = $stockId;
        $updParams[] = $fromLocationId;

        if (isset($bsCols['status'])) {
            $whereParts[] = "LOWER(TRIM(COALESCE(`status`, ''))) IN ('', 'in_stock', 'stock', 'available', 'ready')";
        }

        if (isset($bsCols['is_deleted'])) {
            $whereParts[] = "(`is_deleted` IS NULL OR `is_deleted` = 0)";
        }

        if (isset($bsCols['deleted_at'])) {
            $whereParts[] = "`deleted_at` IS NULL";
        }

        $updStockSql = "
            UPDATE `barcode_stock`
            SET " . implode(', ', $setParts) . "
            WHERE " . implode(' AND ', $whereParts) . "
        ";

        $updStock = $pdo->prepare($updStockSql);
        $updStock->execute($updParams);

        if ($updStock->rowCount() !== 1) {
            throw new Exception('Stock reject update failed');
        }

        $setT = ["`status` = ?"];
        $paramsT = ['rejected'];

        if (isset($trCols['confirmed_by'])) {
            $setT[] = "`confirmed_by` = ?";
            $paramsT[] = $userId;
        }

        if (isset($trCols['confirmed_at'])) {
            $setT[] = "`confirmed_at` = NOW()";
        }

        if (isset($trCols['rejected_reason'])) {
            $setT[] = "`rejected_reason` = ?";
            $paramsT[] = $reason;
        }

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

        $paramsT[] = $transferId;

        $updTransfer = $pdo->prepare("
            UPDATE `stock_transfers`
            SET " . implode(', ', $setT) . "
            WHERE `id` = ?
              AND LOWER(TRIM(COALESCE(`status`, ''))) = 'pending'
        ");
        $updTransfer->execute($paramsT);

        if ($updTransfer->rowCount() !== 1) {
            throw new Exception('Transfer reject status update failed');
        }

        add_audit_log(
            $pdo,
            'barcode_stock',
            $stockId,
            'UPDATE',
            $userId,
            [
                'location_id' => $fromLocationId,
                'transfer_status' => $transfer['barcode_transfer_status']
            ],
            [
                'location_id' => $fromLocationId,
                'transfer_status' => 'none',
                'transfer_code' => $transferCode
            ],
            "Stock transfer rejected | {$transferCode} | {$label}"
        );

        add_audit_log(
            $pdo,
            'stock_transfers',
            $transferId,
            'UPDATE',
            $userId,
            [
                'status' => 'pending'
            ],
            [
                'status' => 'rejected',
                'confirmed_by' => $userId,
                'rejected_reason' => $reason
            ],
            "Transfer rejected | {$transferCode} | {$label}"
        );

        $msg = '❌ Transfer বাতিল করা হয়েছে — stock আগের location-এ থাকবে';
    }

    $pdo->commit();

    send_json([
        'success' => true,
        'status' => true,
        'message' => $msg,
        'action' => $action,
        'transfer_id' => $transferId,
        'transfer_code' => $transferCode,
        'barcode_stock_id' => $stockId,
        'barcode' => $barcode,
        'from_location_id' => $fromLocationId,
        'to_location_id' => $toLocationId,
        'data' => [
            'action' => $action,
            'transfer_id' => $transferId,
            'transfer_code' => $transferCode,
            'barcode_stock_id' => $stockId,
            'barcode' => $barcode,
            'from_location_id' => $fromLocationId,
            'to_location_id' => $toLocationId
        ]
    ]);

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

    send_json([
        'success' => false,
        'status' => false,
        'message' => 'Transfer confirm/reject সমস্যা: ' . $e->getMessage()
    ], 500);
}