<?php

namespace App\Http\Controllers;

use App\Models\ConfFormatFile;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Http;

class MasterFileController extends Controller
{
    public function index()
    {
        $menu = 'MasterFile';
        $currentContent = 'MasterFile';
        return view('home', compact('menu', 'currentContent'));
    }

    public function createPatch(Request $request)
    {
        // $request->validate([
        //     'format_file_id' => 'required|exists:conf_format_file,formatservice_ID',
        //     'file' => 'required|file|max:12209752',
        //     'limit' => 'nullable|integer',
        //     'noLimit' => 'nullable|boolean',
        //     'genWithSmartUpdate' => 'nullable|boolean',
        //     'createPatch' => 'nullable|boolean',
        //     'sendToEec' => 'nullable|boolean',
        // ]);

        $file = $request->file('file');
        $filePath = $file->getRealPath();

        if(isset($request->truncateGoods) && ($request->format_file_id == 196)) {
            $truncateGoods = true ;
        }else{
            $truncateGoods = false ;
        }
       

        $fileFormat = ConfFormatFile::where('formatservice_ID', $request->format_file_id)->first();
        $jsonFilePath = storage_path(str_replace(".inc", ".json", $fileFormat->file));

        if (!file_exists($jsonFilePath)) {
            return redirect()->back()->withErrors(['error' => 'Format JSON file not found.']);
        }

        $formatData = json_decode(file_get_contents($jsonFilePath), true);
        $message = '';

        if ($request->createPatch) {
            $sqlPackAll = $this->readTxt($filePath, $formatData, $fileFormat, $request->limit, $request->noLimit);

            $this->processPatches($sqlPackAll, $fileFormat, $request->genWithSmartUpdate, $request->noLimit , $truncateGoods);
            $message .= 'Patch master file created successfully. ';
        }

        if ($request->sendToEec && !empty($fileFormat->ac)) {
            $timestamp = Carbon::now()->toDateString();
            $response = $this->sendMasterFileToEcc(config('services.eec.url'), [
                'type' => $fileFormat->ac,
                'file' => fopen($filePath, 'r'),
                'timestamp' => $timestamp,
            ]);

            $responseStatus = $response->status();
            $responseData = $response->json();

            $this->keepTransactionToEcc(auth()->id(), $fileFormat->ac, $file->getClientOriginalName(), json_encode([
                'type' => $fileFormat->ac,
                'timestamp' => $timestamp,
            ]), Carbon::now(), $responseStatus, json_encode($responseData));

            $message .= 'Send to EEC successfully.';
        }

        return redirect()->route('patch.index')->with('message', $message);
    }

    private function sendMasterFileToEcc($url, $postData)
    {
        return Http::attach('file', $postData['file'])
            ->asMultipart()
            ->post($url, [
                'type' => $postData['type'],
                'timestamp' => $postData['timestamp'],
            ]);
    }

    private function keepTransactionToEcc($uid, $type, $filename, $requestData, $datetime, $responseStatus, $responseData)
    {
        DB::table('log_send_master2eec')->insert([
            'UID' => $uid,
            'TYPE' => $type,
            'FILENAME' => $filename,
            'REQDATA' => $requestData,
            'ACTDATETIME' => $datetime,
            'RESPSTATUS' => $responseStatus,
            'RESPDATA' => $responseData,
        ]);
    }

