<?php
session_start();

header('Content-Type: application/json; charset=utf-8');

$path = realpath(dirname(__DIR__, 3) . '/services/Model.php');
if (!$path) {
    echo json_encode([
        'status' => 'error',
        'message' => 'Model.php not found',
    ]);
    exit;
}

require_once $path;

date_default_timezone_set('Asia/Dhaka');

$dateTime = date('Y-m-d g:i:sA');
$date = date('Y-m-d');

$obj = new Model();

function json_out($status, $message, $extra = [])
{
    echo json_encode(array_merge([
        'status' => $status,
        'message' => $message,
    ], $extra));
    exit;
}

function normalize_customer_ids($customers)
{
    if (is_string($customers)) {
        $customers = explode(',', $customers);
    }

    if (!is_array($customers)) {
        return [];
    }

    $ids = [];
    foreach ($customers as $customerId) {
        $id = (int)$customerId;
        if ($id > 0) {
            $ids[$id] = $id;
        }
    }

    return array_values($ids);
}

function money($value)
{
    return round((float)$value, 2);
}

function resolve_disconnect_base_date($disconnectDate, $currentDate, $freeDays)
{
    $disconnectDate = trim((string)$disconnectDate);
    if ($disconnectDate === '') {
        return $currentDate;
    }

    $disconnectTs = strtotime($disconnectDate);
    if ($disconnectTs === false) {
        return $currentDate;
    }

    $todayTs = strtotime($currentDate);
    $dateDifference = ($todayTs - $disconnectTs) / 86400;

    if ($dateDifference > (float)$freeDays) {
        return $currentDate;
    }

    return date('Y-m-d', $disconnectTs);
}

$userId = (int)($_SESSION['userid'] ?? 0);
if ($userId <= 0) {
    json_out('error', 'Session expired. Please login again.');
}

$customerIds = normalize_customer_ids($_POST['customers'] ?? []);
if (empty($customerIds)) {
    json_out('error', 'No valid customers selected.');
}

$resellerSingle = $obj->details_by_cond('_reseller_createuser', "UserId='$userId'");
if (!$resellerSingle) {
    json_out('error', 'Reseller not found.');
}

$connection = $obj->getConnection();
$mikrotikTableExists = $obj->tableExists('re_mikrotik_user');
$payMonth = 1;
$availableBalance = money($resellerSingle['balance'] ?? 0);

$successCustomers = [];
$failedCustomers = [];

