<?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\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()
    {
        //$this->logConsole("=== Hanuman Result Sikarin START ===");
        error_log("=== Hanuman Result Sikarin START ===");

        $query = HanumanResultSikarinCheck::find()
            ->where(['not', ['RiaHDocID' => null]])
            ->andWhere(['not', ['PatHN' => null]])
            ->andWhere(['<>', 'RiaHDocID', ''])
            ->andWhere(['<>', 'PatHN', ''])
            ->asArray()
            ->orderBy(['RiaHDocDate' => SORT_DESC])
            ->all();

        //$this->logConsole("Total records: " . count($query));
        error_log("Total records: " . count($query));

        $sendMapping = [];

        // config
        $cfg = Yii::$app->params['external_api'] ?? null;
        if (!$cfg || empty($cfg['receiveUrl'])) {
            //$this->logConsole("Missing external_api config or receiveUrl", 'error');
            error_log("Missing external_api config or receiveUrl", 'error');
            return 1;
        }

        // get token
        $tokenError = null;
        $token = $this->getValidApiToken($cfg, $tokenError);
        if (empty($token)) {
            //$this->logConsole("Cannot obtain valid API token: " . (is_array($tokenError) ? json_encode($tokenError) : ($tokenError ?? 'unknown')), 'error');
            error_log("Cannot obtain valid API token: " . (is_array($tokenError) ? json_encode($tokenError) : ($tokenError ?? 'unknown')), 'error');
            return 1;
        }

        $url = $cfg['receiveUrl'];
        //$this->logConsole("Using API token (ready to send)");
        error_log("Using API token (ready to send)");

        $query = HanumanResultSikarinCheck::find()
            ->where(['not', ['RiaHDocID' => null]])
            ->andWhere(['not', ['PatHN' => null]])
            ->andWhere(['<>', 'RiaHDocID', ''])
            ->andWhere(['<>', 'PatHN', ''])
            ->asArray()
            ->orderBy(['RiaHDocDate' => SORT_DESC])
            ->all();

        $groupedByLabNo = [];

        foreach ($query as $rows) {
            // collect files
            $filesData = [];
            $timestamp = date('dmYHis');
            $labNo = $rows['LabNo'] ?? '';
            $docIdParam = $rows['RiaHDocID'] ?? '';
            $docDate = !empty($rows['RiaHDocDate']) ? date('Y-m-d', strtotime($rows['RiaHDocDate'])) : '';

            if (!empty($docIdParam)) {
                $LisResultUrl = "https://report.prolab.co.th/prolab/printpdf.php?docID={$docIdParam}&docDate={$docDate}";
                $pdfContent = $this->fetchUrl($LisResultUrl, 20);
                if ($pdfContent !== false && strlen($pdfContent) > 0) {
                    $filesData[] = [
                        'FileName'   => "{$labNo}_{$timestamp}.pdf",
                        'Filebase64' => base64_encode($pdfContent),
                    ];
                }

                $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) {
                                $filesData[] = [
                                    'FileName'   => "{$labNo}_{$timestamp}_{$fn}",
                                    'Filebase64' => base64_encode($content),
                                ];
                            }
                        }
                    }
                }
            }

            // build test item (do not filter out empty strings)
            $testItem = [
                'TestCode' => (string)($rows['TestCode'] ?? ''),
                'TestName' => (string)($rows['TestName'] ?? ''),
                'TestRemark' => $rows['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['ResultCode'] ?? ''),
                    'ResultName' => (string)($rows['ResultName'] ?? ''),
                    'ResultValue' => (string)($rows['RiaLDRsltAnal'] ?? ''),
                    'ResultUnit' => (string)($rows['LabUnit'] ?? ''),
                    'ResultFlag' => '',
                    'ReferenceRange' => trim(($rows['LabNormal1'] ?? '') . ' ' . ($rows['LabNormal2'] ?? '')),
                    'ResultRemark' => '',
                ]],
            ];

            if (!isset($groupedByLabNo[$labNo])) {
                $groupedByLabNo[$labNo] = [
                    'LabNo' => $labNo,
                    'RequestRemark' => '',
                    'ResultStatus' => '',
                    'TestList' => [],
                ];
            }

            $groupedByLabNo[$labNo]['TestList'][] = $testItem;
            $sendMapping[$rows['RiaHDocID']] = $rows['RiaHDocID'];

            // prepare payload for this lab (do not strip empty strings)
            $payload = $groupedByLabNo[$labNo];

            /*if (empty($payload) || !isset($payload['LabNo'])) {
                //$this->logConsole("Skipping send: payload missing LabNo for key={$labNo}", 'warning');
                error_log("Skipping send: payload missing LabNo for key={$labNo}", 'warning');
                continue;
            }

            // --- NEW: log the JSON payload (truncated) ---
            $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            //$this->logConsole("Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));
            error_log("Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));
            // ------------------------------------------------

            // แปลง TestList เป็น array ของ "TestCode:TestName"
            $tests = array_map(function ($t) {
                // ป้องกันกรณี key หายไป
                $code = isset($t['TestCode']) ? $t['TestCode'] : '(noCode)';
                $name = isset($t['TestName']) ? $t['TestName'] : '(noName)';
                return $code . ':' . $name;
            }, $payload['TestList'] ?? []);

            // ใส่ลงใน error_log แบบเดียวกับของเดิม
            error_log(
                "Sending payload for LabNo={$payload['LabNo']} " .
                    "(tests=" . json_encode($tests, JSON_UNESCAPED_UNICODE) . "), " .
                    "RiaHDocID={$rows['RiaHDocID']}"
            );
            //$this->logConsole("Sending payload for LabNo={$payload['LabNo']} (tests=" . count($payload['TestList']) . ")");

            // FIRST attempt
            $response = $this->postJsonCurl($url, $payload, [
                'Authorization' => "Bearer {$token}",
                'Content-Type' => 'application/json',
            ]);

            $lastResponse = $response;
            $rawResp = $response['response'] ?? '';
            $httpCode = $response['http_code'] ?? 0;
            $curlErr = $response['curl_error'] ?? null;

            if (!empty($curlErr)) {
                //$this->logConsole("cURL error: {$curlErr}", 'warning');
                //error_log("cURL error: {$curlErr}", 'warning');
                error_log("WARNING: cURL error: {$curlErr}");
            }

            // IF 401, refresh token and RETRY ONCE (no loop)
            if ($httpCode == 401) {
                //$this->logConsole("401 Unauthorized received — refreshing token and retrying", 'warning');
                error_log("401 Unauthorized received — refreshing token and retrying", 'warning');
                $token = $this->getValidApiToken($cfg, $tokenError);
                if (!empty($token)) {
                    // --- NEW: log payload again before retry (may help to confirm unchanged payload) ---
                    //$this->logConsole("Retrying with refreshed token. Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));
                    error_log("Retrying with refreshed token. Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));
                    // -------------------------------------------------------------------------------
                    $response = $this->postJsonCurl($url, $payload, [
                        'Authorization' => "Bearer {$token}",
                        'Content-Type' => 'application/json',
                    ]);
                    $lastResponse = $response;
                    $rawResp = $response['response'] ?? '';
                    $httpCode = $response['http_code'] ?? 0;
                    $curlErr = $response['curl_error'] ?? null;
                    if (!empty($curlErr)) {
                        //$this->logConsole("cURL error on retry: {$curlErr}", 'warning');
                        error_log("cURL error on retry: {$curlErr}", 'warning');
                    }
                } else {
                    //$this->logConsole("Failed to refresh token after 401", 'error');
                    error_log("Failed to refresh token after 401", 'error');
                }
            }
            error_log("Response (http={$httpCode}): " . $this->truncateForLog($rawResp, 8192));*/
            //$this->logConsole("Response (http={$httpCode}): " . $this->truncateForLog($rawResp, 8192));

            if (empty($payload) || !isset($payload['LabNo'])) {
                $labKey = $payload['LabNo'] ?? ($rows['LabNo'] ?? '(unknown)');
                error_log("Skipping send: payload missing LabNo for key={$labKey}");
                continue;
            }

            $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            $payloadJson = ($payloadJson === false) ? var_export($payload, true) : $payloadJson;
            error_log("Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));

            $tests = array_map(function ($t) {
                $code = $t['TestCode'] ?? '(noCode)';
                $name = $t['TestName'] ?? '(noName)';
                return $code . ':' . $name;
            }, $payload['TestList'] ?? []);

            error_log("Sending payload for LabNo=" . ($payload['LabNo'] ?? '(unknown)') .
                " (tests=" . json_encode($tests, JSON_UNESCAPED_UNICODE) . "), RiaHDocID=" . ($rows['RiaHDocID'] ?? '(nil)'));

            $response = $this->postJsonCurl($url, $payload, [
                'Authorization' => "Bearer {$token}",
                'Content-Type' => 'application/json',
            ]);

            $lastResponse = $response;
            $rawResp = $response['response'] ?? '';
            $httpCode = (int)($response['http_code'] ?? 0);
            $curlErr = $response['curl_error'] ?? null;

            if (!empty($curlErr)) {
                error_log("WARNING: cURL error: {$curlErr}");
            }

            if ($httpCode === 401) {
                error_log("401 Unauthorized received — refreshing token and retrying");
                $token = $this->getValidApiToken($cfg, $tokenError);
                if (!empty($token)) {
                    error_log("Retrying with refreshed token. Payload (truncated): " . $this->truncateForLog($payloadJson, 8192));
                    $response = $this->postJsonCurl($url, $payload, [
                        'Authorization' => "Bearer {$token}",
                        'Content-Type' => 'application/json',
                    ]);
                    $lastResponse = $response;
                    $rawResp = $response['response'] ?? '';
                    $httpCode = (int)($response['http_code'] ?? 0);
                    $curlErr = $response['curl_error'] ?? null;
                    if (!empty($curlErr)) {
                        error_log("WARNING: cURL error on retry: {$curlErr}");
                    }
                } else {
                    error_log("ERROR: Failed to refresh token after 401");
                }
            }

            error_log("Response (http={$httpCode}): " . $this->truncateForLog((string)$rawResp, 8192));


            // decode and check success
            $decoded = json_decode($rawResp, true);
            $statusVal = $decoded['Status'] ?? $decoded['status'] ?? null;
            $messageVal = $decoded['Message'] ?? $decoded['message'] ?? '';

            $success = false;
            if (is_numeric($statusVal)) {
                $success = (intval($statusVal) === 0);
            } elseif (is_string($statusVal) && strtolower($statusVal) === 'success') {
                $success = true;
            } elseif (is_string($messageVal) && strpos(strtolower($messageVal), 'success') !== false) {
                $success = true;
            } elseif (is_string($rawResp) && strpos(strtolower($rawResp), '"status":0') !== false) {
                $success = true;
            }

            if ($success) {
                //$this->logConsole("SUCCESS LabNo={$labNo}");
                error_log("Success LabNo={$labNo}, RiaHDocID=" . ($rows['RiaHDocID'] ?? ''));

                $exists = LisResult::find()->where([
                    'lab_no' => $rows['LabNo'],
                    'test_code' => $rows['TestCode'],
                    'cust_id' => $rows['CustID'],
                    'hn' => $rows['PatHN'],
                ])->exists();

                if (!$exists) {
                    $LisResult = new LisResult([
                        'lab_no' => $rows['LabNo'],
                        'riah_doc_id' => $rows['RiaHDocID'],
                        'riah_doc_date' => $rows['RiaHDocDate'],
                        'test_code' => $rows['TestCode'],
                        'test_name' => $rows['TestName'],
                        'cust_id' => $rows['CustID'],
                        'hn' => $rows['PatHN'],
                        'result_value' => $rows['RiaLDRsltAnal'] ?? '',
                        'result_unit' => $rows['LabUnit'] ?? '',
                        'reference_range' => trim(($rows['LabNormal1'] ?? '') . ' ' . ($rows['LabNormal2'] ?? '')),
                        'status' => 1,
                    ]);
                    $LisResult->save(false);
                } else {
                    error_log("Record already exists in LisResult, skipping insert: LabNo={$rows['LabNo']}, TestCode={$rows['TestCode']}, CustID={$rows['CustID']}, HN={$rows['PatHN']}", 'warning');
                    //$this->logConsole("Record already exists in LisResult, skipping insert: LabNo={$rows['LabNo']}, TestCode={$rows['TestCode']}, CustID={$rows['CustID']}, HN={$rows['PatHN']}", 'warning');
                }
            } else {
                $msg = $lastResponse['response'] ?? ($lastResponse['curl_error'] ?? 'ไม่พบข้อมูลตอบกลับ');
                error_log("FAIL LabNo={$labNo}; last_http=" . ($lastResponse['http_code'] ?? 'ไม่พบข้อมูลตอบกลับ') . "; message=" . $this->truncateForLog($msg, 1024));
                //$this->logConsole("FAIL LabNo={$labNo}; last_http=" . ($lastResponse['http_code'] ?? 'ไม่พบข้อมูลตอบกลับ') . "; message=" . $this->truncateForLog($msg, 1024), 'error');
            }
        } // end foreach
        error_log("=== Hanuman Result Sikarin END ===");
        //$this->logConsole("=== Hanuman Result Sikarin END ===");
        return 0;
        //var_dump($payload);
    }
}
