<?php



declare(strict_types=1);



require_once dirname(__DIR__, 2) . '/wizwizxui-timebot/services/PlanInboundIds.php';

require_once dirname(__DIR__, 2) . '/wizwizxui-timebot/services/XuiV3Config.php';

require_once dirname(__DIR__, 2) . '/wizwizxui-timebot/services/XuiV3ApiClient.php';

require_once dirname(__DIR__, 2) . '/wizwizxui-timebot/services/XuiV3Service.php';



class PlanInboundHelper

{

    public static function ensureSchema(mysqli $conn): void

    {

        PlanInboundIds::ensureSchema($conn);

    }



    /** @return array<string, mixed>|null */

    public static function serverConfigRow(mysqli $conn, int $serverId): ?array

    {

        if ($serverId <= 0) {

            return null;

        }

        $stmt = $conn->prepare('SELECT * FROM server_config WHERE id = ? LIMIT 1');

        $stmt->bind_param('i', $serverId);

        $stmt->execute();

        $row = $stmt->get_result()->fetch_assoc();

        $stmt->close();

        return $row ?: null;

    }



    /** @return array<int, array{id:int,label:string}> */

    public static function listInbounds(mysqli $conn, int $serverId): array

    {

        $row = self::serverConfigRow($conn, $serverId);

        if (!$row || ($row['type'] ?? '') === 'marzban') {

            return [];

        }

        if (!XuiV3Config::isPanelServer($row)) {

            return [];

        }

        try {

            $svc = new XuiV3Service($row);

            $resp = $svc->listInbounds();

            if (!$resp->success || !is_array($resp->obj)) {

                return [];

            }

            $out = [];

            foreach ($resp->obj as $inbound) {

                $id = (int) ($inbound->id ?? 0);

                if ($id <= 0) {

                    continue;

                }

                $remark = trim((string) ($inbound->remark ?? ''));

                $protocol = trim((string) ($inbound->protocol ?? ''));

                $port = (int) ($inbound->port ?? 0);

                $label = '#' . $id;

                if ($remark !== '') {

                    $label .= ' — ' . $remark;

                }

                if ($protocol !== '') {

                    $label .= ' (' . $protocol;

                    if ($port > 0) {

                        $label .= ':' . $port;

                    }

                    $label .= ')';

                }

                $out[] = ['id' => $id, 'label' => $label];

            }

            return $out;

        } catch (Throwable $e) {

            return [];

        }

    }



    /** @return array{ok:bool, ids:int[]} */

    public static function fetchInboundIds(mysqli $conn, int $serverId): array

    {

        $row = self::serverConfigRow($conn, $serverId);

        if (!$row || ($row['type'] ?? '') === 'marzban' || !XuiV3Config::isPanelServer($row)) {

            return ['ok' => false, 'ids' => []];

        }

        try {

            $svc = new XuiV3Service($row);

            $resp = $svc->listInbounds();

            if (!$resp->success || !is_array($resp->obj)) {

                return ['ok' => false, 'ids' => []];

            }

            $ids = [];

            foreach ($resp->obj as $inbound) {

                $id = (int) ($inbound->id ?? 0);

                if ($id > 0) {

                    $ids[] = $id;

                }

            }

            return ['ok' => true, 'ids' => $ids];

        } catch (Throwable $e) {

            return ['ok' => false, 'ids' => []];

        }

    }



    /** @return int[] */

    public static function inboundIdList(mysqli $conn, int $serverId): array

    {

        return self::fetchInboundIds($conn, $serverId)['ids'];

    }



    /** @param int[] $rawIds @return int[] */

    public static function validateInboundIds(mysqli $conn, int $serverId, array $rawIds): array

    {

        $rawIds = array_values(array_unique(array_filter(array_map('intval', $rawIds))));

        if (empty($rawIds)) {

            return [];

        }

        $live = self::inboundIdList($conn, $serverId);

        if (empty($live)) {

            return $rawIds;

        }

        return PlanInboundIds::intersectWithLive($rawIds, $live);

    }



