<?php

namespace App\Http\Controllers;

use App\Models\ConfServerLicense;
use App\Models\ConfServerLicenseJavaversion;
use App\Models\ConfServerLicenseOrgcontrol;
use App\Models\ConfServerLicenseOrglist;
use Illuminate\Support\Facades\File;
use App\Models\ConfServerPendding;
use App\Models\HscodeStatus;
use App\Models\TabPatchFile;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Throwable;

class SmartUpdateController extends Controller
{
    public function checkAction(Request $request)
    {

        $serviceName = $request->input('SERVICENAME');
        $action = $request->input('ACTION');
        $serverKeyClient = $request->input('SERVERKEYCLIENT');

        // if ($serviceName !== 'SMARTUPDATE' || $action !== 'HISTORY_PATCH') {
        //     return response()->json(['error' => 'Invalid request'], 400);
        // }

        if ($action === 'HISTORY_PATCH') {
            $this->historyPatch($serverKeyClient);
        } else if ($action === 'LIST_PATCH') {
            $this->listPatch($request);
        } else if ($action === 'UPDATE_PATCH') {
            $this->updatePatch($request);
        } else if ($action === 'FINISH_PATCH') {
            $this->finishPatch($request);
        }
    }

    public function historyPatch($serverKeyClient)
    {
        $serverId = DB::table('conf_server_license')
            ->where('SNKEY', $serverKeyClient)
            ->value('ID');

        if (!$serverId) {
            return response()->json(['error' => 'Invalid SERVERKEYCLIENT'], 404);
        }
        $patchHistory = $this->queryToSimpleTable("
            SELECT 
                TaskFinish as 'Update Date', 
                TaskRunner as 'Update By', 
                PDATE as 'Patch Date', 
                PATCHNAME as 'Title', 
                PLEVEL as 'Level', 
                PDESC as 'Description' 
            FROM conf_server_pendding AS t0 
            INNER JOIN conf_smartupdate AS t1 
            ON t0.PatchID = t1.PID 
            WHERE ServerId = '$serverId' 
            AND TaskStatus = 999 
            AND PAPPROVEDATE < NOW() 
            AND PAPPROVEDATE <> '0000-00-00 00:00:00' 
            AND TaskDate < NOW() 
            AND TaskDate <> '0000-00-00 00:00:00'
        ");

        return $patchHistory;
    }

    public function listPatch($request)
    {
        $serverKeyClient = $request->input('SERVERKEYCLIENT');
        $clientVersion = $request->input('CLIENTVERSION');

        $serverId = $this->getServerId($serverKeyClient);

        if (!$serverId) {
            return response()->json(['error' => 'Invalid SERVERKEYCLIENT'], 404);
        }
        $pendingUpdates = ConfServerPendding::select(
            't0.PatchID as PatchID',
            't1.PDATE as PatchDate',
            't1.PATCHNAME as Title',
            't1.PLEVEL as Level',
            't1.PDESC as Description',
            DB::raw("IF('{$clientVersion}' <= t1.major_version, 'Update', 'Version incompatible') AS Action")
        )
            ->from('conf_server_pendding as t0')
            ->join('conf_smartupdate as t1', 't0.PatchID', '=', 't1.PID')
            ->where('t0.ServerId', $serverId)
            ->where('t0.TaskStatus', '<', 999)
            ->where('t1.PAPPROVEDATE', '<', now())
            ->where('t1.PAPPROVEDATE', '<>', '0000-00-00 00:00:00')
            ->where('t0.TaskDate', '<', now())
            ->where('t0.TaskDate', '<>', '0000-00-00 00:00:00')
            ->orderBy('t0.PatchID', 'ASC')
            ->get();

        $cannotUpdateAll = false;
        foreach ($pendingUpdates as $index => $update) {
            if ($index > 0 && $update->Action == 'Update') {
                $update->Action = 'Require previous update';
            }

            if ($update->Action == 'Version incompatible') {
                $cannotUpdateAll = true;
            }
        }

        DB::table('log_history')->insert([
            'HDATE' => now(),
            'HSID' => $serverId,
            'HACTION' => 'LIST_PATCH',
        ]);

        ConfServerPendding::where('ServerID', $serverId)
            ->where('TaskStatus', '<', 999)
            ->where('TaskDate', '<', now())
            ->update(['TaskStatus' => 1]);

        $htmlContent = view('smartupdate.patch_update', [
            'serverKeyClient' => $serverKeyClient,
            'pendingUpdates' => $pendingUpdates,
            'clientVersion' => $clientVersion,
            'cannotUpdateAll' => $cannotUpdateAll,
            'uId' => $request->input('MUID'),
            'uCode' => $request->input('MUCODE'),
        ])->render();

        echo iconv("UTF-8", "TIS-620", $htmlContent);
    }
    public function queryToSimpleTable($query, $numberSortOpt = "YES", $columnSortOpt = "YES", $colorPack = ['#DDDDDD', '#F2F2F2', '#FFFFFF', '#F2F2FF'], $noCodeIfEmpty = "NO")
    {
        $result = DB::select($query);

        if (empty($result)) {
            return $noCodeIfEmpty === "YES" ? '' : '<p>No data found.</p>';
        }


        $columns = array_keys((array) $result[0]);
        $tabID = 'table' . rand() + 50;
        $res = $columnSortOpt === "YES" ? "<script src=\"core/resource/sortTable.js\"></script>" : "";

        $res .= "<center><table id='$tabID' border=0 cellpadding=5 cellspacing=1 bgcolor='{$colorPack[0]}' width=100% nowrap='nowrap'><thead class='simpleThead'><tr>";

        foreach ($columns as $column) {
            $res .= "<td bgcolor='{$colorPack[1]}'><b><font face='Arial, Helvetica, sans-serif' size=1>" . ($column) . "</font></b></td>";
        }
        $res .= "</tr></thead><tbody class='simpleTbody'>";

        foreach ($result as $index => $row) {
            $bgColor = $colorPack[($index % 2) + 2];
            $res .= "<tr>";
            foreach ($columns as $column) {
                $align = is_numeric(str_replace(',', '', $row->$column)) && $numberSortOpt === "YES" ? " align='right' " : '';
                $res .= "<td valign='top' $align bgcolor='$bgColor' nowrap='nowrap'><font face='Arial, Helvetica, sans-serif' size=2>" . ($row->$column) . "</font></td>";
            }
            $res .= "</tr>";
        }

        $res .= "</tbody></table></center>";

        if ($columnSortOpt === "YES") {
            $res .= "<script language='javascript'>initTable(\"$tabID\");</script>";
        }

        return $res;
    }

    public static function updatePatch($request)
    {
        $serverKeyClient = $request->input('SERVERKEYCLIENT');
        $clientVersion = $request->input('CLIENTVERSION');
        $patchId = $request->input('PATCHID');

        $serverId = DB::table('conf_server_license')
            ->where('SNKEY', $serverKeyClient)
            ->value('ID');


        if (!empty($clientVersion)) {
            DB::table('conf_server_license')
                ->where('ID', $serverId)
                ->update(['cur_version' => $clientVersion]);
        }

        if ($patchId === 'AUTO') {
            $patchId = DB::table('conf_server_pendding as t0')
                ->join('conf_smartupdate as t1', 't0.PatchID', '=', 't1.PID')
                ->where('t1.PLEVEL', 'AUTO')
                ->where('t0.ServerId', $serverId)
                ->where('t0.TaskStatus', '<', 999)
                ->where('t1.PAPPROVEDATE', '<', now())
                ->where('t1.PAPPROVEDATE', '<>', '0000-00-00 00:00:00')
                ->where('t0.TaskDate', '<', now())
                ->where('t0.TaskDate', '<>', '0000-00-00 00:00:00')
                ->value('PID');
            $mode = 'AUTO';
        }

        $patchDetails = DB::table('conf_server_pendding as t0')
            ->join('conf_smartupdate as t1', 't0.PatchID', '=', 't1.PID')
            ->where('t1.PID', $patchId)
            ->where('t0.ServerId', $serverId)
            ->where('t0.TaskStatus', '<', 999)
            ->where('t1.PAPPROVEDATE', '<', now())
            ->where('t1.PAPPROVEDATE', '<>', '0000-00-00 00:00:00')
            ->where('t0.TaskDate', '<', now())
            ->where('t0.TaskDate', '<>', '0000-00-00 00:00:00')
            ->first(['PATCHCODE_SERVER', 'PATCHCODE', 'MAJOR_VERSION']);

        if ($patchDetails && $clientVersion > $patchDetails->MAJOR_VERSION) {
            return response()->json([
                'status' => 'FAILED',
                'message' => 'Version Incompatible.',
            ]);
        }
        if (!empty($patchDetails->PATCHCODE_SERVER)) {
            $ptid = static::extractPtid($patchDetails->PATCHCODE_SERVER);
            $pacthFiles = TabPatchFile::where("ptid", $ptid)->get();
            foreach ($pacthFiles as $index => $row) {
                ${'file_name_' . $index} = $row->file_name;
                ${'file_data_' . $index} = $row->file_data;
            }
            $max = count($pacthFiles);

            $checkDeployemnt = strpos($patchDetails->PATCHCODE_SERVER, 'file_exists("deployment/".$VERSION');
            $checkExchangeRate = strpos($patchDetails->PATCHCODE_SERVER, 'center_conf_exchangerate');


            if ($checkDeployemnt !== false) {
                $folder = static::extractVersion($patchDetails->PATCHCODE_SERVER);
                $DOUPGRADE = "N";
                if (!empty($folder)) {
                    if (Storage::exists("deployment/" . $folder)) {
                        $DOUPGRADE = "Y";
                        // if (Storage::exists("deployment/" . $folder . ".cachefiles")) {
                        //     $DATA = Storage::get("deployment/" . $folder . ".cachefiles");
                        // } else {
                        $DATA = base64_encode(gzcompress(var_export(static::getFileVersion($folder), true)));
                        // Storage::put("deployment/" . $folder . ".cachefiles", $DATA);
                        // }
                        // if (Storage::exists("deployment/" . $folder . ".cachedirs")) {
                        //     $DATADIR = Storage::get("deployment/" . $folder . ".cachedirs");
                        // } else {
                        $DATADIR = base64_encode(gzcompress(var_export(static::getDirVersion($folder), true)));
                        // Storage::put("deployment/" . $folder . ".cachedirs", $DATADIR);
                        // }
                    } else {
                        $DOUPGRADE = "N";
                    }
                }
                $file_name_0 = '';
                $file_data_0 = '';
            }
            $patchCodeServer = str_replace('Query2Var', 'static::Query2Var', $patchDetails->PATCHCODE_SERVER);
            $patchCodeServer = str_replace('Query2SQL', 'static::Query2SQL', $patchCodeServer);
            if ($checkExchangeRate !== false) {
                $codeEval = strpos($patchDetails->PATCHCODE_SERVER, '//import');
                if ($codeEval !== false) {
                    $result = substr($patchDetails->PATCHCODE_SERVER, 0, $codeEval);
                }
                eval($result);
                $sourceTable = 'center_conf_exchangerate';
                $destinationTable = 'conf_exchangerate';
                $conditionColumn = 'exdate';
                $conditionValue = $MONTH;
                $additionalColumns = [
                    'amenddate' => $UPDATECODE
                ];
                $resultImport = static::generateInsertSQLWithCount($sourceTable, $destinationTable, $conditionColumn, $conditionValue, $additionalColumns);
                $serverchk  = $resultImport["total"];
                $SQL1 = $resultImport["sql"];

                $sourceTable = 'center_conf_exchangerate_export';
                $destinationTable = 'conf_exchangerate_export';
                $resultExport = static::generateInsertSQLWithCount($sourceTable, $destinationTable, $conditionColumn, $conditionValue, $additionalColumns);
                $serverchk  = $resultImport["total"];
                $SQL2 = $resultImport["sql"];
            }

            $patchCode = $patchDetails->PATCHCODE;
            $patchCode =  str_replace('updatePatchFile("$$file_name_0", "$$file_data_0");', '', $patchCode);

            $patchCode = str_replace('$', '#', $patchCode);
            $patchCode = str_replace('##', '$', $patchCode);

            eval('$patchCode=<<<EOF2' . chr(13) . $patchCode . chr(13) . 'EOF2;' . chr(13));
            $patchCode = str_replace('#', '$', $patchCode);

            if (isset($mode) && $mode === 'AUTO') {
                $pid = DB::table('conf_server_pendding as t0')
                    ->join('conf_smartupdate as t1', 't0.PatchID', '=', 't1.PID')
                    ->where('t1.PLEVEL', 'AUTO')
                    ->where('t0.ServerId', $serverId)
                    ->where('t0.TaskStatus', '<', 999)
                    ->where('t1.PAPPROVEDATE', '<', now())
                    ->where('t1.PAPPROVEDATE', '<>', '0000-00-00 00:00:00')
                    ->where('t0.TaskDate', '<', now())
                    ->where('t0.TaskDate', '<>', '0000-00-00 00:00:00')
                    ->value('PID');

                if ($pid > 0) {
                    $patchCode .= "\$AUTO='#NEED_MORE_PATCH#';";
                    $patchCode .= "\$PATCHID=$patchId;";
                } else {
                    $patchCode .= "\$AUTO='#NO_MORE_PATCH#';";
                    $patchCode .= "\$PATCHID=$patchId;";
                }
            }

            if ($serverKeyClient == '3101023619000000120120228') {
                $patchCode = encrypt($patchCode, $serverKeyClient);
            }

            DB::table('log_history')->insert([
                'HDATE' => now(),
                'HSID' => $serverId,
                'HACTION' => "PATCH $patchId",
            ]);

            DB::table('conf_server_pendding')
                ->where('ServerId', $serverId)
                ->where('PatchID', $patchId)
                ->update(['TaskStatus' => 2]);



            echo base64_encode($patchCode);
        } else {
            echo base64_encode('$PATCH_STATUS="EMPTY PATCHCODE SERVER";');
        }
    }

    public function finishPatch($request)
    {
        $serverKeyClient = $request->input('SERVERKEYCLIENT');
        $action = $request->input('ACTION');
        $clientVersion = $request->input('CLIENTVERSION');
        $patchId = $request->input('PATCHID');
        $feedback = $request->input('FEEDBACK');
        $userRunner = $request->input('RUNNER');

        $serverId = DB::table('conf_server_license')
            ->where('SNKEY', $serverKeyClient)
            ->value('ID');

        if ($feedback != '') {
            $total = explode(';', $feedback);
            $total_tariff = '2397';
            $total_imduty = '325087';
            $total_stat = '19943';
            $count_tariff = $total[0] ?? null;
            $count_statcode = $total[1] ?? null;
            $count_imduty = $total[2] ?? null;

            if ($count_tariff != '') {
                $status_tariff = $total_tariff == $count_tariff ? 'master_tariff : successful' : 'master_tariff : failed';
                HscodeStatus::updateOrCreate(
                    ['id' => 1, 'serverkey' => $serverKeyClient],
                    ['recordtotal' => $total_tariff, 'recordcustoms' => $count_tariff, 'status' => $status_tariff, 'finishtime' => now()]
                );
            }

            if ($count_imduty != '') {
                $status_imduty = $total_imduty == $count_imduty ? 'master_imduty : successful' : 'master_imduty : failed';
                HscodeStatus::updateOrCreate(
                    ['id' => 2, 'serverkey' => $serverKeyClient],
                    ['recordtotal' => $total_imduty, 'recordcustoms' => $count_imduty, 'status' => $status_imduty, 'finishtime' => now()]
                );
            }

            if ($count_statcode != '') {
                $status_statcode = $total_stat == $count_statcode ? 'master_statcode : successful' : 'master_statcode : failed';
                HscodeStatus::updateOrCreate(
                    ['id' => 3, 'serverkey' => $serverKeyClient],
                    ['recordtotal' => $total_stat, 'recordcustoms' => $count_statcode, 'status' => $status_statcode, 'finishtime' => now()]
                );
            }

            if (strpos($feedback, ':')) {
                $arr_ = explode(':', $feedback);
                if ($arr_[0] == 'FEEDBACK_FILE') {
                    $directoryPath = "FEEDBACKFILE/$serverKeyClient";
                    if (!Storage::exists($directoryPath)) {
                        Storage::makeDirectory($directoryPath);
                    }

                    $filePath = $directoryPath . "/" . $arr_[1];
                    Storage::put($filePath, gzuncompress(base64_decode($arr_[2])));
                }
            }

            $serverLicense = ConfServerLicense::where('SNKEY', $serverKeyClient)->first();
            if ($serverLicense->BACKUP_FEEDBACK != '' && $patchId != env('PATCH_DOWNLOADFILE_ID')) {
                // Insert history
                DB::table('conf_server_backup_history')->insert([
                    'SNKEY' => $serverKeyClient,
                    'BACKUP_VERSION' => $serverLicense->BACKUP_DATE,
                    'BACKUP_DATA' => $serverLicense->BACKUP_FEEDBACK,
                    'BACKUP_BY' => $serverLicense->BACKUP_STATUS,
                ]);
            }

            ConfServerLicense::where('SNKEY', $serverKeyClient)->update([
                'BACKUP_DATE' => now(),
                'BACKUP_STATUS' => $userRunner,
                'BACKUP_FEEDBACK' => $feedback
            ]);
        }

        if (!empty($clientVersion)) {
            if (is_array($clientVersion)) {
                if (!empty($clientVersion['PHPVERSION'])) {
                    $serverkeyPHPVersion = $clientVersion['PHPVERSION'];
                    $PHP_VERSION_ID = strpos($serverkeyPHPVersion, "5.2") !== false ? 1 : 2;

                    ConfServerLicense::where('SNKEY', $serverKeyClient)
                        ->update(['PHP_VERSION_ID' => $PHP_VERSION_ID]);
                }

                if (!empty($clientVersion['JAVAVERSION'])) {
                    $fullText = implode(" || ", $clientVersion['JAVAVERSION']);

                    $javaVersion = new ConfServerLicenseJavaversion;
                    $javaVersion->SNKEY = $serverKeyClient;
                    $javaVersion->javaversion = $clientVersion['JAVAVERSION'][0];
                    $javaVersion->javaVersionFullText = $fullText;
                    $javaVersion->lastUpdate = now();
                    $javaVersion->save();

                    ConfServerLicenseJavaVersion::where('id', '<', $javaVersion->id)
                        ->where('SNKEY', $serverKeyClient)
                        ->delete();
                }

                if (!empty($clientVersion['GETORGANIZE'])) {
                    $checkDuplicate = ConfServerLicenseOrgcontrol::where('SNKEY', $serverKeyClient)
                        ->whereDate('createDate', now())
                        ->first();

                    if ($checkDuplicate) {
                        $this->deleteGetOrganize($checkDuplicate->id);
                    }

                    $controlId = DB::table('conf_server_license_orgcontrol')->insertGetId([
                        'SNKEY' => $serverKeyClient,
                        'createDate' => now(),
                    ]);

                    foreach ($clientVersion['GETORGANIZE'] as $arrayData) {
                        ConfServerLicenseOrglist::create([
                            'controlId' => $controlId,
                            'spnOrganize' => $arrayData['ORG'],
                        ]);
                    }
                }
            } else {
                ConfServerLicense::where('SNKEY', $serverKeyClient)
                    ->update(['cur_version' => $clientVersion]);
            }
        }

        DB::table('log_history')->insert([
            'HDATE' => now(),
            'HSID' => $serverId,
            'HACTION' => "$action $patchId"
        ]);

        DB::table('conf_server_pendding')
            ->where('ServerId', $serverId)
            ->where('PatchId', $patchId)
            ->update([
                'TaskStatus' => 999,
                'TaskFinish' => now(),
                'TaskRunner' => $userRunner
            ]);

        $patchName = DB::table('conf_smartupdate')->where('pid', $patchId)->value('PATCHNAME');
        echo base64_encode("\$PATCHNAME=\"$patchName\";");
    }


    public static function  processPatchCode($patchCode)
    {
        $patchCode = str_replace('$', '#', $patchCode);
        $patchCode = str_replace('##', '$', $patchCode);
        eval('$patchCode=<<<EOF2' . chr(13) . $patchCode . chr(13) . 'EOF2;' . chr(13));
        $patchCode = str_replace('#', '$', $patchCode);

        return $patchCode;
    }

    public static function getServerId($serverKeyClient)
    {
        return DB::table('conf_server_license')
            ->where('SNKEY', $serverKeyClient)
            ->value('ID');
    }


    function encrypt($pure_string, $encryption_key)
    {
        $cipher = "aes-256-cbc";
        $iv_size = openssl_cipher_iv_length($cipher);
        $iv = openssl_random_pseudo_bytes($iv_size);
        $encrypted_string = openssl_encrypt($pure_string, $cipher, $encryption_key, 0, $iv);
        return base64_encode($encrypted_string . '::' . $iv);
    }
    // function encrypt($pure_string, $encryption_key) {
    //     $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
    //     $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    //     $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
    //     return $encrypted_string;
    // }

    public static function getFileVersion($version)
    {
        $DATA = [];
        $directoryPath = storage_path("app/deployment/" . $version);

        if (File::exists($directoryPath)) {
            $files =  File::allFiles($directoryPath);

            foreach ($files as $file) {
                $contents = File::get($file);
                $relativeFilePath = substr($file->getPathname(), strlen($directoryPath) + 1);
                $DATA[$relativeFilePath] = base64_encode($contents);
            }
        }
        return $DATA;
    }
    public static function getDirVersion($version)
    {
        $DATA = array();
        $directoryPath = storage_path("app/deployment/" . $version);

        if (File::exists($directoryPath)) {
            $files = File::allFiles($directoryPath);

            foreach ($files as $file) {
                $path_parts = pathinfo($file);

                $dir = substr($path_parts['dirname'], strlen($directoryPath) + 1);
                $DATA[$dir] = $dir;
            }
        }
        return $DATA;
    }


    public static function extractPtid($string)
    {
        $pattern = "/ptid\s*=\s*'(\d+)'/";
        if (preg_match($pattern, $string, $matches)) {
            return $matches[1];
        }
        return null;
    }
    public static function extractVersion($string)
    {
        $pattern = '/\$VERSION\s*=\s*"([^"]+)"/';

        if (preg_match($pattern, $string, $matches)) {
            return $matches[1];
        }
        return null;
    }

    public static function generateInsertSQLWithCount($sourceTable, $destinationTable, $conditionColumn, $conditionValue, $additionalColumns)
    {
        // Fetch data from the source table based on the condition
        $rows = DB::table($sourceTable)
            ->where($conditionColumn, 'like', $conditionValue)
            ->get();

        // Check if rows exist
        if ($rows->isEmpty()) {
            return [
                'total' => 0,
                'sql' => ''
            ];
        }

        // Detect the database type
        $dbType = config('database.default');
        $quoteL = $dbType === 'sqlsrv' ? '[' : '`';
        $quoteR = $dbType === 'sqlsrv' ? ']' : '`';

        $insertStatements = [];

        foreach ($rows as $row) {
            $values = [];

            // Include all columns from the row dynamically
            foreach ((array)$row as $column => $value) {
                // Escape single quotes for MSSQL and MySQL
                $escapedValue = str_replace("'", "''", $value);

                // Handle special MSSQL cases, e.g., default datetime
                if ($escapedValue === '0000-00-00 00:00:00') {
                    $escapedValue = '2000-01-01 00:00:00';
                }

                $values[] = "'$escapedValue'";
            }

            // Append additional columns (e.g., `amenddate`) dynamically
            foreach ($additionalColumns as $key => $value) {
                $escapedValue = str_replace("'", "''", $value);
                $values[] = "'$escapedValue'";
            }

            // Create the INSERT statement
            $columns = array_keys((array)$row);
            $columns = array_merge($columns, array_keys($additionalColumns));

            $quotedColumns = array_map(fn($col) => $quoteL . $col . $quoteR, $columns);
            $insertStatements[] = "INSERT INTO $quoteL$destinationTable$quoteR (" . implode(', ', $quotedColumns) . ") VALUES (" . implode(', ', $values) . ");";
        }

        // Combine all statements into a single string
        return [
            'total' => $rows->count(),
            'sql' => implode("\n", $insertStatements)
        ];
    }
}
