<?php

namespace console\controllers;

use console\models\ApiToken;
use yii\console\Controller;
use console\models\RiaFrmHVLAB;
use console\models\HisRequest;
use console\models\LisApiD;
use console\models\LisApiSend;
use console\models\LisResult;
use Yii;
use yii\console\ExitCode;

class LisSendController extends Controller
{
    /**
     * Console action: รันกระบวนการส่งผลไปยัง external API
     * เรียกจาก CLI: php /path/to/yii lis-api-send/create
     */
    public function actionCreate()
    {
        // ป้องกันให้รันซ้อนกัน (lockfile)
        $lockFile = Yii::getAlias('@runtime') . '/lis_api_send.lock';
        $fp = fopen($lockFile, 'c');
        if (!$fp) {
            $this->stderr("Cannot open lockfile: {$lockFile}\n");
            return ExitCode::UNSPECIFIED_ERROR;
        }
        if (!flock($fp, LOCK_EX | LOCK_NB)) {
            $this->stdout("Process already running. Exiting.\n");
            return ExitCode::OK;
        }

        // ให้โปรเซสไม่หมดเวลา (console)
        @set_time_limit(0);

        $this->stdout("Start LisApiSend at " . date('Y-m-d H:i:s') . "\n");

        // ===== ดึงข้อมูล Lab =====
        $RiaLabD = LisApiD::find()
            ->where(['RiaHDocID' => '253080444', 'PatHN' => '002', 'RiaLDApprvFlag' => '1'])
            ->orderBy(['RiaHDocDate' => SORT_DESC])
            ->all();

        $groupedByLabNo = [];
        $sendMapping = [];
        $globalDebug = [];

        foreach ($RiaLabD as $rows) {
            $riaH = RiaFrmHVLAB::findOne(['RiaHDocID' => $rows->RiaHDocID]);
            if (!$riaH) {
                $globalDebug[$rows->RiaHDocID] = ["Missing RiaFrmHVLAB for {$rows->RiaHDocID}"];
                continue;
            }

            $hisReq = HisRequest::find()->where(['HN' => $riaH->PatHN, 'CustomerCode' => $riaH->CustID])->one();

            $filesData = [];
            $labNo = $hisReq->LabNo ?? '';
            $timestamp = date('dmYHis');
            $docIdParam = $rows['RiaHDocID'] ?? '';
            $debug = [];

            if (!empty($docIdParam)) {
                $dirUrl = 'https://report.prolab.co.th/pdflink/' . $docIdParam . '/';
                $mydir =  "/var/www/html/pdflink/" . $docIdParam;
                $mydirobj = scandir($mydir);
                $mydirarray = array();

                if ($mydirobj <> "") {
                    foreach ($mydirobj as $filename) {
                        if (strpos($filename, ".png") || strpos($filename, ".pdf") || strpos($filename, ".jpg") || strpos($filename, ".jpeg" || strpos($filename, ".doc"))) {
                            $filename_ext = $dirUrl . "/" . $filename;
                            array_push($mydirarray, $filename_ext);
                            //base64 encode
                            $content = file_get_contents($filename_ext);
                            $ext = pathinfo($filename, PATHINFO_EXTENSION);
                            $newFileName = ($labNo ?: 'lab') . '_' . $timestamp . '.' . $ext;
                            $finfo = new \finfo(FILEINFO_MIME_TYPE);
                            $mime = $finfo->buffer($content);
                            $filesData[] = [
                                'filename' => $newFileName,
                                'base64'   => base64_encode($content),
                                'size'     => strlen($content),
                                'mimetype' => $mime,
                            ];
                        }
                    }
                }

                /*$possibleFiles = [];
                for ($j = 1; $j <= 20; $j++) {
                    $possibleFiles[] = $docIdParam . '_' . $j . '.pdf';
                }
                $possibleFiles[] = $docIdParam . '.pdf';
                $possibleFiles[] = 'report.pdf';
                $possibleFiles[] = 'result.pdf';

                foreach ($possibleFiles as $fileName) {
                    $fileUrl = $dirUrl . $fileName;

                    // HEAD check
                    $ch = curl_init($fileUrl);
                    curl_setopt($ch, CURLOPT_NOBODY, true);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
                    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                    $head = curl_exec($ch);
                    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    $curlErr = curl_errno($ch) ? curl_error($ch) : null;
                    curl_close($ch);

                    $debug[] = "Checking: {$fileName} -> HTTP {$httpCode}" . ($curlErr ? " (curlErr: {$curlErr})" : '');

                    if ($httpCode == 200) {
                        // GET content
                        $ch2 = curl_init($fileUrl);
                        curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
                        curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true);
                        curl_setopt($ch2, CURLOPT_TIMEOUT, 15);
                        curl_setopt($ch2, CURLOPT_SSL_VERIFYPEER, false);
                        $content = curl_exec($ch2);
                        $curlErr2 = curl_errno($ch2) ? curl_error($ch2) : null;
                        curl_close($ch2);

                        if ($content !== false && !empty($content)) {
                            $ext = pathinfo($fileName, PATHINFO_EXTENSION);
                            $newFileName = ($labNo ?: 'lab') . '_' . $timestamp . '.' . $ext;

                            $finfo = new \finfo(FILEINFO_MIME_TYPE);
                            $mime = $finfo->buffer($content);

                            $filesData[] = [
                                'filename' => $newFileName,
                                'base64'   => base64_encode($content),
                                'size'     => strlen($content),
                                'mimetype' => $mime,
                            ];

                            $debug[] = "Success: Loaded {$fileName} (" . strlen($content) . " bytes)" . ($curlErr2 ? " (curlErr: {$curlErr2})" : '');
                        } else {
                            $debug[] = "Empty content for {$fileName}" . ($curlErr2 ? " (curlErr: {$curlErr2})" : '');
                        }
                    }
                }

                if (empty($filesData)) {
                    $debug[] = "No file found in {$dirUrl}";
                }
            } else {
                $debug[] = "docIdParam empty";
            }

            $globalDebug[$docIdParam ?: 'no_doc_id_' . uniqid()] = $debug;*/
            }

            // ===== สร้าง TestItem =====
            $testItem = [
                'TestCode' => (string)($rows->TestCode ?? ''),
                'TestName' => (string)($rows->TestName ?? ''),
                'TestRemark' => '',
                'InformCriticalByCode' => '',
                'InformCriticalBy' => '',
                'InformCriticalTo' => '',
                'InformCriticalDateTime' => '',
                'CriticalFlag' => '',
                'ReportResultByCode' => '',
                'ReportResultBy' => (string)($rows->RiaLDUserNameEntry ?? ''),
                'ReportResultDateTime' => $this->dateTimeFormat($rows->RiaLDUserDateEntry ?? ''),
                'ApproveResultByCode' => '',
                'ApproveResultBy' => (string)($rows->RiaLDUserNameAppr ?? ''),
                'ApproveResultDateTime' => $this->dateTimeFormat($rows->RiaLDUserDateAppr ?? ''),
                'Filedata' =>  $filesData,
                'ResultList' => [
                    [
                        'ResultCode' => (string)($rows->TestCode ?? ''),
                        'ResultName' => (string)($rows->TestName ?? ''),
                        'ResultValue' => (string)($rows->RiaLDRsltAnal ?? ''),
                        'ResultUnit' => (string)($rows->LabUnit ?? ''),
                        'ResultFlag' => '',
                        'ReferenceRange' => trim(($rows->LabNormal1 ?? '') . ' ' . ($rows->LabNormal2 ?? '')),
                        'ResultRemark' => '',
                    ]
                ],
            ];

            // ===== จัดกลุ่มตาม LabNo =====
            if (!isset($groupedByLabNo[$labNo])) {
                $groupedByLabNo[$labNo] = [
                    'LabNo' => $labNo,
                    'RequestRemark' => '',
                    'ResultStatus' => '',
                    'TestList' => []
                ];
            }
            $groupedByLabNo[$labNo]['TestList'][] = $testItem;
            $sendMapping[$rows->RiaHDocID] = $rows->RiaHDocID;
        }

        // ===== เตรียม payload (เลือก record แรกของ groupedByLabNo) =====
        $testList = $groupedByLabNo;
        $payload = count($testList) > 0 ? array_values($testList)[0] : null;

        // ===== ตรวจสอบ config =====
        $cfg = Yii::$app->params['external_api'] ?? null;
        if (!$cfg) {
            $this->stderr("Config external_api not found\n");
            flock($fp, LOCK_UN);
            fclose($fp);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        if (empty($cfg['receiveUrl'])) {
            $this->stderr("receiveUrl not configured in external_api\n");
            flock($fp, LOCK_UN);
            fclose($fp);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        // ===== ขอ token =====
        $tokenError = null;
        $token = $this->getValidApiToken($cfg, $tokenError);

        if (!$token) {
            $this->stderr("Cannot get API token: " . json_encode($tokenError) . "\n");
            flock($fp, LOCK_UN);
            fclose($fp);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        $url = $cfg['receiveUrl'];

        if (!$payload) {
            $this->stdout("No test data to send\n");
            flock($fp, LOCK_UN);
            fclose($fp);
            return ExitCode::OK;
        }

        // ===== ส่ง payload โดยตรง (ไม่ห่อด้วย dataJson) =====
        $wrappedPayload = $payload;

        $debugInfo = [
            'url' => $url,
            'tokenUrl' => $cfg['tokenUrl'] ?? 'not set',
            'token_exists' => !empty($token),
            'token_length' => strlen($token ?? ''),
            'payload_count' => count($testList),
            'payload_size' => strlen(json_encode($wrappedPayload, JSON_UNESCAPED_UNICODE)),
        ];

        $this->stdout("Posting to external API ({$debugInfo['payload_size']} bytes)...\n");

        $response = $this->postJsonCurl($url, $wrappedPayload, [
            'Authorization' => "Bearer {$token}",
        ]);

        // รวม debug และ file debug
        $response['debug_info'] = $debugInfo;
        $response['file_debug'] = $globalDebug;
        $response['token_received'] = $token;
        if ($tokenError) {
            $response['token_warning'] = $tokenError;
        }

        // ===== ตรวจ response ตามสเป็ค (Status number, 0 = Success) =====
        $success = false;
        $decoded = null;

        if (!empty($response['response'])) {
            $decoded = json_decode($response['response'], true);

            if (is_array($decoded)) {
                // ตรวจ Status field (รองรับ 'Status' หรือ 'status')
                $statusVal = $decoded['Status'] ?? ($decoded['status'] ?? null);
                if ($statusVal !== null) {
                    if (is_numeric($statusVal)) {
                        $success = (intval($statusVal) === 0);
                    } else {
                        $s = strtolower(trim((string)$statusVal));
                        if ($s === '0' || $s === 'success' || $s === 'ok') {
                            $success = true;
                        }
                    }
                }

                // fallback: ถ้าไม่มี Status ให้ตรวจ Message
                if (!$success) {
                    $msg = strtolower(trim($decoded['Message'] ?? ($decoded['message'] ?? '')));
                    if ($msg !== '' && (strpos($msg, 'success') !== false || strpos($msg, 'successful') !== false)) {
                        $success = true;
                    }
                }
            }
        }

        Yii::info('External API decoded response: ' . var_export($decoded, true), __METHOD__);
        Yii::info('Determined success = ' . ($success ? 'true' : 'false') . '; http_code=' . ($response['http_code'] ?? ''), __METHOD__);

        // ===== ถ้า success ให้บันทึก LisResult (status = 1) =====
        if ($success) {
            foreach ($RiaLabD as $rows) {
                $riaH = RiaFrmHVLAB::findOne(['RiaHDocID' => $rows->RiaHDocID]);
                if (!$riaH) continue;
                $hisReq = HisRequest::find()->where(['HN' => $riaH->PatHN, 'CustomerCode' => $riaH->CustID])->one();
                if (!$hisReq) {
                    Yii::warning("No HisRequest for HN={$riaH->PatHN} Cust={$riaH->CustID} RiaHDocID={$rows->RiaHDocID}", __METHOD__);
                    continue;
                }

                $LisResult = LisResult::find()->where([
                    'lab_no' => $hisReq->LabNo,
                    'test_code' => $rows->LabID,
                    'cust_id' => $riaH->CustID,
                    'hn' => $riaH->PatHN
                ])->one();

                if (!$LisResult) {
                    $LisResult = new LisResult([
                        'lab_no' => $hisReq->LabNo,
                        'riah_doc_id' => $rows->RiaHDocID,
                        'riah_doc_date' => $rows->RiaHDocDate,
                        'test_code' => $rows->LabID,
                        'test_name' => $rows->LabName,
                        'cust_id' => $riaH->CustID,
                        'hn' => $riaH->PatHN,
                        'result_value' => $rows->RiaLDRsltAnal ?? '',
                        'result_unit' => $rows->LabUnit ?? '',
                        'reference_range' => trim(($rows->LabNormal1 ?? '') . ' ' . ($rows->LabNormal2 ?? '')),
                        'status' => 1,
                    ]);
                    if (!$LisResult->save(false)) {
                        Yii::error("Failed to save LisResult for lab_no={$hisReq->LabNo} test_code={$rows->LabID}", __METHOD__);
                    }
                } else {
                    $LisResult->status = 1;
                    if (!$LisResult->save(false)) {
                        Yii::error("Failed to update LisResult id={$LisResult->id}", __METHOD__);
                    }
                }
            }
        }

        $this->stdout("Finished LisApiSend at " . date('Y-m-d H:i:s') . "\n");
        // ปล่อย lock
        flock($fp, LOCK_UN);
        fclose($fp);
        // คืนค่า response (console) - ให้ log เก็บใน Yii log ถ้าต้องการ
        // สามารถเขียน $response ลงไฟล์ log เพิ่มได้
        $this->stdout("API Response HTTP: " . ($response['http_code'] ?? '') . "\n");
        $this->stdout("API Response Body: " . ($response['response'] ?? '') . "\n");

        return ExitCode::OK;
    }

    /** helper: แปลง datetime เป็น dd/mm/YYYY H:i:s */
    public function dateTimeFormat($value)
    {
        if (empty($value)) return '';
        try {
            $dt = new \DateTime($value);
            return $dt->format('d/m/Y H:i:s');
        } catch (\Throwable $e) {
            return '';
        }
    }

    /**
     * ขอ token จาก API (คืนค่า associative array แบบ {ok, token, expires_at, http_code, raw, error})
     */
    protected function getApiToken($cfg)
    {
        $tokenUrl = $cfg['tokenUrl'] ?? Yii::$app->params['external_api']['tokenUrl'] ?? null;
        $username = $cfg['username'] ?? Yii::$app->params['external_api']['username'] ?? null;
        $password = $cfg['password'] ?? Yii::$app->params['external_api']['password'] ?? null;

        $payload = ['username' => $username, 'password' => $password];

        $ch = curl_init($tokenUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Accept: application/json']);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $raw = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlErr = curl_errno($ch) ? curl_error($ch) : null;
        curl_close($ch);

        $result = ['ok' => false, 'token' => null, 'expires_at' => null, 'http_code' => $httpCode, 'raw' => $raw, 'error' => null];

        if ($raw === false || $curlErr) {
            $result['error'] = 'cURL error: ' . ($curlErr ?? 'unknown');
            return $result;
        }

        $decoded = json_decode($raw, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $result['error'] = 'Invalid JSON response from token endpoint';
            return $result;
        }

        if (!empty($decoded['access_token'])) {
            $result['ok'] = true;
            $result['token'] = $decoded['access_token'];
            $expiresIn = intval($decoded['expires_in'] ?? 3600);
            $result['expires_at'] = date('Y-m-d H:i:s', time() + $expiresIn);
        } elseif (!empty($decoded['token'])) {
            $result['ok'] = true;
            $result['token'] = $decoded['token'];
            $expiresIn = intval($decoded['expires_in'] ?? 3600);
            $result['expires_at'] = date('Y-m-d H:i:s', time() + $expiresIn);
        } else {
            $result['error'] = $decoded['error'] ?? ($decoded['message'] ?? 'No token in response');
        }

        return $result;
    }

    /**
     * ดึง token ที่ valid (คืน token string หรือ null และตั้ง $tokenError หากมีปัญหา)
     */
    protected function getValidApiToken($cfg, &$tokenError = null)
    {
        $apiName = $cfg['apiName'] ?? 'gems_api';
        $tokenModel = ApiToken::find()->where(['api_name' => $apiName])->one();
        $token = null;
        $nowTs = time();
        $refreshMargin = $cfg['refreshMargin'] ?? 300; // 5 นาที

        $needRequest = !$tokenModel || (strtotime($tokenModel->expires_at) <= ($nowTs + $refreshMargin));

        if ($needRequest) {
            $tokenResp = $this->getApiToken($cfg);

            if (empty($tokenResp) || empty($tokenResp['ok'])) {
                $tokenError = [
                    'message' => 'Failed to get token from API',
                    'tokenUrl' => $cfg['tokenUrl'] ?? null,
                    'error' => $tokenResp['error'] ?? 'Unknown error',
                    'http_code' => $tokenResp['http_code'] ?? 0,
                    'raw' => $tokenResp['raw'] ?? null,
                ];

                if ($tokenModel && !empty($tokenModel->token)) {
                    return $tokenModel->token; // fallback: ใช้ token เก่า
                }

                return null;
            }

            $token = $tokenResp['token'];
            $expiresAt = $tokenResp['expires_at'] ?? date('Y-m-d H:i:s', time() + 3600);

            if (!$tokenModel) {
                $tokenModel = new ApiToken();
                $tokenModel->api_name = $apiName;
            }
            $tokenModel->token = $token;
            $tokenModel->expires_at = $expiresAt;
            $tokenModel->save(false);
        } else {
            $token = $tokenModel->token;
        }

        return $token;
    }

    /** helper: ส่ง JSON ผ่าน cURL (คืนข้อมูล debug เต็ม) */
    protected function postJsonCurl($url, $payload, $headers = [])
    {
        $ch = curl_init($url);
        $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        $curlHeaders = ['Content-Type: application/json', 'Accept: application/json'];
        foreach ($headers as $k => $v) {
            if (is_int($k)) {
                $curlHeaders[] = $v;
            } else {
                $curlHeaders[] = "{$k}: {$v}";
            }
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeaders);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_errno($ch) ? curl_error($ch) : null;
        $curlErrno = curl_errno($ch);
        curl_close($ch);

        return [
            'http_code' => $httpCode,
            'response' => $response,
            'curl_error' => $curlError,
            'curl_errno' => $curlErrno,
            'url' => $url,
            'payload_size' => strlen($jsonPayload),
        ];
    }


    public function actionCreate()
    {
        // ตรวจ environment: true = รันจาก CLI/console
        $isConsole = (Yii::$app instanceof \yii\console\Application);

        // อย่าตั้ง Yii::$app->response->format เมื่อรันแบบ console (จะเกิด UnknownPropertyException)
        if (!$isConsole) {
            Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        }

        // ===== ดึงข้อมูล Lab =====
        $RiaLabD = LisApiD::find()
            ->where(['RiaHDocID' => '253080444', 'PatHN' => '002', 'RiaLDApprvFlag' => '1'])
            ->orderBy(['RiaHDocDate' => SORT_DESC])
            ->all();

        $groupedByLabNo = [];
        $globalDebug = [];
        // เก็บ RiaHDocID ที่จะถูกส่ง (เฉพาะ test ที่ใส่ลง payload)
        $toSendRiaHDocIDs = [];

        foreach ($RiaLabD as $rows) {
            $riaH = RiaFrmHVLAB::findOne(['RiaHDocID' => $rows->RiaHDocID]);
            if (!$riaH) {
                $globalDebug[$rows->RiaHDocID] = ["Missing RiaFrmHVLAB for {$rows->RiaHDocID}"];
                Yii::warning("START processing RiaHDocID={$rows->RiaHDocID} LabNo=UNKNOWN - missing RiaFrmHVLAB", __METHOD__);
                continue;
            }

            $hisReq = HisRequest::find()->where(['HN' => $riaH->PatHN, 'CustomerCode' => $riaH->CustID])->one();
            $labNo = $hisReq->LabNo ?? '';

            Yii::info("START processing RiaHDocID={$rows->RiaHDocID} LabNo={$labNo} HN={$riaH->PatHN} Cust={$riaH->CustID} at " . date('c'), __METHOD__);

            // ===== เตรียมไฟล์ผล =====
            $filesData = [];
            $timestamp = date('dmYHis');
            $docIdParam = $rows['RiaHDocID'] ?? '';
            $docDate = date('Y-m-d', strtotime($rows['RiaHDocDate'] ?? ''));

            if (!empty($docIdParam)) {
                $dirUrl = 'https://report.prolab.co.th/pdflink/' . $docIdParam . '/';
                $mydir = "/var/www/html/pdflink/" . $docIdParam;
                $mydirobj = is_dir($mydir) ? scandir($mydir) : [];
                $filesData = [];

                // ไฟล์ผลหลักจาก LisResult
                $LisResultUrl = 'https://report.prolab.co.th/prolab/printpdf.php?docID=' . $docIdParam . '&docDate=' . $docDate;

                // ===== ถ้ามี LisResult → ทำก่อน =====
                $pdfContent = @file_get_contents($LisResultUrl);
                $hasLisResult = ($pdfContent !== false && strlen($pdfContent) > 0);

                if ($hasLisResult) {
                    $newFileName = ($labNo ?: 'lab') . '_' . $timestamp . '.pdf';
                    $filesData[] = [
                        'FileName' => $newFileName,
                        'Filebase64' => base64_encode($pdfContent),
                    ];
                }

                // ===== ถ้ามีไฟล์ใน dirUrl และต้องทำ outlab ด้วย =====
                if (!empty($mydirobj) && count($mydirobj) > 2) { // >2 เพื่อไม่เอา . และ ..
                    foreach ($mydirobj as $filename) {
                        if (
                            stripos($filename, ".png") !== false ||
                            stripos($filename, ".pdf") !== false ||
                            stripos($filename, ".jpg") !== false ||
                            stripos($filename, ".jpeg") !== false ||
                            stripos($filename, ".doc") !== false
                        ) {
                            $fileUrl = $dirUrl . $filename;
                            $content = @file_get_contents($fileUrl);
                            if ($content !== false) {
                                $newFileName = ($labNo ?: 'lab') . '_' . $timestamp . '_outlab_' . $filename;
                                $filesData[] = [
                                    'FileName' => $newFileName,
                                    'Filebase64' => base64_encode($content),
                                ];
                            }
                        }
                    }
                }
            }

            // ===== สร้าง TestItem =====
            $testItem = [
                'TestCode' => (string)($rows->TestCode ?? ''),
                'TestName' => (string)($rows->TestName ?? ''),
                'TestRemark' => '',
                'InformCriticalByCode' => '',
                'InformCriticalBy' => '',
                'InformCriticalTo' => '',
                'InformCriticalDateTime' => '',
                'CriticalFlag' => '',
                'ReportResultByCode' => '',
                'ReportResultBy' => (string)($rows->RiaLDUserNameEntry ?? ''),
                'ReportResultDateTime' => $this->dateTimeFormat($rows->RiaLDUserDateEntry ?? ''),
                'ApproveResultByCode' => '',
                'ApproveResultBy' => (string)($rows->RiaLDUserNameAppr ?? ''),
                'ApproveResultDateTime' => $this->dateTimeFormat($rows->RiaLDUserDateAppr ?? ''),
                'Filedata' => $filesData,
                'ResultList' => [
                    [
                        'ResultCode' => (string)($rows->TestCode ?? ''),
                        'ResultName' => (string)($rows->TestName ?? ''),
                        'ResultValue' => (string)($rows->RiaLDRsltAnal ?? ''),
                        'ResultUnit' => (string)($rows->LabUnit ?? ''),
                        'ResultFlag' => '',
                        'ReferenceRange' => trim(($rows->LabNormal1 ?? '') . ' ' . ($rows->LabNormal2 ?? '')),
                        'ResultRemark' => '',
                    ]
                ],
            ];

            // ===== จัดกลุ่มตาม LabNo =====
            if (!isset($groupedByLabNo[$labNo])) {
                $groupedByLabNo[$labNo] = [
                    'LabNo' => $labNo,
                    'RequestRemark' => '',
                    'ResultStatus' => '',
                    'TestList' => []
                ];
            }
            $groupedByLabNo[$labNo]['TestList'][] = $testItem;
            // เก็บ RiaHDocID ของรายการที่จริงจะส่ง
            $toSendRiaHDocIDs[] = $rows->RiaHDocID;

            Yii::info("END processing RiaHDocID={$rows->RiaHDocID} LabNo={$labNo} at " . date('c') . " (added TestCode=" . ($rows->TestCode ?? '') . ")", __METHOD__);
        }

        // ===== กรองเอาเฉพาะ LabNo ที่มี TestList จริง ๆ =====
        $filtered = [];
        foreach ($groupedByLabNo as $ln => $data) {
            if (!empty($data['TestList'])) {
                $filtered[$ln] = $data;
            } else {
                Yii::info("SKIP LabNo={$ln} - all tests already sent or no tests to send", __METHOD__);
            }
        }
        $testList = $filtered;

        // ===== เตรียม payload (เลือก record แรกของ groupedByLabNo) =====
        $payload = count($testList) > 0 ? array_values($testList)[0] : null;

        // ===== ตรวจสอบ config =====
        $cfg = Yii::$app->params['external_api'] ?? null;
        if (!$cfg) {
            $result = [
                'error' => 'Config external_api not found',
                'sent_payload' => $testList,
                'file_debug' => $globalDebug
            ];
            if ($isConsole) {
                echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
                return ExitCode::UNSPECIFIED_ERROR;
            }
            return $result;
        }

        if (empty($cfg['receiveUrl'])) {
            $result = [
                'error' => 'receiveUrl not configured',
                'config' => $cfg,
                'sent_payload' => $testList,
                'file_debug' => $globalDebug
            ];
            if ($isConsole) {
                echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
                return ExitCode::UNSPECIFIED_ERROR;
            }
            return $result;
        }

        // ===== ขอ token =====
        $tokenError = null;
        $token = $this->getValidApiToken($cfg, $tokenError);

        if (!$token) {
            $result = [
                'error' => 'Cannot get API token',
                'token_error' => $tokenError,
                'sent_payload' => $testList,
                'file_debug' => $globalDebug
            ];
            if ($isConsole) {
                echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
                return ExitCode::UNSPECIFIED_ERROR;
            }
            return $result;
        }

        $url = $cfg['receiveUrl'];

        if (!$payload) {
            $result = [
                'error' => 'No test data to send',
                'sent_payload' => $testList,
                'file_debug' => $globalDebug
            ];
            if ($isConsole) {
                echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
                return ExitCode::OK;
            }
            return $result;
        }

        // ===== ส่ง payload โดยตรง (ตรวจจาก LisApiSend ก่อนส่ง) =====
        $wrappedPayload = $payload;
        $payloadJson = json_encode($wrappedPayload, JSON_UNESCAPED_UNICODE);

        $debugInfo = [
            'url' => $url,
            'tokenUrl' => $cfg['tokenUrl'] ?? 'not set',
            'token_exists' => !empty($token),
            'token_length' => strlen($token ?? ''),
            'payload_count' => count($testList),
            'payload_size' => strlen($payloadJson),
        ];

        Yii::info("START sending payload for LabNo=" . ($wrappedPayload['LabNo'] ?? '') .
            " to {$url} at " . date('c') .
            " payload_size=" . $debugInfo['payload_size'], __METHOD__);

        // หาเรคอร์ดที่ยังส่งไม่สำเร็จจาก LisApiSend (status = NULL)
        $pendingSends = LisApiSend::find()
            ->where(['riah_doc_id' => $toSendRiaHDocIDs, 'status' => null])
            ->all();

        if (empty($pendingSends)) {
            $result = [
                'error' => 'No pending LisApiSend records to send (status IS NOT NULL).',
                'sent_payload' => $testList,
                'file_debug' => $globalDebug,
            ];
            if ($isConsole) {
                echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
                return ExitCode::OK;
            }
            return $result;
        }

        // $maxAttempts = 0 หมายถึงไม่จำกัดจนกว่าจะ success (ปรับเป็น >0 ถ้าต้องการจำกัด)
        $maxAttempts = 0;
        $attempt = 0;
        $success = false;
        $response = ['error' => 'not sent'];
        $decoded = null;

        // Loop จนกว่าจะ success (หรือเกิน maxAttempts ถ้ากำหนด)
        while (true) {
            $attempt++;
            // บันทึก attempts ลงใน LisApiSend (ถ้ามีฟิลด์ attempts)
            foreach ($pendingSends as $ps) {
                try {
                    if (property_exists($ps, 'attempts')) {
                        $ps->attempts = intval($ps->attempts) + 1;
                    }
                    if (property_exists($ps, 'last_attempt_at')) {
                        $ps->last_attempt_at = date('Y-m-d H:i:s');
                    }
                    $ps->save(false);
                } catch (\Throwable $e) {
                    Yii::warning("Failed to update LisApiSend attempt for riah_doc_id={$ps->riah_doc_id}: " . $e->getMessage(), __METHOD__);
                }
            }

            // ส่งด้วย cURL
            $response = $this->postJsonCurl($url, $wrappedPayload, [
                'Authorization' => "Bearer {$token}",
            ]);

            $decoded = null;
            if (!empty($response['response'])) {
                $decoded = json_decode($response['response'], true);
            }

            // ตรวจสอบ success ตามสเป็ค (Status number, 0 = Success)
            $success = false;
            if (is_array($decoded)) {
                $statusVal = $decoded['Status'] ?? ($decoded['status'] ?? null);
                if ($statusVal !== null) {
                    if (is_numeric($statusVal)) {
                        $success = (intval($statusVal) === 0);
                    } else {
                        $s = strtolower(trim((string)$statusVal));
                        if ($s === '0' || $s === 'success' || $s === 'ok') {
                            $success = true;
                        }
                    }
                }

                if (!$success) {
                    $msg = strtolower(trim($decoded['Message'] ?? ($decoded['message'] ?? '')));
                    if ($msg !== '' && (strpos($msg, 'success') !== false || strpos($msg, 'successful') !== false)) {
                        $success = true;
                    }
                }
            }

            Yii::info("Attempt #{$attempt} sending payload: success=" . ($success ? 'true' : 'false') .
                " http_code=" . ($response['http_code'] ?? '') . " at " . date('c'), __METHOD__);

            if ($success) {
                // อัปเดต LisApiSend records → status=1 พร้อมบันทึกรายละเอียด response
                foreach ($pendingSends as $ps) {
                    try {
                        $ps->status = 1;
                        $ps->response = is_string($response['response'] ?? null) ? $response['response'] : json_encode($response['response']);
                        if (property_exists($ps, 'last_attempt_at')) {
                            $ps->last_attempt_at = date('Y-m-d H:i:s');
                        }
                        $ps->save(false);
                    } catch (\Throwable $e) {
                        Yii::warning("Failed to update LisApiSend success for riah_doc_id={$ps->riah_doc_id}: " . $e->getMessage(), __METHOD__);
                    }
                }

                // บันทึก LisResult สำหรับรายการที่ส่งจริง (ใช้ $toSendRiaHDocIDs)
                foreach ($RiaLabD as $rows) {
                    if (!in_array($rows->RiaHDocID, $toSendRiaHDocIDs, true)) {
                        continue;
                    }
                    $riaH = RiaFrmHVLAB::findOne(['RiaHDocID' => $rows->RiaHDocID]);
                    if (!$riaH) continue;
                    $hisReq = HisRequest::find()->where(['HN' => $riaH->PatHN, 'CustomerCode' => $riaH->CustID])->one();
                    if (!$hisReq) {
                        Yii::warning("No HisRequest for HN={$riaH->PatHN} Cust={$riaH->CustID} RiaHDocID={$rows->RiaHDocID}", __METHOD__);
                        continue;
                    }

                    $LisResult = LisResult::find()->where([
                        'lab_no' => $hisReq->LabNo,
                        'test_code' => $rows->LabID,
                        'cust_id' => $riaH->CustID,
                        'hn' => $riaH->PatHN
                    ])->one();

                    if (!$LisResult) {
                        $LisResult = new LisResult([
                            'lab_no' => $hisReq->LabNo,
                            'riah_doc_id' => $rows->RiaHDocID,
                            'riah_doc_date' => $rows->RiaHDocDate,
                            'test_code' => $rows->LabID,
                            'test_name' => $rows->LabName,
                            'cust_id' => $riaH->CustID,
                            'hn' => $riaH->PatHN,
                            'result_value' => $rows->RiaLDRsltAnal ?? '',
                            'result_unit' => $rows->LabUnit ?? '',
                            'reference_range' => trim(($rows->LabNormal1 ?? '') . ' ' . ($rows->LabNormal2 ?? '')),
                            'status' => 1,
                        ]);
                        if (!$LisResult->save(false)) {
                            Yii::error("Failed to save LisResult for lab_no={$hisReq->LabNo} test_code={$rows->LabID}", __METHOD__);
                        } else {
                            Yii::info("Saved LisResult (status=1) for lab_no={$hisReq->LabNo} test_code={$rows->LabID}", __METHOD__);
                        }
                    } else {
                    }
                }

                break; // ออกจาก loop เพราะสำเร็จแล้ว
            }

            // ถ้าไม่สำเร็จ ให้อัพเดต LisApiSend บันทึกรอบล่าสุด (response) แล้วลองใหม่
            foreach ($pendingSends as $ps) {
                try {
                    $ps->response = is_string($response['response'] ?? null) ? $response['response'] : json_encode($response['response']);
                    if (property_exists($ps, 'last_attempt_at')) {
                        $ps->last_attempt_at = date('Y-m-d H:i:s');
                    }
                    $ps->save(false);
                } catch (\Throwable $e) {
                    Yii::warning("Failed to update LisApiSend after failed attempt for riah_doc_id={$ps->riah_doc_id}: " . $e->getMessage(), __METHOD__);
                }
            }

            if ($maxAttempts > 0 && $attempt >= $maxAttempts) {
                Yii::error("Reached maxAttempts={$maxAttempts} without success. Giving up.", __METHOD__);
                break;
            }

            // รอ 1 วินาทีก่อนลองใหม่ (ปรับตามต้องการ)
            sleep(1);
        } // end while

        // เตรียมผลลัพธ์สุดท้าย
        $result = $response;
        $result['debug_info'] = $debugInfo;
        $result['file_debug'] = $globalDebug;
        $result['token_received'] = $token;
        $result['payload_sent_json'] = $payloadJson;
        $result['payload_sent'] = $wrappedPayload;
        if (!empty($decoded)) {
            $result['api_decoded'] = $decoded;
        }

        return $result;
    }
}
