<?php

/**
 * sync_pos_sales.php
 *
 * Fetches Sri Lankan branches (currency_id != 1) from tblbranchmaster,
 * then loops each branch — fetching unsent sales and pushing to MIMS
 * per branch, similar to how exchange rate sync loops per currency.
 *
 * Each branch has its own posid (POSInterfaceCode) and ClientID from
 * tblcredential (keyed by branchcode).
 */

$response = [];

require_once __DIR__ . '/catchexception.php';
require_once __DIR__ . '/db_config.php';

// ─────────────────────────────────────────────────────────────────────────────
// CONSTANTS
// ─────────────────────────────────────────────────────────────────────────────
define('APP_CODE',         'POS-02');
// define('TOKEN_URL',        'https://d3dsrywsljg161.cloudfront.net/connect/token');
define('TOKEN_URL',        'https://mims.imonitor.center/connect/token');
// define('SUBMIT_URL',       'https://d3dsrywsljg161.cloudfront.net/api/possale/importpossaleswithitems');
define('SUBMIT_URL',       'https://mims.imonitor.center/api/possale/importpossaleswithitems');
define('SALES_TYPE',       'Sales');
define('TAX_RATE_DEFAULT',  0.00);

// ─────────────────────────────────────────────────────────────────────────────
// HELPERS (unchanged)
// ─────────────────────────────────────────────────────────────────────────────
function pg_query_safe($con, string $sql)
{
    $res = pg_query($con, $sql);
    if (!$res) {
        throw new RuntimeException('DB Error: ' . pg_last_error($con) . ' | SQL: ' . $sql);
    }
    return $res;
}

function get_credential($con, string $key_name): string
{
    $key = pg_escape_string($con, $key_name);
    $res = pg_query_safe($con, "SELECT value FROM tblcredential WHERE key_name = '{$key}' LIMIT 1");
    $row = pg_fetch_assoc($res);
    if (!$row) {
        throw new RuntimeException("Credential '{$key_name}' not found in tblcredential.");
    }
    return trim($row['value']);
}

function get_bearer_token(string $client_id, string $client_secret): string
{
    $post_fields = [
        'grant_type'    => 'client_credentials',
        'client_id'     => $client_id,
        'client_secret' => $client_secret,
    ];

    $ch = curl_init(TOKEN_URL);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $post_fields,
        CURLOPT_TIMEOUT        => 30,
    ]);

    $raw       = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curl_err  = curl_error($ch);
    curl_close($ch);

    if ($raw === false || $curl_err) {
        throw new RuntimeException("Token request cURL error: {$curl_err}");
    }

    $data = json_decode($raw, true);

    if ($http_code !== 200 || empty($data['access_token'])) {
        throw new RuntimeException("Token request failed (HTTP {$http_code}). Response: {$raw}");
    }

    return $data['access_token'];
}

function post_sales(string $token, array $payload): array
{
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE);

    $ch = curl_init(SUBMIT_URL);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $json,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $token,
        ],
        CURLOPT_TIMEOUT        => 60,
    ]);

    $raw       = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curl_err  = curl_error($ch);
    curl_close($ch);

    if ($raw === false || $curl_err) {
        throw new RuntimeException("Submit cURL error: {$curl_err}");
    }

    $data = json_decode($raw, true);

    if ($http_code !== 200) {
        throw new RuntimeException("Submit failed (HTTP {$http_code}). Response: {$raw}");
    }

    return $data ?? [];
}

function epoch_to_date(float $epoch_ms): string
{
    $ts = ($epoch_ms > 1e10) ? (int)($epoch_ms / 1000) : (int)$epoch_ms;
    return date('d/m/Y', $ts);
}

function epoch_to_time(float $epoch_ms): string
{
    $ts = ($epoch_ms > 1e10) ? (int)($epoch_ms / 1000) : (int)$epoch_ms;
    return date('H:i:s', $ts);
}

function resolve_payment_method(int $mode): string
{
    $map = [
        1 => 'Cash',
        2 => 'Credit Card',
        3 => 'Net Banking',
        4 => 'MPU',
        5 => 'Voucher',
        6 => 'Online',
    ];
    return $map[$mode] ?? 'Cash';
}

function make_batch_code(): string
{
    return date('dmYHis');
}