foreach ($customerIds as $token) {
    try {
        $connection->beginTransaction();

        $lockedReseller = $obj->rawSqlSingle(
            "SELECT * FROM _reseller_createuser WHERE UserId='$userId' FOR UPDATE"
        );
        if (!$lockedReseller) {
            throw new RuntimeException('Reseller not found.');
        }

        $data = $obj->rawSqlSingle(
            "SELECT * FROM re_tbl_agent WHERE ag_id='$token' AND entry_by='$userId' FOR UPDATE"
        );
        if (!$data) {
            throw new RuntimeException('Customer not found for this reseller.');
        }

        $currentResellerBalance = money($lockedReseller['balance'] ?? 0);
        $availableBalance = $currentResellerBalance;

        $customerBill = money($data['taka'] ?? 0);
        $resellerCharge = money(($data['re_taka'] ?? 0) * $payMonth);

        if ($customerBill < 0 || $resellerCharge < 0) {
            throw new RuntimeException('Invalid billing amount found for this customer.');
        }

        if ($currentResellerBalance < $resellerCharge) {
            throw new RuntimeException('Insufficient reseller balance.');
        }

        $agentName = trim((string)($data['ag_name'] ?? ''));
        $agentIp = trim((string)($data['ip'] ?? ''));
        $disconnectBaseDate = resolve_disconnect_base_date(
            $data['mikrotik_disconnect'] ?? '',
            $date,
            $lockedReseller['freeday'] ?? 0
        );
        $newDisconnect = date('Y-m-d', strtotime($disconnectBaseDate . " +$payMonth months"));

        $agentUpdate = [
            'paid_amount' => money($data['paid_amount'] ?? 0),
            'dueadvance' => money($data['dueadvance'] ?? 0),
            'generate_amount' => money($data['generate_amount'] ?? 0),
            'mikrotik_disconnect' => $newDisconnect,
            'balance' => money(($data['balance'] ?? 0) + $resellerCharge),
            'bill_status' => 1,
            'pay_status' => 0,
            'payment_status' => 1,
        ];

        if ((int)($data['billgenerate'] ?? 0) === 0) {
            $agentUpdate['billgenerate'] = 1;
            $agentUpdate['dueadvance'] = money($agentUpdate['dueadvance'] + $customerBill);
            $agentUpdate['generate_amount'] = money($agentUpdate['generate_amount'] + $customerBill);
        }

        if ($customerBill > 0) {
            $agentUpdate['paid_amount'] = money($agentUpdate['paid_amount'] + $customerBill);
            $agentUpdate['dueadvance'] = money($agentUpdate['dueadvance'] - $customerBill);
        }

        if ((int)($data['ag_status'] ?? 0) === 0) {
            $agentUpdate['ag_status'] = 1;
        }

        $newResellerBalance = money($currentResellerBalance - $resellerCharge);

        $obj->Update_data('_reseller_createuser', [
            'balance' => $newResellerBalance,
        ], "UserId='$userId'");

        $lastResellerAccountId = $obj->Insert_data('re_tbl_reseller_account', [
            'reseller_id' => $userId,
            'agent_id' => $token,
            'amount' => $resellerCharge,
            'type' => 5,
            'description' => "Balance recharge for $payMonth month disconnect date $newDisconnect ($agentName / $agentIp)",
            'entry_by' => $userId,
            'entry_date' => $date,
        ]);

        $obj->Insert_data('re_tbl_account', [
            'agent_id' => $token,
            'cus_id' => $data['cus_id'] ?? '',
            'acc_amount' => $customerBill,
            'acc_type' => '3',
            'acc_description' => "Bill collection at $dateTime",
            'entry_by' => $userId,
            'entry_date' => $date,
            'update_by' => $userId,
            'reseller_id' => $userId,
            'reseller_account_id' => $lastResellerAccountId,
        ]);

        $obj->resellerHistoryLog([
            're_id' => $userId,
            'header' => 'Bill Collection',
            'descriptions' => 'Bill Collection Name: "' . ($data['ag_name'] ?? '') . '" And Cus ID: "' . ($data['cus_id'] ?? '') . '" Collected. Amount: ' . $customerBill . '.',
            'type' => 'insert',
            'ag_id' => $token,
        ]);

        $obj->Update_data(
            're_tbl_agent',
            $agentUpdate,
            "ag_id='$token' AND entry_by='$userId'"
        );

        $connection->commit();
        $availableBalance = $newResellerBalance;

        if (
            $mikrotikTableExists &&
            !empty($data['mikrotik_id']) &&
            $agentIp !== ''
        ) {
            try {
                $obj->reEnableSingleSecret((int)$data['mikrotik_id'], $agentIp);
            } catch (Throwable $mikrotikError) {
            }
        }

        $successCustomers[] = [
            'customer_id' => $token,
            'cus_id' => $data['cus_id'] ?? '',
            'name' => $agentName,
            'amount' => $customerBill,
            'reseller_charge' => $resellerCharge,
            'new_disconnect' => $newDisconnect,
        ];
    } catch (Throwable $e) {
        if ($connection->inTransaction()) {
            $connection->rollBack();
        }

        $failedCustomers[] = [
            'customer_id' => $token,
            'reason' => $e->getMessage(),
        ];
    }
}

$successCount = count($successCustomers);
$failedCount = count($failedCustomers);

if ($successCount === 0) {
    json_out('error', 'No recharge completed.', [
        'requested_count' => count($customerIds),
        'success_count' => 0,
        'failed_count' => $failedCount,
        'remaining_balance' => $availableBalance,
        'success_customers' => $successCustomers,
        'failed_customers' => $failedCustomers,
    ]);
}

$message = 'Recharge completed successfully.';
if ($failedCount > 0) {
    $message = "Recharge completed for $successCount customer(s), $failedCount failed.";
}

json_out('success', $message, [
    'requested_count' => count($customerIds),
    'success_count' => $successCount,
    'failed_count' => $failedCount,
    'is_partial' => $failedCount > 0,
    'remaining_balance' => $availableBalance,
    'success_customers' => $successCustomers,
    'failed_customers' => $failedCustomers,
]);
