<?php

namespace App\Http\Controllers\Qrcode;

use App\Helpers\ResponseHelper;
use App\Http\Controllers\Controller;
use App\Models\ApiKey\ApikeyModel;
use App\Models\ErrorLogs\ErrorLogsModel;
use App\Models\InternalUserProfilesModel;
use App\Models\JobQueue;
use App\Models\LinesModel;
use App\Models\ProvinceAndCity\CityModel;
use App\Models\WalletModel;
use App\Http\Service\AESUtilService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use function Laravel\Prompts\form;

class QrcodeController extends Controller
{
    //
    protected $aesUtilService;

    public function __construct(AESUtilService $AESUtilService)
    {
        $this->aesUtilService = $AESUtilService;
    }

    /**
     * @OA\Post(
     *     path="/v1/generateQrcode",
     *     summary="Generate QR Code",
     *     tags={"Qr Docs"},
     *     @OA\Parameter(
     *         name="apikey",
     *         in="header",
     *         required=true,
     *         @OA\Schema(
     *             type="string"
     *         ),
     *         description="API key for the auth application"
     *     ),
     *     @OA\Parameter(
     *         name="Authorization",
     *         in="header",
     *         required=true,
     *         @OA\Schema(
     *             type="string"
     *         ),
     *         description="JWT token to be validated"
     *     ),
     *     security={
     *         {"api_key": {}}
     *     },
     *     @OA\RequestBody(
     *         required=true,
     *         description="Wallet id in requestbody for find user wallet and return your qr encrypted data",
     *         @OA\JsonContent(
     *             required={"wallet_id"},
     *             @OA\Property(property="wallet_id", type="integer", example=123)
     *         )
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Successful operation",
     *         @OA\JsonContent(
     *             @OA\Property(property="status", type="integer", example=1),
     *             @OA\Property(property="message", type="string", example="qr با موفقیت ایجاد شد"),
     *             @OA\Property(property="data", type="object",
     *                 @OA\Property(property="qr", type="string", example="encrypted_qr_code"),
     *                 @OA\Property(property="credit", type="integer", example=1000)
     *             )
     *         )
     *     ),
     *     @OA\Response(
     *         response=400,
     *         description="Bad request"
     *     ),
     *     @OA\Response(
     *         response=401,
     *         description="Unauthorized"
     *     ),
     *     @OA\Response(
     *         response=404,
     *         description="Wallet not found",
     *         @OA\JsonContent(
     *             @OA\Property(property="status", type="integer", example=0),
     *             @OA\Property(property="message", type="string", example="کیف پول کاربر یافت نشد")
     *         )
     *     ),
     *     @OA\Response(
     *         response=500,
     *         description="Internal server error",
     *         @OA\JsonContent(
     *             @OA\Property(property="status", type="integer", example=0),
     *             @OA\Property(property="message", type="string", example="خطا در احراز هویت سرویس")
     *         )
     *     )
     * )
     */
    public function generateQrcode(Request $request)
    {
        $apikey = ApikeyModel::where('apikey', $request->header('apikey'))->first();
        if ($apikey) {
            $wallet = WalletModel::select('city_id', 'credit')->where('id', $request->wallet_id)->where('user_id', Auth::user()->getAuthIdentifier())->first();
            if (!$wallet) {
                return ResponseHelper::unSuccessResponse(0, 'کیف پول کاربر یافت نشد', 404);
            }
            // بازیابی اطلاعات کانکشن برای شهر مربوطه
            $cities = CityModel::select('uc', 'ip_address', 'username', 'password')->where('id', $wallet->city_id)->get();
            if ($cities->isEmpty()) {
                return response()->json(['status' => 0, 'message' => 'uc وجود ندارد'], 404);
            }

            $all_lines = [];
            $user_card_id = null;
            foreach ($cities as $city) {
                // استفاده از کانکشن داینامیک برای انجام کوئری
                $profile = InternalUserProfilesModel::where('user_id', Auth::user()->getAuthIdentifier())->where('city_id', $city->id)->first();
                if (!$user_card_id) {
                    $user_card_id = $profile->card_id;
                }

                if ($user_card_id) {


                    $uc = $profile->uc;

                    $city_id = CityModel::where('uc', (int)$uc)->first();

                    $lines = LinesModel::where('uc', $uc)->get();

                    $lines = $lines->map(function ($line) {
                        $line->Idnumber = (int)$line->Idnumber;
                        $line->Code = (int)$line->Code;
                        $line->Price = (int)$line->Price;
                        return $line;
                    });
                    $lines = $lines->map(function ($line) use ($uc, $city_id) {
                        $line->Idnumber = (int)$line->Idnumber;
                        $line->Code = (int)$line->Code;
                        $line->Price = (int)$line->Price;
                        $line->uc = $uc; // اضافه کردن مقدار uc به هر خط
                        $line->city_id = $city_id->id; // اضافه کردن مقدار uc به هر خط
                        return $line;
                    });

                    $all_lines = array_merge($all_lines, $lines->toArray());
                }
            }

            if (!$user_card_id) {
                return ResponseHelper::systemErrorResponse(0, "شماره تماس کاربر در سیستم یافت نشد", [], 200, 890);
            }

            return response()->json(['status' => 1, 'message' => 'qr با موفقیت ساخته شد', 'data' => (object)['qr' => (object)['uc' => $city->uc, 'card_id' => $user_card_id], 'lines' => $all_lines]]);

        } else {
            ErrorLogsModel::insert([
                'type' => 1,
                'description' => "generateQrcode | apikey auth unsuccessfully!",
                'ip_address' => $request->ip()
            ]);
            return response()->json(['status' => 0, 'message' => "خطا در احراز هویت سرویس", 'code' => 500], 200);
        }

    }