    public static function syncOrphanPlans(mysqli $conn, ?int $serverId = null): int

    {

        self::ensureSchema($conn);

        $fixed = 0;

        if ($serverId !== null && $serverId > 0) {

            return self::syncOrphanPlansForServer($conn, $serverId);

        }

        $res = $conn->query(

            'SELECT DISTINCT server_id FROM server_plans WHERE ' . PlanInboundIds::sqlHasInboundsCondition()

        );

        if (!$res) {

            return 0;

        }

        while ($row = $res->fetch_assoc()) {

            $fixed += self::syncOrphanPlansForServer($conn, (int) $row['server_id']);

        }

        return $fixed;

    }



    private static function syncOrphanPlansForServer(mysqli $conn, int $serverId): int

    {

        $fetch = self::fetchInboundIds($conn, $serverId);

        if (!$fetch['ok']) {

            return 0;

        }

        $valid = $fetch['ids'];

        $stmt = $conn->prepare(

            'SELECT id, inbound_id, inbound_ids FROM server_plans WHERE server_id = ? AND '

            . PlanInboundIds::sqlHasInboundsCondition()

        );

        $stmt->bind_param('i', $serverId);

        $stmt->execute();

        $rows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

        $stmt->close();



        $fixed = 0;

        foreach ($rows as $plan) {

            $planId = (int) $plan['id'];

            $current = PlanInboundIds::parseFromRow($plan);

            $synced = PlanInboundIds::intersectWithLive($current, $valid);

            if ($synced !== $current) {

                PlanInboundIds::updatePlanRow($conn, $planId, $synced);

                $fixed++;

            }

        }

        return $fixed;

    }



    /** @param int[] $selectedIds */

    public static function renderInboundField(

        mysqli $conn,

        int $serverId,

        array $selectedIds,

        string $inputName,

        bool $required = false

    ): string {

        $inbounds = self::listInbounds($conn, $serverId);

        $selectedIds = array_values(array_unique(array_filter(array_map('intval', $selectedIds))));

        $selectedSet = array_flip($selectedIds);

        $req = $required ? ' required' : '';

        $name = htmlspecialchars($inputName, ENT_QUOTES);

        $html = '<div class="m-2"><span class="text-sm text-gray-600 dark:text-gray-300">Inboundها (چند انتخاب — Ctrl+کلیک)</span>';



        if (empty($inbounds)) {

            $html .= '<p class="text-xs text-orange-600 mt-1">⚠ لیست inbound از پنل دریافت نشد.</p>';

            foreach ($selectedIds as $sid) {

                $html .= '<input type="hidden" name="' . $name . '[]" value="' . (int) $sid . '"/>';

            }

            $html .= '<input name="' . $name . '[]" type="number" placeholder="ID inbound" class="mt-1 w-full border rounded px-3 py-2 text-sm"' . $req . '/></div>';

            return $html;

        }



        $size = min(max(count($inbounds), 4), 10);

        $html .= '<select name="' . $name . '[]" multiple size="' . $size . '" class="mt-1 w-full border border-gray-300 rounded px-3 py-2 text-sm dark:bg-gray-700 dark:text-gray-200"' . $req . '>';

        foreach ($inbounds as $ib) {

            $id = (int) $ib['id'];

            $sel = isset($selectedSet[$id]) ? ' selected' : '';

            $html .= '<option value="' . $id . '"' . $sel . '>' . htmlspecialchars($ib['label'], ENT_QUOTES) . '</option>';

        }

        foreach ($selectedIds as $sid) {

            $onPanel = false;

            foreach ($inbounds as $ib) {

                if ((int) $ib['id'] === $sid) {

                    $onPanel = true;

                    break;

                }

            }

            if (!$onPanel) {

                $html .= '<option value="' . $sid . '" selected>⚠ #' . $sid . ' (حذف شده)</option>';

            }

        }

        $html .= '</select>';

        $liveCount = count(array_intersect($selectedIds, array_column($inbounds, 'id')));

        if (!empty($selectedIds)) {

            $html .= '<p class="text-xs text-gray-500 mt-1">انتخاب‌شده: ' . count($selectedIds) . ' — فعال: ' . $liveCount . '</p>';

        }

        $html .= '</div>';

        return $html;

    }