    function processPatches($sqlPackAll,  $fileFormat, $genSpnSmartUpdateDecode, $noLimit , $truncateGoods)
    {
        $uid = auth()->user()->id;
        $pLevel = "Critical";
        $nameFormat = $fileFormat->name ?? 'Unknown Format';
        $pDesc = $nameFormat;
        $day = Date('j');
        $month = Date('n');
        $year = Date('Y');
        $pApproveDate = date("Y-m-d h:i:s");
        $partPatch = '';
        $countSql = count($sqlPackAll);
        $part = 1;

        foreach ($sqlPackAll as $i__ => $sqlPack) {
            if ($countSql != 1 && !$noLimit) {
                $partPatch = 'Part ' . $part++;
            }


            // $utf8_encoded = mb_convert_encoding(var_export($sqlPack, true), 'UTF-8', 'auto');

            // $utf8_encoded = mb_convert_encoding(var_export($sqlPack, true), 'UTF-8', 'auto');
            $tis620_encoded = iconv('UTF-8', 'Windows-874',var_export($sqlPack, true));
            // $tis620_encoded = var_export($sqlPack, true);
            // dd($tis620_encoded);
            $patchCode = '';
            if($truncateGoods) {
                $patchCode .= '$sql = "truncate table master_permissiongoods";
                                exec_query($sql);
                                if ($DBTYPE == "MSSQL") {
                                    $Count_CONSTRAINT = Query2ArrayVarPack("SELECT COUNT(TC.CONSTRAINT_NAME) AS count_CONSTRAINT,TC.CONSTRAINT_NAME  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC 
                                        INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KU   ON TC.CONSTRAINT_TYPE = "PRIMARY KEY" 
                                        AND TC.CONSTRAINT_NAME = KU.CONSTRAINT_NAME 
                                        and ku.table_name="master_permissiongoods" 
                                        GROUP BY TC.CONSTRAINT_NAME");

                                    if ($Count_CONSTRAINT["count_CONSTRAINT"][0] != 5) {
                                        exec_query("ALTER TABLE [master_permissiongoods] DROP CONSTRAINT [" . $Count_CONSTRAINT["CONSTRAINT_NAME"][0] . "]");
                                        exec_query("ALTER TABLE [master_permissiongoods] ADD CONSTRAINT [" . $Count_CONSTRAINT["CONSTRAINT_NAME"][0] . "] PRIMARY KEY([tariffClass],[tariffStat],[startDate],[permissionGoodsType],[companyTaxNo])");
                                    }
                                }';
            }
            $ALL64 = base64_encode(gzcompress($tis620_encoded));


            $patchCode .= '$ALL64="' . $ALL64 . '";' . "\n";

            if ($genSpnSmartUpdateDecode) {
                $updatedecode = '$ALLVAR=gzuncompress(spnsmartupdatedecode($ALL64));' . "\n";
            } else {
                $updatedecode = '$ALLVAR=gzuncompress(base64_decode($ALL64));' . "\n";
            }

            $patchCode .= $updatedecode;
            $patchCode .= "eval('\$SQL='." . '$ALLVAR.";");' . "\n";
            $patchCode .= $this->generatePatchCode($countSql, $i__);

            if ($noLimit && ($i__ == $countSql - 1)) {
                $this->savePatch($patchCode, $nameFormat, $day, $month, $year, $partPatch, $pLevel, $pDesc, $uid, $pApproveDate);
            } elseif (!$noLimit) {
                $this->savePatch($patchCode, $nameFormat, $day, $month, $year, $partPatch, $pLevel, $pDesc, $uid, $pApproveDate);
            }
        }
    }


    private function generatePatchCode($countSql, $i__)
    {
        $patchCode = '';
        $patchCode .= '$insert=$SQL["insert"];' . "\n";
        $patchCode .= '$update=$SQL["update"];' . "\n";
        $patchCode .= '$select=$SQL["select"];' . "\n";
        $patchCode .= '$select2=$SQL["select2"];' . "\n";
        $patchCode .= '$DATABASE=$SQL["DATABASE"];' . "\n";
        $patchCode .= '$CountSQL_=count($insert);' . "\n";
        $patchCode .= '$succ="0";' . "\n";
        $patchCode .= '$succ2="0";' . "\n";
        $patchCode .= 'for($i_=0;$i_<$CountSQL_;$i_++){' . "\n";
        $patchCode .= '    $INSERT_ID="";' . "\n";
        $patchCode .= '    if($DBTYPE=="MYSQL"){' . "\n";
        $patchCode .= '        $sql=$insert[$i_]." ON DUPLICATE KEY UPDATE ".$update[$i_];' . "\n";
        $patchCode .= '    }' . "\n";
        $patchCode .= '    if($DBTYPE=="MSSQL"){' . "\n";
        $patchCode .= '        $sql="IF EXISTS (".$select[$i_].") BEGIN UPDATE $DATABASE SET ".$update[$i_].$select2[$i_]." END ELSE ".$insert[$i_];' . "\n";
        $patchCode .= '    }' . "\n";
        $patchCode .= '    exec_query($sql);' . "\n";
        $patchCode .= '    $succ++;' . "\n";
        $patchCode .= '    if($INSERT_ID!=""){$succ2++;}' . "\n";
        $patchCode .= '}' . "\n";
        $patchCode .= 'unset($ALL64);' . "\n";
        $patchCode .= 'unset($ALLVAR);' . "\n";
        $patchCode .= 'unset($SQL);' . "\n";
        $patchCode .= 'unset($insert);' . "\n";
        $patchCode .= 'unset($update);' . "\n";
        $patchCode .= 'unset($select);' . "\n";
        $patchCode .= 'unset($select2);' . "\n";
        $patchCode .= '$PRINT_ .=  date("h:i:s")." Process ' . ($i__ + 1) . ' / ' . $countSql . ' Successful Update $succ data(s) (Added = $succ2) from $CountSQL_.</br>";' . "\n";

        return $patchCode;
    }

    private function savePatch($patchCode, $nameformat, $day, $month, $year, $partPatch, $PLEVEL, $PDESC, $UID, $PAPPROVEDATE)
    {

        $patchCode .= '$PRINTOUT=$PRINT_;' . "\n";
        $patchCode .= '$PATCH_STATUS="OK";' . "\n";
        // $patchCode = str_replace("'", "''", $patchCode);

        $data = [
            'PATCHNAME' => "Update Master File $nameformat วันที่ $day เดือน $month ปี $year $partPatch",
            'PDATE' => Carbon::now(),
            'PLEVEL' => $PLEVEL,
            'PCODE' => 'SHIPPINGNET',
            'MAJOR_VERSION' => 'ALL',
            'PDESC' => $PDESC,
            'POWNER' => $UID,
            'PTYPE' => 'UPDATE MASTER',
            'PAPPROVEDATE' => $PAPPROVEDATE,
            'PATCHCODE' => iconv("utf-8", "tis-620" ,$patchCode),
            'UNINSTALL' => '$DONE=1;',
            'PATCHCODE_SERVER' => '$DONE=1;',
        ];

        DB::table('conf_smartupdate')->insert($data);
    }

    private function readTxt($filePath, $formatData, $ac, $limit = 10000, $noLimit = true)
    {
        // header("Content-Type: text/html; charset=TIS-620");
        ini_set('memory_limit', '-1');
        $sqlPackAll = [];
        $sqlPack = [];
        $count = 0;
        $fileHandle = fopen($filePath, "r");

        while (!feof($fileHandle)) {
           
            $text = fgets($fileHandle);
            try {
                $text = iconv('TIS-620', 'UTF-8', $text);
                
            } catch (\Throwable $th) {
                $encoding = mb_detect_encoding($text, ['UTF-8', 'ISO-8859-1', 'ASCII'], true);
                $text = iconv('Windows-874', 'UTF-8', $text);
          
            }
  
            $X = $Y = $Z = 0;

            $primaryKeyConditions = [];

            foreach ($formatData['primary_key'] as $keyIndex => $primaryKey) {
                $fieldFormat = $formatData['format'][$keyIndex];
                $type = $fieldFormat['TYPE'];

                if (strpos($type, 'DE') !== false) {
                    $type = str_replace('DE', '', $type);

                    $type = (int) $type + 1;
                }

                $type = (int) filter_var($type, FILTER_SANITIZE_NUMBER_INT);
                $fieldValue = mb_substr($text, $Y, $type, 'UTF-8');
                // $fieldValue = substr($text, $Y, $type);
                $Y += $type;

                if ($fieldFormat['FORMAT'] === 'date') {
                    $fieldValue = $this->convertDate($fieldValue);
                }

                $primaryKeyConditions[] = $primaryKey['FILD'] . " = '" . trim($fieldValue) . "'";
            }

            $select2[] = " WHERE " . implode(' AND ', $primaryKeyConditions);
            $select[] = "SELECT * FROM " . $formatData['database'] . " " . " WHERE " . implode(' AND ', $primaryKeyConditions);


            $insertFields = [];
            $insertValues = [];

            foreach ($formatData['format'] as $fieldFormat) {
                $type = $fieldFormat['TYPE'];

                if (strpos($type, 'DE') !== false) {
                    $type = str_replace('DE', '', $type);
                    $type = (int) $type + 1;
                }
                $type = (int) filter_var($type, FILTER_SANITIZE_NUMBER_INT);

                $fieldValue = mb_substr($text, $X, $type, 'UTF-8');
                // $fieldValue = substr($text, $Y, $type);
                $X += $type;
                if ($fieldFormat['FORMAT'] === 'date') {
                    $fieldValue = $this->convertDate($fieldValue);
                }


                $insertFields[] = "`" . $fieldFormat['FILD'] . "`";
                $insertValues[] = "'" . str_replace("'", "''", trim($fieldValue)) . "'";
            }

            $insert[] = "INSERT INTO " . $formatData['database'] . " (" . implode(',', $insertFields) . ") VALUES (" . implode(',', $insertValues) . ")";

            $update[] = $this->generateUpdateQuery($formatData['format'], $text, $Z, $formatData['primary_key']);

            $sqlPack = [
                'insert' => $insert,
                'update' => $update,
                'select' => $select,
                'select2' => $select2,
                'DATABASE' => $formatData['database'],
                'counter' => $count += 1
            ];


            if ($count >= $limit && !$noLimit) {
                $sqlPackAll[] = $sqlPack;
                $count = 0;
                unset($sqlPack);
            }
        }
        fclose($fileHandle);
        $sqlPackAll[] = $sqlPack;
        return $sqlPackAll;
    }
    private function generateUpdateQuery($formatData, $text, &$Z, $primaryKeys)
    {
        $update = "";

        foreach ($formatData as $index => $fieldFormat) {
            $type = $fieldFormat['TYPE'];

            if (strpos($type, 'DE') !== false) {
                $type = str_replace('DE', '', $type);
                $type = (int) $type + 1;
            }
            $type = (int) filter_var($type, FILTER_SANITIZE_NUMBER_INT);
            $fieldValue = mb_substr($text, $Z, $type);
            $Z += $type;

            if ($fieldFormat['FORMAT'] === 'date') {
                $fieldValue = $this->convertDate($fieldValue);
            }

            if (!in_array($fieldFormat['FILD'], array_column($primaryKeys, 'FILD'))) {
                if ($update != "") {
                    $update .= ", ";
                }

                $update .= "`" . $fieldFormat['FILD'] . "` = '" . str_replace("'", "''", trim($fieldValue)) . "'";
            }
        }

        return $update;
    }
    
}