    public function getLatLang(Request $request)
    {
        // Retrieve the geographic data from the database

        if (!isset($request->code)) {
            return response()->json(['status' => 0, 'message' => 'کد لاین الزامیست']);
        }

        // Set up dynamic database connection parameters
        $host = "188.136.191.136";
        $port = '1433'; // Default SQL Server port
        $database = 'Ecity'; // Database name
        $username = "sa";
        $password = "bsh78753";

        // Create a dynamic connection name
        $dynamicConnectionName = 'dynamic_sqlsrv_' . 222;

        // Purge any existing connection with the same name
        DB::purge($dynamicConnectionName);

        // Configure the dynamic connection
        config([
            "database.connections.$dynamicConnectionName" => [
                'driver' => 'sqlsrv',
                'host' => $host,
                'port' => $port,
                'database' => $database,
                'username' => $username,
                'password' => $password,
                'charset' => 'utf8',
                'prefix' => '',
                'prefix_indexes' => true,
                'encrypt' => 'no',
                'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'true'),
            ],
        ]);
        $latlang = DB::connection($dynamicConnectionName)
            ->table('PLineT')
            ->select(DB::raw('geo.ToString() as s'))
            ->where('Code', $request->code)
            ->first();

// If no data is found, set an empty array as the default value
        if (!$latlang) {
            return response()->json(['status' => 0, 'message' => 'لیست یافت نشد'], 404);
        }

// Extract the coordinates from the LINESTRING format
        $coordinates = str_replace(['LINESTRING (', ')'], '', $latlang->s);

// Split the coordinates into an array
        $coordinatesArray = explode(', ', $coordinates);

// Reformat the coordinates into an array of objects
        $formattedCoordinates = array_map(function ($coordinate) {
            list($lat, $long) = explode(' ', $coordinate);
            return [
                "lat" => $lat,
                "long" => $long
            ];
        }, $coordinatesArray);

// Return the response in JSON format
        return response()->json([
            'status' => 1,
            'message' => 'موقعیت جغرافیایی دریافت شد',
            'data' => $formattedCoordinates
        ]);
    }


    public function dsda()
    {
        // Clear existing lines
        LinesModel::truncate();

        // Fetch all cities except the local one
        $cities = CityModel::where('ip_address', '!=', '127.0.0.1')->get();

        foreach ($cities as $city) {
            // Setup dynamic database connection
            $this->setupDatabaseConnection($city);

            try {
                // Fetch lines from the remote database
                $lines = DB::connection($this->getDynamicConnectionName($city->id))
                    ->table('PLineT')
                    ->select('Idnumber', 'Code', 'Title', DB::raw('ISNULL(Price, 0) as Price'))
                    ->get();

                return $lines;
                foreach ($lines as $line) {
                    $locations = $this->fetchLineLocations($city, $line->Code);

                    if ($locations) {
                        // Ensure unique locations

                        // Insert or update the line record
                        LinesModel::updateOrCreate(
                            ['Code' => $line->Code, 'city_id' => $city->id],
                            [
                                'Idnumber' => $line->Idnumber,
                                'Title' => $line->Title,
                                'Price' => $line->Price,
                                "uc" => $city->uc,
                                'locations' => json_encode($locations),
                            ]
                        );
                    }
                }
            } catch (\Exception $e) {
                // Log the error and store information about the failed connection
                $this->logJobFailure($city, $e->getMessage());
            }
        }
    }

    private function setupDatabaseConnection($city)
    {
        $connectionName = $this->getDynamicConnectionName($city->id);

        // Purge any existing connection with the same name
        DB::purge($connectionName);

        // Configure the dynamic connection
        config([
            "database.connections.$connectionName" => [
                'driver' => 'sqlsrv',
                'host' => $city->ip_address,
                'port' => '1433',
                'database' => 'Ecity',
                'username' => $city->username,
                'password' => $city->password,
                'charset' => 'utf8',
                'prefix' => '',
                'prefix_indexes' => true,
                'encrypt' => 'no',
                'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'true'),
            ],
        ]);
    }

    private function getDynamicConnectionName($cityId)
    {
        return 'dynamic_sqlsrv_' . $cityId;
    }

    private function fetchLineLocations($city, $lineCode)
    {
        $connectionName = $this->getDynamicConnectionName($city->id);

        $latlang = DB::connection($connectionName)
            ->table('PLineT')
            ->select(DB::raw('geo.ToString() as s'))
            ->where('Code', $lineCode)
            ->first();

        if (!$latlang) {
            return null;
        }

        // Extract and parse coordinates
        $coordinates = str_replace(['LINESTRING (', ')'], '', $latlang->s);
        $points = explode(', ', $coordinates);
        $locations = [];

        foreach ($points as $point) {
            list($lat, $long) = explode(' ', $point);

            if (is_numeric($lat) && is_numeric($long)) {
                $locations[] = ['lat' => (float)$lat, 'long' => (float)$long];
            }
        }

        return $locations;
    }

    private function logJobFailure($city, $errorMessage)
    {
        JobQueue::create([
            'job_type' => 'SAVE_LINES',
            'ip_address' => $city->ip_address,
            'username' => $city->username,
            'password' => $city->password,
            'job_status' => 'PENDING',
            'json' => json_encode(['city_id' => $city->id, 'error' => $errorMessage]),
        ]);
    }
}
