select('*') ->from(['h' => EflCheckSentHisFinal::tableName()]) ->where(['is', 'h.lab_no', new Expression('NULL')]) ->all(); // ---------- Fetch pending items using EXISTS to avoid row duplication ---------- /*$query_lab = HanumanResultPhatthonCheck::find() ->alias('h') ->andWhere(['is', 'h.lab_no', new Expression('NULL')]) ->orderBy([ 'h.LabNo' => SORT_ASC, 'h.RiaHDocDate' => SORT_DESC, 'h.RiaLDSeq' => SORT_ASC ]) ->asArray() ->all();*/ //echo '
';
            //var_dump($query_lab);
            //die();

        if (empty($query_lab)) {
            error_log('No pending lab data matching efl_hl7_obr');
            return;
        }

        /* ===== Scan fallback ===== */
        $fallback = [
            'report_name'  => '',
            'report_dt'    => '',
            'approve_name' => '',
            'approve_dt'   => '',
        ];

        foreach ($query_lab as $r) {
            if (empty($fallback['report_name']) && !empty($r['RiaLDUserNameEntry'])) {
                $fallback['report_name'] = $r['RiaLDUserNameEntry'];
            }
            if (empty($fallback['report_dt']) && !empty($r['RiaLDUserDateEntry'])) {
                $fallback['report_dt'] = $r['RiaLDUserDateEntry'];
            }
            if (empty($fallback['approve_name']) && !empty($r['RiaLDUserNameAppr'])) {
                $fallback['approve_name'] = $r['RiaLDUserNameAppr'];
            }
            if (empty($fallback['approve_dt']) && !empty($r['RiaLDUserDateAppr'])) {
                $fallback['approve_dt'] = $r['RiaLDUserDateAppr'];
            }
        }

        // Group rows by LabNo and TestCode
        $grouped = [];
        foreach ($query_lab as $row) {
            $labNo = $row['LabNo'] ?? '';
            $testCode = $row['obr_test_code'] ?? '';
            if ($labNo && $testCode) {
                // Group by pair to ensure one ZIP per LN + TestCode as per efl_hl7_obr
                $grouped[$labNo . '_' . $testCode][] = $row;
            }
        }

        $outputDir = Yii::getAlias('@runtime/output_zips');
        if (!is_dir($outputDir)) {
            mkdir($outputDir, 0777, true);
        }

        $processedLns = []; // Track processed LabNos for report assignment

        foreach ($grouped as $groupKey => $rows) {
            $firstRow = $rows[0];
            $labNo = $firstRow['LabNo'] ?? '';
            $testCodeForFilename = $firstRow['obr_test_code'] ?? 'Unknown';
            $docIdParam = $firstRow['RiaHDocID'] ?? '';
            $docDate = !empty($firstRow['RiaHDocDate']) ? date('Y-m-d', strtotime($firstRow['RiaHDocDate'])) : '';

            // 1. Fetch Files
            $reportFiles = []; 
            $reportFilenames = [];

            if (!empty($docIdParam)) {
                // Fetch PDF from URL
                $LisResultUrl = "https://report.prolab.co.th/prolab/printpdf.php?docID={$docIdParam}&docDate={$docDate}";
                $pdfContent = $this->fetchUrl($LisResultUrl, 20);
                if ($pdfContent !== false && strlen($pdfContent) > 0) {
                    $fn = "{$labNo}_{$testCodeForFilename}.pdf";
                    $reportFiles[] = ['name' => $fn, 'content' => $pdfContent];
                    $reportFilenames[] = $fn;
                }

                // Fetch from Local Dir
                $localDir = "/var/www/html/pdflink/{$docIdParam}";
                if (is_dir($localDir)) {
                    foreach (scandir($localDir) as $fn) {
                        if ($fn === '.' || $fn === '..') continue;
                        if (!preg_match('/\.(pdf|jpg|jpeg|png|doc|docx)$/i', $fn)) continue;
                        $path = "{$localDir}/{$fn}";
                        if (is_file($path) && is_readable($path)) {
                            $content = @file_get_contents($path);
                            if ($content !== false) {
                                // Prefix filename to ensure uniqueness or use original
                                $newFn = "{$labNo}_{$testCodeForFilename}_{$fn}";
                                $reportFiles[] = ['name' => $newFn, 'content' => $content];
                                $reportFilenames[] = $newFn;
                            }
                        }
                    }
                }
            }

            // Determine if report should be included (only for the first time this LabNo is processed)
            $reportField = [];
            $shouldIncludeFiles = false;
            if (!in_array($labNo, $processedLns)) {
                $reportField = $reportFilenames;
                $shouldIncludeFiles = true;
                $processedLns[] = $labNo;
            }

            // 2. Prepare JSON Data
            $labsData = [];
            foreach ($rows as $r) {
                $labsData[] = [
                    "ln" => $r['LabNo'] ?? '',
                    "result" => $r['RiaLDRsltAnal'] ?? '',
                    "sub_result" => "",
                    "unit" => $r['LabUnit'] ?? '',
                    "method" => "",
                    "test_code" => $r['obr_test_code'] ?? '',
                    "test_name" => $r['TestName'] ?? '',
                    "specimen" => "",
                    "profile_name" => "",
                    "normal_range" => trim(($r['LabNormal1'] ?? '') . ' ' . ($r['LabNormal2'] ?? '')),
                    "report" => "", 
                    "comment" => $r['TestRemark'] ?? '', 
                    "status" => "Approve",
                    "report_by" => (string)($r['RiaLDUserNameEntry'] ?: $fallback['report_name']),
                    "report_time" => $this->dateTimeFormat($r['RiaLDUserDateEntry'] ?: $fallback['report_dt']),
                    "approve_by" => (string)($r['RiaLDUserNameAppr'] ?: $fallback['approve_name']),
                    "approve_time" => $this->dateTimeFormat($r['RiaLDUserDateAppr'] ?: $fallback['approve_dt']),
                    "attache" => []
                ];
            }

            $patName = $firstRow['PatName'] ?? '';
            $fname = $patName;
            $lname = "";
            $parts = explode(' ', trim($patName), 2);
            if (count($parts) > 1) {
                $fname = $parts[0];
                $lname = $parts[1];
            }

            $jsonPayload = [
                "patient" => [
                    "hn" => $firstRow['PatHN'] ?? '',
                    "idcard" => "",
                    "title" => "", 
                    "fname" => $fname,
                    "lname" => $lname,
                    "sex" => "", 
                    "dob" => ""
                ],
                "orderdetail" => [
                    "order_number" => "",
                    "ln" => $labNo,
                    "hn_customer" => $firstRow['CustID'] ?? $firstRow['PatHN'] ?? '',
                    "ref_no" => "",
                    "ward_customer" => "",
                    "status" => "",
                    "doctor" => "",
                    "comment_order" => "",
                    "comment_patient" => "",
                    "time_register" => $firstRow['RiaHDocDate'] ?? '',
                    "download" => ""
                ],
                "labs" => $labsData,
                "report" => $reportField,
                "report_original" => ""
            ];

            // 3. Create Zip
            $zipFilename = "{$labNo}_{$testCodeForFilename}.zip";
            $zipPath = $outputDir . DIRECTORY_SEPARATOR . $zipFilename;

            // Prepare Temp Directory for shell zip
            $tempDir = Yii::getAlias('@runtime/temp_zip_' . $labNo . '_' . uniqid());
            if (!is_dir($tempDir)) {
                mkdir($tempDir, 0777, true);
            }

            // Write JSON to temp
            $jsonFilename = "{$labNo}_{$testCodeForFilename}.json";
            file_put_contents($tempDir . DIRECTORY_SEPARATOR . $jsonFilename, json_encode($jsonPayload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
            
            // Write Report Files to temp (Only if this is the first time for this LabNo)
            if ($shouldIncludeFiles) {
                foreach ($reportFiles as $rf) {
                    file_put_contents($tempDir . DIRECTORY_SEPARATOR . $rf['name'], $rf['content']);
                }
            }

            // Execute zip command
            $cmd = "cd " . escapeshellarg($tempDir) . " && zip -r " . escapeshellarg($zipPath) . " .";
            exec($cmd, $output, $ret);

            if ($ret === 0) {
                error_log("Created ZIP (Shell): {$zipPath}");

                // บันทึก LisResult สำหรับทุก Test ใน lab นี้ที่ถูก Zip ไปแล้ว
                foreach ($rows as $r) {
                    $testCode = (string)($r['obr_test_code'] ?? '');
                    $testName = (string)($r['TestName'] ?? '');
                    $hn = (string)($r['PatHN'] ?? '');
                    $riahDocId = (string)($r['RiaHDocID'] ?? '');
                    $riahDocDate = $r['RiaHDocDate'] ?? null;
                    $resultValue = (string)($r['RiaLDRsltAnal'] ?? '');
                    $resultUnit = (string)($r['LabUnit'] ?? '');
                    $referenceRange = trim(($r['LabNormal1'] ?? '') . ' ' . ($r['LabNormal2'] ?? ''));
                    $custId = '1600'; // กำหนดค่าตาม snippet ของผู้ใช้
                    $seq = $r['RiaLDSeq'] ?? 0;

                    $existsQuery = [
                        'lab_no' => $labNo,
                        'test_code' => $testCode,
                        'cust_id' => $custId,
                        'hn' => $hn,
                        'seq' => $seq,
                    ];
                    
                    $exists = LisResult::find()->where($existsQuery)->exists();

                    if (!$exists) {
                        $lisResult = new LisResult([
                            'lab_no' => $labNo,
                            'riah_doc_id' => $riahDocId,
                            'riah_doc_date' => $riahDocDate,
                            'test_code' => $testCode,
                            'test_name' => $testName,
                            'cust_id' => $custId,
                            'hn' => $hn,
                            'result_value' => $resultValue,
                            'result_unit' => $resultUnit,
                            'reference_range' => $referenceRange,
                            'status' => 1,
                            'seq' => $seq,
                        ]);
                        if (!$lisResult->save(false)) {
                            error_log("Failed to save LisResult for LabNo={$labNo}, TestCode={$testCode}");
                        }
                    } else {
                        error_log(
                            "Record already exists in LisResult, skipping insert: "
                                . "LabNo={$labNo}, TestCode={$testCode}, CustID={$custId}, HN={$hn}"
                        );
                    }
                }
            } else {
                error_log("Failed to create ZIP (Shell): {$zipPath} (Exit Code: $ret)");
            }

            // Cleanup temp directory
            if (is_dir($tempDir)) {
                FileHelper::removeDirectory($tempDir);
            }
        }
        
        error_log("=== Hanuman Result Phatthon Zip Generator END ===");
    }

    /**
     * helper: fetch URL via cURL (robust)
     */
    protected function fetchUrl($url, $timeout = 10)
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_errno($ch) ? curl_error($ch) : null;
        curl_close($ch);

        if ($data === false || $http >= 400) {
            error_log("fetchUrl failed: {$url} http={$http} err=" . ($err ?? 'none'));
            return false;
        }
        return $data;
    }

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