<?php

namespace App\Http\Controllers\Admin;

use App\Models\VpsServer;
use GuzzleHttp\Client;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Yajra\DataTables\DataTables;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Http;

class MarzbanController extends Controller
{
    public function token(Request $request): JsonResponse
    {
        $request->validate([
            'protocol' => 'required',
            'hostname' => 'required',
            'username' => 'required',
            'password' => 'required',
        ]);
        $url = "{$request->protocol}://{$request->hostname}/api/admin/token";
        $username = $request->username;
        $password = $request->password;
        try {
            // Make the HTTP request
            $response = Http::asForm()
                ->timeout(10)
                ->withoutVerifying()
                ->post($url, [
                    'username' => $username,
                    'password' => $password
                ]);
            $responseBody = $response->json();
            return response()->json($responseBody);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function users(Request $request): JsonResponse
    {
        $request->validate(['id' => $request->id], [
            'id' => 'required|integer|exists:vps,id',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/users";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->get($url);
            $responseBody = $response->json();
            $data = [];
            $now = Carbon::now('Asia/Jakarta');
            foreach ($responseBody['users'] as $value) {
                $expire = $expire_day = '';
                $password_vmess = $value['proxies']['vmess']['id'] ?? '';
                $password_vless = $value['proxies']['vless']['id'] ?? '';
                $password_trojan = $value['proxies']['trojan']['password'] ?? '';
                $password_shadowsocks = $value['proxies']['shadowsocks']['password'] ?? '';
                if (!empty($value['expire'])) {
                    $expire_date = Carbon::createFromTimestamp($value['expire']);
                    $expire = $expire_date->format('d-m-Y h:i:s');
                    $expire_day = '<span class="right badge badge-danger">' . round($expire_date->diffInDays($now, true)) . ' day</span>';
                } else {
                    $expire = $expire_day = '<span class="right badge badge-success">Always ON</span>';
                }

                $action = '<a href="javascript:void(0)" data-toggle="tooltip"
                            data-id="' . $request->id . '"
                            data-username="' . $value['username'] . '"
                            data-passwordvmess="' . $password_vmess . '"
                            data-passwordvless="' . $password_vless . '"
                            data-passwordtrojan="' . $password_trojan . '"
                            data-passwordshadowsocks="' . $password_shadowsocks . '"
                            data-expire="' . $value['expire'] . '"
                            data-datalimit="' . $value['data_limit'] . '"
                            data-datalimitresetstrategy="' . $value['data_limit_reset_strategy'] . '"
                            data-status="' . $value['status'] . '"
                            data-note="' . $value['note'] . '"
                            data-original-title="Edit" class="btn btn-primary btn-xs editData2"><i class="fa fa-edit"></i></a>
                        ';
                $action .= ' <a href="javascript:void(0)" data-toggle="tooltip" data-id="' . $request->id . '" data-username="' . $value['username'] . '" data-original-title="Delete" class="btn btn-danger btn-xs deleteData2">
                                <i class="fa fa-trash"></i>
                            </a>';
                $data[] = [
                    'username' => $value['username'],
                    'proxies' => $value['proxies'],
                    'status' => $value['status'],
                    'used_traffic' => self::formatBytes($value['used_traffic']),
                    'data_limit' => self::formatBytes($value['data_limit']),
                    'data_limit_reset_strategy' => $value['data_limit_reset_strategy'],
                    'expire' => $expire,
                    'expire_day' => $expire_day,
                    'action' => $action,
                ];
            }
            return response()->json([
                'response' => $data,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function usersGetByUsername(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
            'username' => 'required|string|min:4|max:15',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/user/{$request->username}";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->get($url);
            $responseBody = $response->json();
            return response()->json([
                'response' => $responseBody,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function usersStatus(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
            'username' => 'required|string|min:4|max:15',
            'status' => 'required|in:active,disabled',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/user/{$request->username}";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        $param_data = [
            "status" => $request->status,
        ];
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->put($url, $param_data);
            $responseBody = $response->json();
            return response()->json([
                'response' => $responseBody,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function usersUUID(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
            'username' => 'required|string|min:4|max:15',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/user/{$request->username}";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        $uuid = (string) Str::uuid();
        $param_data = [];
        if ($request->account_proxies == 'vmess') {
            $param_data = [
                "proxies" => [
                    "vmess" => [
                        "id" => $uuid
                    ],
                ],
            ];
        } else if ($request->account_proxies == 'vless') {
            $param_data = [
                "proxies" => [
                    "vless" => [
                        "id" => $uuid,
                    ],
                ],
            ];
        } else if ($request->account_proxies == 'trojan') {
            $param_data = [
                "proxies" => [
                    "trojan" => [
                        "password" => $uuid
                    ],
                ],
            ];
        } else if ($request->account_proxies == 'shadowsocks') {
            $param_data = [
                "proxies" => [
                    "shadowsocks" => [
                        "password" => $uuid
                    ],
                ],
            ];
        }
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->put($url, $param_data);
            $responseBody = $response->json();
            return response()->json([
                'response' => $uuid,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function usersAdd(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
            'username' => 'required|string|min:4|max:15',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/user";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        //param input
        $account_proxies = $request->account_proxies;
        $username = $request->username;
        $password = $request->password ?? (string) Str::uuid();
        $expire = $request->expire ?? 0;
        $data_limit = $request->data_limit ?? 0;
        $data_limit_reset_strategy = $request->data_limit_reset_strategy ?? 'no_reset';
        $status = $request->status ?? 'active';
        $note = $request->note;
        $param_data = [
            "username" => $username,
            "expire" => $expire,
            "data_limit" => intval($data_limit),
            "data_limit_reset_strategy" => $data_limit_reset_strategy,
            "status" => $status,
            "note" => $note,
        ];
        $request_marzban  = new Request([
            'id' => $request->id,
        ]);
        $inbounds = $this->inbounds($request_marzban)->getData();
        foreach ($inbounds->response->{$account_proxies} as $key => $value) {
            $param_data["inbounds"][$account_proxies][] = $value->tag;
        }
        if ($account_proxies == 'vmess') {
            $param_data["proxies"] = [
                "vmess" => [
                    "id" => $password
                ],
            ];
        } else if ($account_proxies == 'vless') {
            $param_data["proxies"] = [
                "vless" => [
                    "id" => $password,
                    "flow" => "xtls-rprx-vision"
                ],
            ];
        } else if ($account_proxies == 'trojan') {
            $param_data["proxies"] = [
                "trojan" => [
                    "password" => $password
                ],
            ];
        } else if ($account_proxies == 'shadowsocks') {
            $param_data["proxies"] = [
                "shadowsocks" => [
                    "password" => $password
                ],
                "method" => "aes-128-gcm"
            ];
        }
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->post($url, $param_data);
            $responseBody = $response->json();
            if ($response->successful()) {
                return response()->json([
                    'response' => $responseBody,
                    'metadata' => [
                        'code' => $response->status(),
                        'message' => 'OK',
                    ],
                ], $response->status());
            } else {
                return response()->json([
                    'response' => $responseBody,
                    'metadata' => [
                        'code' => $response->status(),
                        'message' => 'Request failed',
                    ],
                ], $response->status());
            }
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function usersDelete(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
            'username' => 'required|string|min:4|max:15',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/user/{$request->username}";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->delete($url);
            $responseBody = $response->json();
            if ($response->successful()) {
                return response()->json([
                    'response' => $responseBody,
                    'metadata' => [
                        'code' => $response->status(),
                        'message' => 'OK',
                    ],
                ], $response->status());
            } else {
                return response()->json([
                    'response' => $responseBody,
                    'metadata' => [
                        'code' => $response->status(),
                        'message' => 'Request failed',
                    ],
                ], $response->status());
            }
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function system(Request $request): JsonResponse
    {
        $request->validate(['id' => $request->id], [
            'id' => 'required|integer|exists:vps,id',
        ]);

        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/system";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->get($url);
            $responseBody = (object) $response->json();
            $data = $responseBody;
            $data->mem_total = self::formatBytes($data->mem_total);
            $data->mem_used = self::formatBytes($data->mem_used);
            $data->incoming_bandwidth = self::formatBytes($data->incoming_bandwidth);
            $data->outgoing_bandwidth = self::formatBytes($data->outgoing_bandwidth);
            $data->incoming_bandwidth_speed = self::formatBytes($data->incoming_bandwidth_speed);
            $data->outgoing_bandwidth_speed = self::formatBytes($data->outgoing_bandwidth_speed);
            return response()->json([
                'response' => $data,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    public function formatBytes($size, $precision = 2)
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

        $power = $size > 0 ? floor(log($size, 1024)) : 0;

        return number_format($size / (1024 ** $power), $precision, '.', ',') . ' ' . $units[$power];
    }

    public function inbounds(Request $request): JsonResponse
    {
        $request->validate([
            'id' => 'required|integer|exists:vps,id',
        ]);
        $data = VpsServer::find($request->id);
        if (!$data) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 404,
                    'message' => 'VPS server not found or inactive',
                ],
            ], 404);
        }
        $url = "{$data->protocol}://{$data->hostname}/api/inbounds";
        $token_type = $data->token_type;
        $access_token = $data->access_token;
        try {
            // Make the HTTP request
            $response = Http::withHeaders([
                'Authorization' => "{$token_type} {$access_token}",
                'Content-Type' => 'application/json',
            ])
                ->timeout(10)
                ->withoutVerifying()
                ->get($url);
            $responseBody = (object) $response->json();
            return response()->json([
                'response' => $responseBody,
                'metadata' => [
                    'code' => 200,
                    'message' => 'OK',
                ],
            ], 200);
        } catch (\Exception $e) {
            return response()->json([
                'response' => null,
                'metadata' => [
                    'code' => 500,
                    'message' => 'Connection error: ' . $e->getMessage(),
                ],
            ], 500);
        }
    }

    // public function generatePassword(): JsonResponse
    // {
    //     $uuid = (string) Str::uuid();
    //     $password = (string) Str::random(22);
    //     $res = [
    //         'response' => [
    //             'uuid' => $uuid,
    //             'password' => $password,
    //         ],
    //         'metadata' => [
    //             'code' => 200,
    //             'message' => 'OK',
    //         ],
    //     ];
    //     return response()->json($res, 200);
    // }
}