    /** @return int[] */

    public static function parsePostedInboundIds(): array

    {

        $raw = $_POST['inbound_ids_plan'] ?? $_POST['inbound_id_plan'] ?? $_POST['inbound_plan'] ?? [];

        if (!is_array($raw)) {

            $raw = [$raw];

        }

        return array_values(array_unique(array_filter(array_map('intval', $raw))));

    }

}



class WizPanelPostHandler

{

    public static function process(mysqli $conn): void

    {

        PlanInboundHelper::ensureSchema($conn);

        if (isset($_POST['btn_edit']) && !empty($_POST['server_id'])) {

            self::handleServerEdit($conn);

        }

        if (isset($_POST['btn_edit']) && !empty($_POST['plan_id'])) {

            self::handlePlanEdit($conn);

        }

    }



    private static function handleServerEdit(mysqli $conn): void

    {

        $serverId = (int) $_POST['server_id'];

        if ($serverId <= 0) {

            return;

        }

        $ip = (string) ($_POST['ip_server'] ?? '');

        $panelUrl = rtrim((string) ($_POST['panel_url_server'] ?? ''), '/');

        $sni = (string) ($_POST['sni_server'] ?? '');

        $headerType = (string) ($_POST['header_type_server'] ?? '');

        $requestHeader = (string) ($_POST['request_header_server'] ?? '');

        $responseHeader = (string) ($_POST['response_header_server'] ?? '');

        $security = (string) ($_POST['security_server'] ?? '');

        $tlsSettings = (string) ($_POST['tlsSettings_server'] ?? '');

        $username = (string) ($_POST['username_server'] ?? '');

        $password = (string) ($_POST['password_server'] ?? '');

        $apiToken = (string) ($_POST['api_token_server'] ?? '');

        $subBase = (string) ($_POST['subscription_base_url_server'] ?? '');

        $title = (string) ($_POST['title_server'] ?? '');

        $ucount = (int) ($_POST['ucount_server'] ?? 0);

        $remark = (string) ($_POST['remark_server'] ?? '');

        $flag = (string) ($_POST['flag_server'] ?? '');



        $stmt = $conn->prepare('UPDATE server_config SET ip=?, panel_url=?, sni=?, header_type=?, request_header=?, response_header=?, security=?, tlsSettings=?, username=?, password=?, api_token=?, subscription_base_url=? WHERE id = ?');

        $stmt->bind_param('ssssssssssssi', $ip, $panelUrl, $sni, $headerType, $requestHeader, $responseHeader, $security, $tlsSettings, $username, $password, $apiToken, $subBase, $serverId);

        if (!$stmt->execute()) {

            $_SESSION['flash_message'] = 'خطا: ' . $stmt->error;

            $stmt->close();

            header('Location: servers.php');

            exit;

        }

        $stmt->close();

        $stmt = $conn->prepare('UPDATE server_info SET title=?, ucount=?, remark=?, flag=? WHERE id = ?');

        $stmt->bind_param('sissi', $title, $ucount, $remark, $flag, $serverId);

        if (!$stmt->execute()) {

            $_SESSION['flash_message'] = 'خطا: ' . $stmt->error;

            $stmt->close();

            header('Location: servers.php');

            exit;

        }

        $stmt->close();

        PlanInboundHelper::syncOrphanPlans($conn, $serverId);

        editwizwiz();

        header('Location: servers.php');

        exit;

    }



    private static function handlePlanEdit(mysqli $conn): void