function mark_synced($con, array $autonums): void
{
    if (empty($autonums)) return;
    $ids = implode(',', array_map('intval', $autonums));
    pg_query_safe($con, "UPDATE tblsales SET isbillsync = 1 WHERE autonum IN ({$ids})");
}

// ─────────────────────────────────────────────────────────────────────────────
// MAIN
// ─────────────────────────────────────────────────────────────────────────────
try {

    // ── 1. Load shared API credentials from tblcredential ───────────────────
    $client_secret  = get_credential($con, 'client_secret');
    $property_code  = get_credential($con, 'property_code');

    // ── 2. Fetch all Sri Lankan branches (currency_id != 1) ─────────────────
    //
    // Mirror of exchange rate sync: get the list first, then loop.
    // Each branch row carries its own posid (POSInterfaceCode) and
    // client_id — both are branch-unique per the ZANDO spec.
    // ────────────────────────────────────────────────────────────────────────
    $branch_query = "
        SELECT
            b.branchcode,
            b.branchname,
            b.posid             AS pos_interface_code,
            b.posid AS client_id,
            b.tax_percentage,
            b.is_taxable,
            c.currency_short_name
        FROM  tblbranchmaster b
        JOIN  tblcurrency     c ON c.currency_id = b.currency_id
        WHERE b.currency_id = 1
          AND b.posid IS NOT NULL
        ORDER BY b.branchcode ASC
    ";

    $branch_result = pg_query($con, $branch_query);

    if (!$branch_result) {
        $response['success'] = 0;
        $response['message'] = 'Failed to fetch Sri Lankan branches: ' . pg_last_error($con);
        echo json_encode($response);
        exit;
    }

    $branches = [];
    while ($row = pg_fetch_assoc($branch_result)) {
        $branches[] = $row;
    }

    if (empty($branches)) {
        echo json_encode([
            'success' => 1,
            'message' => 'No Sri Lankan branches found (currency_id = 1 with posid + client_id set).',
            'submitted' => 0,
        ], JSON_PRETTY_PRINT);
        mch_db_release($con);
        exit;
    }

    $total_submitted = 0;
    $total_failed    = 0;
    $branch_results  = [];

    // ── 3. Loop each branch — exactly like exchange rate loops each currency ─
    foreach ($branches as $branch) {

        $branchcode         = $branch['branchcode'];
        $pos_interface_code = trim($branch['pos_interface_code']);  // branch-unique
        $client_id          = trim($branch['client_id']);           // branch-unique
        $currency           = trim($branch['currency_short_name']);
        $tax_rate           = isset($branch['tax_percentage']) && $branch['tax_percentage'] !== ''
                                ? (float)$branch['tax_percentage']
                                : TAX_RATE_DEFAULT;

        // ── 3a. Obtain a Bearer token for this branch's ClientID ─────────────
        try {
            $token = get_bearer_token($client_id, $client_secret);
        } catch (RuntimeException $e) {
            $total_failed++;
            $branch_results[] = [
                'branchcode'    => $branchcode,
                'return_status' => 'TokenError',
                'error_details' => $e->getMessage(),
            ];
            continue;   // skip to next branch
        }

        // ── 3b. Fetch unsent sales for this branch ───────────────────────────
        $branchcode_esc = (int)$branchcode;

        $sales_sql = "
            SELECT
                s.autonum,
                s.transactionno,
                s.voucherno,
                s.transactiondate,
                s.salestime,
                s.grandtotal,
                s.noofitems,
                s.modeofpayment,
                s.netamount,
                s.taxamount,
                s.discamount,
                s.taxname,
                s.cashamount,
                s.creditamount,
                s.onlineamount,
                TO_CHAR(
                    TO_TIMESTAMP(s.transactiondate / 1000) ,
                    'DD/MM/YYYY'
                ) AS receipt_date,
                TO_CHAR(
                    TO_TIMESTAMP(s.salestime, 'HH:MI AM'),
                    'HH24:MI:SS'
                ) AS receipt_time
            FROM  tblsales s
            WHERE s.branchcode  = {$branchcode_esc} AND TO_DATE(TO_CHAR(TO_TIMESTAMP(transactiondate / 1000), 'YYYY/MM/DD'), 'YYYY/MM/DD')
        BETWEEN '2026-06-23'::date AND '2026-06-23'::date
              --AND COALESCE(s.isbillsync, 0)  = 0
              AND (s.cancelflag IS NULL OR s.cancelflag != 1)
            ORDER BY s.transactiondate ASC, s.autonum ASC
        ";

        $sales_result = pg_query_safe($con, $sales_sql);

        $branch_sales = [];
        while ($row = pg_fetch_assoc($sales_result)) {
            $branch_sales[] = $row;
        }

        if (empty($branch_sales)) {
            $branch_results[] = [
                'branchcode'    => $branchcode,
                'return_status' => 'Skipped',
                'error_details' => 'No unsent bills',
                'bills_sent'    => 0,
            ];
            continue;   // nothing to send for this branch
        }

        // ── 3c. Fetch item details for all sales in this branch ──────────────
        $sale_autonums = array_column($branch_sales, 'autonum');
        $autonums_sql  = implode(',', array_map('intval', $sale_autonums));

        $items_sql = "
            SELECT
                d.autonum          AS detail_autonum,
                d.transactionno,
                d.voucherno,
                d.transactiondate,
                d.qty,
                d.price,
                d.amount,
                d.basicamount,
                i.itemname         AS item_desc
            FROM  tblsalesitemdetails d
            JOIN  tblitemmaster       i ON i.itemcode = d.itemcode
            WHERE d.branchcode    = '{$branchcode_esc}'
              AND d.transactionno IN (
                    SELECT transactionno FROM tblsales WHERE autonum IN ({$autonums_sql})
                  )
              AND d.voucherno     IN (
                    SELECT voucherno    FROM tblsales WHERE autonum IN ({$autonums_sql})
                  )
              AND d.transactiondate IN (
                    SELECT transactiondate FROM tblsales WHERE autonum IN ({$autonums_sql})
                  )
            ORDER BY d.transactionno ASC, d.autonum ASC
        ";

        $items_result = pg_query_safe($con, $items_sql);

        $items_map = [];
        while ($item_row = pg_fetch_assoc($items_result)) {
            $map_key = $item_row['transactionno'] . '_'
                     . $item_row['voucherno']      . '_'
                     . $item_row['transactiondate'];
            $items_map[$map_key][] = $item_row;
        }

        // ── 3d. Build PosSales payload ───────────────────────────────────────
        $pos_sales          = [];
        $submitted_autonums = [];

        foreach ($branch_sales as $sale) {

            $map_key    = $sale['transactionno'] . '_'
                        . $sale['voucherno']      . '_'
                        . $sale['transactiondate'];
            $sale_items = $items_map[$map_key] ?? [];

            $total_before_tax = round((float)($sale['netamount']  ?? 0), 2);
            $total_after_tax  = round((float)($sale['grandtotal'] ?? 0), 2);
            $payment_amt      = $total_after_tax;
            $payment_method   = resolve_payment_method((int)($sale['modeofpayment'] ?? 1));

            $epoch        = (float)$sale['transactiondate'];
            $receipt_date = $sale['receipt_date'] ?? '';
            $receipt_time = $sale['receipt_time'] ?? '';

            // $receipt_no = 'R' . str_pad((int)$sale['voucherno'], 6, '0', STR_PAD_LEFT);
             $receipt_no = pg_escape_string($con, $sale['voucherno']);

            // Items
            $items_payload = [];
            foreach ($sale_items as $it) {
                $item_amt = round((float)$it['amount'], 2);
                $disc_amt = (!empty($it['basicamount']) && (float)$it['basicamount'] > $item_amt)
                              ? round((float)$it['basicamount'] - $item_amt, 2)
                              : 0.00;
                $items_payload[] = [
                    'ItemDesc'        => trim($it['item_desc']),
                    'ItemAmt'         => $item_amt,
                    'ItemDiscountAmt' => $disc_amt,
                ];
            }

            if (empty($items_payload)) {
                $items_payload[] = [
                    'ItemDesc'        => 'Sale',
                    'ItemAmt'         => $total_before_tax,
                    'ItemDiscountAmt' => round((float)($sale['discamount'] ?? 0), 2),
                ];
            }

            $pos_sales[] = [
                'PropertyCode'          => $property_code,
                'POSInterfaceCode'      => $pos_interface_code,   // branch-unique posid
                'ReceiptDate'           => $receipt_date,
                'ReceiptTime'           => $receipt_time,
                'ReceiptNo'             => $receipt_no,
                'NoOfItems'             => max(1, (int)$sale['noofitems']),
                'SalesCurrency'         => $currency,
                'TotalSalesAmtB4Tax'    => $total_before_tax,
                'TotalSalesAmtAfterTax' => $total_after_tax,
                'SalesTaxRate'          => $tax_rate,
                'ServiceChargeAmt'      => 0.00,
                'PaymentAmt'            => $payment_amt,
                'PaymentCurrency'       => $currency,
                'PaymentMethod'         => $payment_method,
                'SalesType'             => SALES_TYPE,
                'Items'                 => $items_payload,
            ];

            $submitted_autonums[] = (int)$sale['autonum'];
        }

        // ── 3e. Build full request payload ───────────────────────────────────
        $batch_code = make_batch_code();

        $payload = [
            'AppCode'          => APP_CODE,
            'PropertyCode'     => $property_code,
            'ClientID'         => $client_id,           // branch-unique
            'ClientSecret'     => $client_secret,
            'POSInterfaceCode' => $pos_interface_code,  // branch-unique
            'BatchCode'        => $batch_code,
            'PosSales'         => $pos_sales,
        ];

        // ── 3f. POST to MIMS ─────────────────────────────────────────────────
        try {

        // TEMP DEBUG: log the full payload being sent
    // error_log("PAYLOAD branch {$branchcode}: " . json_encode($payload, JSON_PRETTY_PRINT));
    echo "<!-- PAYLOAD branch {$branchcode}: "  . json_encode($payload, JSON_PRETTY_PRINT) . " -->\n";
            $api_response = post_sales($token, $payload);
             // TEMP DEBUG: log the raw API response
    // error_log("RESPONSE branch {$branchcode}: " . json_encode($api_response, JSON_PRETTY_PRINT));
    // echo "<!-- DEBUG RESPONSE: " . json_encode($api_response, JSON_PRETTY_PRINT) . " -->\n";

            $return_status    = $api_response['returnStatus']    ?? 'Unknown';
            $records_received = $api_response['recordsReceived'] ?? 0;
            $records_imported = $api_response['recordsImported'] ?? 0;
            $error_details    = $api_response['errorDetails']    ?? '';
            $defective_rows   = $api_response['defectiveRowNos'] ?? '';

            $branch['bills_sent'] = $api_response['recordsReceived'] ?? 0;
            $branch['records_imported'] = $api_response['recordsImported'] ?? 0;
            $branch['return_status'] = $return_status;

            // if (strtolower($return_status) === 'success') {
            //     mark_synced($con, $submitted_autonums);
            //     $total_submitted += count($submitted_autonums);
            // } else {
            //     $total_failed += count($submitted_autonums);
            // }
            if ($branch['return_status'] === 'Success') {
                $total_submitted += $branch['records_imported'];
                // echo "<!-- Marking autonums as synced for branch {$branchcode}: " . implode(', ', $submitted_autonums) . " -->\n";  
                mark_synced($con, $submitted_autonums);
            } else {
                $total_failed += $branch['bills_sent'];
            }

            $branch_results[] = [
                'branchcode'        => $branchcode,
                'batch_code'        => $batch_code,
                'bills_sent'        => count($submitted_autonums),
                'return_status'     => $return_status,
                'records_received'  => $records_received,
                'records_imported'  => $records_imported,
                'error_details'     => $error_details,
                'defective_rows'    => $defective_rows,
            ];

        } catch (RuntimeException $e) {
            $total_failed += count($submitted_autonums);
            $branch_results[] = [
                'branchcode'    => $branchcode,
                'batch_code'    => $batch_code,
                'bills_sent'    => count($submitted_autonums),
                'return_status' => 'Error',
                'error_details' => $e->getMessage(),
            ];
        }
    }

    // ── 4. Final response ────────────────────────────────────────────────────
    $response['success']         = 1;
    $response['message']         = 'POS sync completed';
    $response['total_submitted'] = $total_submitted;
    $response['total_failed']    = $total_failed;
    $response['branch_results']  = $branch_results;

    echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

    mch_db_release($con);

} catch (Exception $e) {

    mch_db_release($con);

    echo json_encode([
        'success' => 0,
        'message' => $e->getMessage(),
    ]);
}
?>