    {

        $planId = (int) $_POST['plan_id'];

        $page = (string) ($_POST['plan_edit_page'] ?? 'multiple');

        if ($planId <= 0) {

            return;

        }

        $redirect = $page === 'single' ? 'singleplans.php' : ($page === 'rahgozar' ? 'rahgozar.php' : 'multipleplans.php');



        $title = (string) ($_POST['title_plan'] ?? '');

        $protocol = (string) ($_POST['protocol_plan'] ?? '');

        $type = (string) ($_POST['type_plan'] ?? '');

        $price = (int) ($_POST['price_plan'] ?? 0);

        $days = (int) ($_POST['days_plan'] ?? 0);

        $volume = (int) ($_POST['volume_plan'] ?? 0);

        $limitip = (int) ($_POST['limitip_plan'] ?? 1);

        $catId = (int) ($_POST['name_category_wizwiz'] ?? 0);

        $serverId = (int) ($_POST['name_server_wizwiz'] ?? 0);

        $description = (string) ($_POST['description_plan'] ?? '');



        if ($page === 'single') {

            $inboundIds = [];

        } else {

            $inboundIds = PlanInboundHelper::validateInboundIds($conn, $serverId, PlanInboundHelper::parsePostedInboundIds());

        }

        $inboundIdsJson = PlanInboundIds::encode($inboundIds);

        $inboundIdLegacy = PlanInboundIds::legacyInboundId($inboundIds);



        $acount = array_key_exists('acount_plan', $_POST) ? (int) $_POST['acount_plan']

            : (array_key_exists('count_plan', $_POST) ? (int) $_POST['count_plan'] : null);

        if ($acount === null) {

            $stmtA = $conn->prepare('SELECT acount FROM server_plans WHERE id = ? LIMIT 1');

            $stmtA->bind_param('i', $planId);

            $stmtA->execute();

            $rowA = $stmtA->get_result()->fetch_assoc();

            $stmtA->close();

            $acount = (int) ($rowA['acount'] ?? 0);

        }



        if ($page === 'rahgozar') {

            $customPath = (string) ($_POST['custom_path_plan'] ?? '');

            $customPort = (string) ($_POST['custom_port_plan'] ?? '');

            $customSni = (string) ($_POST['custom_sni_plan'] ?? '');

            $sql = 'UPDATE server_plans SET title=?, protocol=?, type=?, price=?, days=?, volume=?, limitip=?, inbound_id=?, inbound_ids=?, descr=?, catid=?, server_id=?, acount=?, custom_path=?, custom_port=?, custom_sni=? WHERE id = ?';

            $stmt = $conn->prepare($sql);

            $stmt->bind_param('sssiiiiissiiisssi', $title, $protocol, $type, $price, $days, $volume, $limitip, $inboundIdLegacy, $inboundIdsJson, $description, $catId, $serverId, $acount, $customPath, $customPort, $customSni, $planId);

        } else {

            $dest = trim((string) ($_POST['dest_reality'] ?? '')) ?: null;

            $serverNames = trim((string) ($_POST['serverNames_reality'] ?? '')) ?: null;

            $spiderX = trim((string) ($_POST['spiderX_reality'] ?? '')) ?: null;

            $flow = trim((string) ($_POST['flow_reality'] ?? '')) ?: null;

            $sql = 'UPDATE server_plans SET title=?, protocol=?, type=?, price=?, days=?, volume=?, limitip=?, inbound_id=?, inbound_ids=?, descr=?, catid=?, server_id=?, acount=?, dest=?, serverNames=?, spiderX=?, flow=? WHERE id = ?';

            $stmt = $conn->prepare($sql);

            $stmt->bind_param('sssiiiiissiiissssi', $title, $protocol, $type, $price, $days, $volume, $limitip, $inboundIdLegacy, $inboundIdsJson, $description, $catId, $serverId, $acount, $dest, $serverNames, $spiderX, $flow, $planId);

        }

        if (!$stmt->execute()) {

            $_SESSION['flash_message'] = 'خطا: ' . $stmt->error;

            $stmt->close();

            header('Location: ' . $redirect);

            exit;

        }

        $stmt->close();

        editwizwiz();

        header('Location: ' . $redirect);

        exit;

    }

}


