import { Request, RouteOptionsResponseSchema } from "@hapi/hapi"
import { htmlToText } from 'html-to-text';
import { JoiBuilder } from "../utils/joiSchemaBuilder"
import * as Fs from 'file-system';
import { AccountService } from "../api/services/account.service";
import { AppError } from "./errors"
import { SettingService } from "../api/services/setting.service";
import AppCache from "../utils/appCache";
import * as firebase from "firebase-admin";
import firebaseKey from "../../firebase.json"
import * as crypto from "crypto-js";
import { AttachmentService } from "../api/services/attachment.service";
import * as csv from 'fast-csv';
import Axios, { AxiosRequestConfig, Method } from "axios";
// Initialize the Firebase Admin SDK
firebase.initializeApp({
    credential: firebase.credential.cert(firebaseKey as firebase.ServiceAccount),
});
export class Common {
    static routeHeaders = (authorized?: 'authorized' | 'optionalauthorized' | 'authorizedLatLong' | 'apiheader' | null): RouteOptionsResponseSchema => {
        let headerSchema: SchemaDefinition = {
            language: {
                type: 'string',
                example: 'en',
                description: "PREFERRED_LANGUAGE",
                required: false,
                defaultValue: 'en'
            },
            timezone: {
                type: 'string',
                example: 'UTC',
                description: "PREFERRED_TIMEZONE",
                required: false,
                defaultValue: 'UTC'
            },
            account: {
                type: 'string',
                example: 'account-key',
                description: "ACCOUNT_KEY",
                required: false,
                defaultValue: process.env.DEFAULT_ACCOUNT_KEY
            },
            connection: {
                type: 'string',
                example: 'keep-alive',
                description: "CONNECTION_PREFERENCE",
                required: false,
                defaultValue: 'keep-alive'
            }
        }
        if (authorized === 'authorized') {
            headerSchema = {
                ...headerSchema, ...{
                    authorization: {
                        type: 'string',
                        example: 'eyJhbGciOiJIUzI1NiIsInR...',
                        description: "AUTHORIZATION_TOKEN",
                        required: true
                    }
                }
            }
        } else if (authorized === 'optionalauthorized') {
            headerSchema = {
                ...headerSchema, ...{
                    authorization: {
                        type: 'string',
                        example: 'eyJhbGciOiJIUzI1NiIsInR...',
                        description: "AUTHORIZATION_TOKEN",
                        required: false
                    }
                }
            }
        }
        let globalHeaders = JoiBuilder.buildJoiSchema(headerSchema, { allowUnknown: true });
        return globalHeaders;
    }

    private static FailureError = (err: any, request: any) => {
        const updatedError = err;
        updatedError.output.payload.message = [];
        const customMessages: Record<string, string> = {};

        if (err.isJoi && Array.isArray(err.details) && err.details.length > 0) {
            err.details.forEach((error: { context?: { label?: any }; message?: any, type: string }, index: number) => {
                if (error.type == 'object.unknown') {
                    err.details[index].message = request.i18n.__('UNKNOWN_KEYS_ARE_NOT_ALLOWED');
                }
                // else if (error.type == 'object.base') {
                //     err.details[index].message = request.i18n.__('INVALID_REQUEST_FORMAT');
                // } 
                else {
                    err.details[index].message = request.i18n.__(err.details[index].message);
                }
                const label = error.context?.label || '';
                const errorMessage = error.message || '';
                customMessages[label] = request.i18n.__(errorMessage);
            });
        }
        delete updatedError.output.payload.validation;
        updatedError.output.payload.error = request.i18n.__('BAD_REQUEST');
        updatedError.output.payload.message = request.i18n.__('ERROR_WHILE_VALIDATING_REQUEST');
        updatedError.output.payload.errors = customMessages;
        return updatedError;
    };

    static failover = async (request: any, h: any, error: any) => {
        return this.FailureError(error, request);
    }

    // Generate slug for a text
    static slugify = (text: string, append: string | null = null) => {
        let slug = text.toString().normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().trim().replace(/\s+/g, '-').replace(/[^\w-]+/g, '').replace(/--+/g, '-');
        if (append) {
            slug = slug + '-' + append;
        }
        return slug;
    }

    static limitHtmlWords = (html: string, limit: number): string => {
        if (!html) return "";
        let count = 0;
        const tokens = String(html).match(/<[^>]+>|[^<>\s]+|\s+/g) || [];
        const result = [];
        const stack: string[] = [];

        for (const token of tokens) {
            if (token.startsWith("<")) {
                result.push(token);
                if (token.startsWith("</")) {
                    stack.pop();
                } else if (!token.endsWith("/>") && !token.match(/<(br|hr|img|input|link|meta|area|base|col|command|embed|keygen|param|source|track|wbr)[^>]*>/i)) {
                    const match = token.match(/<([a-zA-Z0-9]+)/);
                    if (match) stack.push(match[1]);
                }
            } else if (token.trim() === "") {
                result.push(token);
            } else {
                count++;
                if (count > limit) break;
                result.push(token);
            }
        }

        // Close remaining tags in reverse order
        while (stack.length > 0) {
            const tag = stack.pop();
            result.push(`</${tag}>`);
        }

        if (count > limit) {
            result.push("...");
        }

        return result.join("");
    }

    static convertHtmlToText = async (html: string): Promise<string> => {
        let text = '';
        if (html != '')
            text = htmlToText(html, {
                wordwrap: false,
                selectors: [
                    {
                        selector: 'a',
                        format: 'inline',
                        options: {
                            // @ts-ignore
                            formatFn: (elem, walk, builder) => {
                                const text = walk(elem.children, builder);
                                const href = elem.attribs.href || '';
                                if (href && !href.includes(text)) {
                                    builder.addInline(`${text} (${href})`, {});
                                } else {
                                    builder.addInline(text, {});
                                }
                            },
                        },
                    },
                    {
                        selector: 'img',
                        format: 'inline',
                        options: {
                            // @ts-ignore
                            formatFn: (elem, walk, builder) => {
                                const alt = elem.attribs.alt?.trim();
                                const src = elem.attribs.src?.trim();
                                const fallback = src?.split('/').pop();
                                const text = `[Image: ${alt || fallback || 'image'}]`;
                                builder.addInline(text, {});
                            },
                        },
                    },
                ],
            });
        return text;
    };

    static generateCode = (Requestedlength: number, type: string = 'string') => {
        const char = type == 'number' ? '1234567890' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; //Random Generate Every Time From This Given Char
        const length = (typeof Requestedlength !== 'undefined' && !isNaN(Requestedlength) && Requestedlength > 0) ? Requestedlength : 6;
        let randomvalue = '';
        for (let i = 0; i < length; i++) {
            const value = Math.floor(Math.random() * char.length);
            randomvalue += char.substring(value, value + 1).toUpperCase();
        }
        return randomvalue;
    }

    static getTotalPages = (records: number, perpage: number): number => {
        let totalPages = Math.ceil(records / perpage);
        return totalPages;
    };

    static prepareSearchText = (searchText: string): searchText => {
        // Split the search text into words
        const words = searchText.split(/\s+/);
        // Initialize two arrays to hold the processed words
        let alphaWords: string[] = [];
        let specialWords: string[] = [];
        // Loop through each word and separate it based on whether it contains special characters
        words.forEach(word => {
            // Check if the word contains special characters (e.g., '@', '.', etc.)
            if (/[^a-zA-Z0-9]/.test(word)) {
                // If it contains special characters, wrap it in quotes
                specialWords.push(`"${word}"`);
            } else {
                // If it's a plain word (alphabetical), replace spaces with '*'
                alphaWords.push(word.replace(/ /g, '*')); // In case there's any internal spaces (though unlikely)
            }
        });
        // Convert the arrays into strings
        const alphaString = alphaWords.join('*');  // Replace spaces with '*'
        const specialString = specialWords.join(' ');  // Keep words with special chars as is
        return { alphaString: alphaString, specialString: specialString }
    }

    static fetchShortCodes = (str: string): string[] => {
        const matches = str.match(/{{(\w+)}}/g);
        let matchArray: string[] = [];
        if (matches?.length)
            matchArray = matches.map(match => match.replace(/{{|}}/g, ''));
        return matchArray;
    }

    static readHTMLFile = async (path: string): Promise<string> => {
        let html = await Fs.readFileSync(path, { encoding: "utf-8" });
        return html;
    };

    static getPrevNext = <T extends string | number>(arr: T[], target?: T): { prev: T | null; next: T | null } => {
        // If no target provided, return first item as next
        if (target === undefined || target === null || target === ("" as T)) {
            return {
                prev: null,
                next: arr.length > 0 ? arr[0] : null
            };
        }
        const index = arr.indexOf(target);
        if (index === -1) {
            return { prev: null, next: null }; // target not found
        }
        const prev = index > 0 ? arr[index - 1] : null;
        const next = index < arr.length - 1 ? arr[index + 1] : null;
        return { prev, next };
    };

    static hasScope = (userAuth: any, arr: string[]) => {
        return (userAuth.scope || []).some((scopeValue: string) => arr.includes(scopeValue));
    }


    static arrayToObject = (items: SettingData[]): Record<string, string | number | boolean | Text> => {
        return items.reduce((acc, { code, value }) => {
            acc[code] = value;
            return acc;
        }, {} as Record<string, string | number | boolean | Text>);
    }

    static initializeAppCache = async (force: boolean = false) => {
        try {
            let accountCache = AppCache.get("accounts");
            if (!accountCache || force) {
                let accountService = new AccountService();
                const listRequest: AccountListAllRequestObject = { searchText: null, sortBy: 'id', sortDirection: "asc" };
                const getAllAccountsInput: AccountGetAllAccountsServiceInput = { listRequest };
                let getAllAccounts = await accountService.getAllAccounts(getAllAccountsInput);
                AppCache.set("accounts", getAllAccounts);
                accountCache = AppCache.get('accounts') as unknown as AccountObjectSummaryInteface[];
                for (let account of getAllAccounts) {
                    let settingService = new SettingService()
                    let accountSettings = await settingService.getAccountSettings(account.id);
                    AppCache.set("setting_" + account.id, this.arrayToObject(accountSettings));
                }
            }
            return;
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(403, 'INVALID_ACCESS', {});
        }
    }

    static getVariables = async (request: Request) => {
        try {
            let userAccountId: number | null;
            const accountToUse = request.headers.host;
            let accountCache = AppCache.get('accounts') as unknown as AccountObjectSummaryInteface[];
            let id = accountCache.find(account => account.name === accountToUse)?.id;
            
            // Fallback for local network or ngrok testing
            if (!id && accountCache.length > 0) {
                id = accountCache[0].id;
            }

            if (id) {
                userAccountId = id;
                const scope = (request.auth?.isAuthenticated && request.auth.credentials.scope) ? request.auth.credentials.scope : null;
                const userId = request.auth?.isAuthenticated ? (request.auth.credentials as unknown as AuthData).userData.userId : null;
                const accountId = request.auth?.isAuthenticated ? (request.auth.credentials as unknown as AuthData).userData.accountId : userAccountId;
                const language: string = (request.headers?.language || process.env.DEFAULT_LANGUAGE_CODE || 'en') as string;
                let isPremium = false;
                if (request.auth?.isAuthenticated && userId) {
                    const Models = require('../api/models').default;
                    const userSetting = await Models.UserSetting.findOne({ where: { userId }, attributes: ['isPremium'] });
                    isPremium = userSetting ? userSetting.isPremium : (request.auth.credentials as unknown as AuthData).userData.isPremium;
                }
                const config: userConfig = {
                    isPremium: isPremium,
                    timeZone: request.headers.timezone
                }
                return {
                    scope: scope,
                    userId: userId,
                    accountId: accountId,
                    language: language,
                    config: config
                }
            } else {
                throw new AppError(403, 'INVALID_ACCESS', {});
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(403, 'INVALID_ACCESS', {});
        }
    }

    static flattenObject = (obj: any, prefix: string = ''): any => {
        let result: any = {};
        for (const key in obj) {
            if (obj.hasOwnProperty(key)) {
                const newKey = prefix ? `${prefix}${key.charAt(0).toUpperCase() + key.slice(1)}` : key;
                if (typeof obj[key] === 'object' && obj[key] !== null) {
                    // Recursively flatten the nested object
                    Object.assign(result, this.flattenObject(obj[key], newKey));
                } else {
                    // Assign the value directly if it's not an object
                    result[newKey] = obj[key];
                }
            }
        }
        return result;
    }

    static splitDateTime = (utcString: Date): { date: string, time: Time } => {
        try {
            const dateObj = new Date(utcString);
            if (isNaN(dateObj.getTime())) {
                throw new Error("Invalid date string");
            }
            const year = dateObj.getUTCFullYear();
            const month = String(dateObj.getUTCMonth() + 1).padStart(2, "0");
            const day = String(dateObj.getUTCDate()).padStart(2, "0");
            const hours = String(dateObj.getUTCHours()).padStart(2, "0");
            const minutes = String(dateObj.getUTCMinutes()).padStart(2, "0");
            const seconds = String(dateObj.getUTCSeconds()).padStart(2, "0");
            return {
                date: `${year}-${month}-${day}`,   // YYYY-MM-DD
                time: `${hours}:${minutes}:${seconds}` as Time // HH:mm:ss
            };
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(400, 'ERROR_WHILE_PARSING_DATA', {});
        }
    }

    static validateEmail = async (email: string): Promise<boolean> => {
        const url = `http://apilayer.net/api/check?access_key=${process.env.MAILBOXLAYER_API_KEY!}&email=${encodeURIComponent(email)}&smtp=1&format=1`;
        try {
            const res = await fetch(url);
            const data = await res.json();
            if (data.success === false) {
                throw new Error(data.error?.info || "API error");
            }
            return data.score > 0.7 ? true : false
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(400, 'ERROR_WHILE_VERIFYING_EMAIL', {});
        }
    }
    // 

    static htmlToText(html: string) {
        return html
            .replace(/<br\s*\/?>/gi, "\n")     // Replace <br> or <br/> 
            .replace(/<\/p>/gi, "\n")          // Replace </p> with newline
            .replace(/<p[^>]*>/gi, "")         // Remove <p> opening tag
            .replace(/&nbsp;/gi, " ")          // Replace HTML space
            .replace(/<[^>]+>/g, "")           // Remove remaining tags
            .trim();
    }

    // Send FCM notification to user sevice
    static sendFcmNotification = async (token: string | null, topic: string | null, notification: { title: string, body: string }, message: { title: string, body: string }, data: Record<string, any>, silent: boolean = false) => {
        try {
            let payload: any;
            if (silent) {
                payload = {
                    notification: notification,
                    data: message,
                    token: token,
                    android: {
                        priority: 'high',  // Required to wake up the app in the background
                    },
                    apns: {
                        payload: {
                            aps: {
                                'content-available': 1  // Required to wake up iOS app in the background
                            },
                        },
                        headers: {
                            'apns-priority': '5'  // Ensures the notification is delivered immediately
                        }
                    }
                };

            } else {
                payload = {
                    notification: notification,
                    data: data,
                    token: token,
                    android: {
                        notification: {
                            sound: 'default',
                        },
                    },
                    apns: {
                        payload: {
                            aps: {
                                sound: 'default',
                            },
                        },
                    },
                };
            }
            if (token) {
                const response = await firebase.messaging().send(payload);
                return response;
            } else {
                payload = { ...payload, topic: topic, token: undefined }
                const response = await firebase.messaging().send(payload);
                return response;
            }
        } catch (err) {
            return false;
        }
    }

    // create whatsapp template
    static createWhatsAppTemplate = async (templateName: string, category: string, language: string, templateContent: string, examples: string[] = []) => {
        try {
            let payload = {
                integrated_number: process.env.WHATSAPP_SENDER_MOBILE_NO,
                template_name: templateName,
                language: language,
                category: category,
                components: [{
                    type: "BODY",
                    text: templateContent,
                    example: {
                        body_text: [
                            examples
                        ]
                    }
                }]
            }
            const config = {
                url: process.env.WHATSAPP_CREATE_TEMPLATE,
                method: 'post',
                data: payload,
                headers: {
                    "Content-Type": "application/json",
                    authkey: process.env.WHATSAPP_AUTH_KEY!
                },
                maxRedirects: 5
            }
            console.log(" ================== check ==========")
            const response = await Axios.request(config);
            console.log("get", response.data);
            return response.data;
        } catch (err) {
            console.log(err, " =========== err check")
            return false;
        }
    }

    static checkWhatsAppTemplateStatus = async (templateName: string) => {
        try {
            const config = {
                url: `${process.env.WHATSAPP_VERIFY_TEMPLATE}${process.env.WHATSAPP_SENDER_MOBILE_NO}`,
                method: 'GET',
                params: {
                    template_name: templateName
                },
                headers: {
                    "Content-Type": "application/json",
                    authkey: process.env.WHATSAPP_AUTH_KEY!
                },
                maxRedirects: 5
            }
            const response = await Axios.request(config);
            return response.data;
        } catch (err) {
            console.log(err)
            return false;
        }
    }

    // Send whatsapp messages
    static sendWhatsApp = async (templateName: string, receiverData: WhatsAppReceiverItem[], namespace: string) => {
        try {
            let payload = {
                integrated_number: process.env.WHATSAPP_SENDER_MOBILE_NO,
                content_type: "template",
                payload: {
                    messaging_product: "whatsapp",
                    type: "template",
                    template: {
                        name: templateName,
                        language: {
                            code: "en_GB"
                        },
                        namespace: namespace,
                        to_and_components: receiverData
                    }
                }
            }
            const config = {
                url: process.env.WHATSAPP_SEND_BULK,
                method: 'post',
                data: payload,
                headers: {
                    "Content-Type": "application/json",
                    authkey: process.env.WHATSAPP_AUTH_KEY!
                }
            }
            const response = await Axios.request(config);
            return response.data;
        } catch (err) {
            console.log(err)
            return false;
        }
    }

    // Common replacer function
    static applyReplacements = (text: Text | string | null | undefined, replacements: Record<string, any>): string | null | undefined => {
        if (!text) return text;
        return String(text).replace(/{{(.*?)}}/g, (_, key) => {
            const value = replacements[key.trim()];
            return value !== undefined ? String(value) : `{{${key}}}`;
        });
    };

    static descrptRequest = (text: string) => {
        try {
            if (text) {
                let decrypted = crypto.AES.decrypt(text, process.env.REQUEST_ENCRYPTION_KEY!).toString(crypto.enc.Utf8)
                return decrypted;
            } else {
                return ""
            }
        } catch (err) {
            return "";
        }
    }

    static encryptResponse = (text: string) => {
        let encrypted = crypto.AES.encrypt(text, process.env.RESPONSE_ENCRYPTION_KEY!).toString();
        return encrypted;
    }

    static parseCSVFile = async (streamData: NodeJS.ReadableStream, requiredHeaders: string[]): Promise<any[]> => {
        const results: any[] = [];
        return new Promise<any[]>((resolve, reject) => {
            let headersChecked = false;
            streamData
                // .pipe(csv.parse({ headers: true, skip_empty_lines: true }))
                .pipe(csv.parse({ headers: true }))
                .on("error", (err: any) => reject(err))
                .on("headers", (headers: string[]) => {
                    headersChecked = true;
                    const missing = requiredHeaders.filter(h => !headers.includes(h));
                    if (missing.length > 0) {
                        return reject(new AppError(400, `CSV missing required headers: ${missing.join(", ")}`));
                    }
                })
                .on("data", (row: any) => results.push(row))
                .on("end", () => {
                    if (!headersChecked) {
                        return reject(new AppError(400, "CSV headers could not be read"));
                    }
                    resolve(results);
                });
        });
    };

    static interleaveEveryNth(normalArr: any[], premiumArr: any[], everyN: number) {
        const result = [];
        let normalIndex = 0;
        let premiumIndex = 0;
        for (let i = 0; normalIndex < normalArr.length || premiumIndex < premiumArr.length; i++) {
            if ((i + 1) % everyN === 0 && premiumIndex < premiumArr.length) {
                // insert premium at every Nth position
                result.push(premiumArr[premiumIndex]);
                premiumIndex++;
            } else if (normalIndex < normalArr.length) {
                // otherwise insert normal
                result.push(normalArr[normalIndex]);
                normalIndex++;
            } else if (premiumIndex < premiumArr.length) {
                // if normal is exhausted, but premium left
                result.push(premiumArr[premiumIndex]);
                premiumIndex++;
            }
        }
        return result;
    }

    static sendOTP = async (mobile: string, platform: string) => {
        try {
            mobile = mobile.trim().replace(/\+/g, "");
            switch (platform) {
                case 'msg91':
                default:
                    const params: any = {
                        template_id: process.env.MSG91_OTP_TEMPLET_ID,
                        mobile,
                        otp_length: 4,
                        otp_expiry: 3,
                        authkey: process.env.MSG91_AUTH_KEY,
                    }
                    if (mobile === process.env.MASTER_MOBILE) {
                        params["otp"] = process.env.MASTER_CODE
                    }
                    const config = {
                        url: process.env.MSG91_SEND_MSG,
                        method: 'get',
                        params: params
                    }
                    try {
                        const response = await Axios.request(config);
                        if (response && response.status === 200) {
                            return response.data.request_id ? response.data.request_id : response.data.message;
                        } else {
                            return false;
                        }
                    } catch (err) {
                        console.log("error")
                    }
                    break;
            }
        } catch (err) {
            console.log('Error in sending OTP', err);
            return false;
        }
    }

    // verify OTP sent from sendOTP method 
    static verifyMobileOTP = async (mobile: string, otp: string, platform: string) => {
        try {
            mobile = mobile.trim().replace(/\+/g, "");
            switch (platform) {
                case 'msg91':
                default:
                    const config = {
                        url: process.env.MSG91_VERIFY_OTP,
                        method: 'get',
                        params: {
                            otp,
                            mobile,
                            authkey: process.env.MSG91_AUTH_KEY
                        }
                    }
                    const response = await Axios.request(config);
                    if (response.status === 200 && response.data.type != 'error') {
                        return true;
                    } else {
                        return false;
                    }
            }
        } catch (err) {
            console.log('Error while verifying OTP', err);
            return false;
        }
    }

    static resendOTP = async (mobile: string, platform: string, type: string) => {
        try {
            switch (platform) {
                case 'msg91':
                default:
                    const params: any = {
                        retrytype: type,
                        mobile,
                        otp_length: 4,
                        otp_expiry: 3,
                        authkey: process.env.MSG91_AUTH_KEY
                    }
                    if (mobile === process.env.MASTER_MOBILE) {
                        params["otp"] = process.env.MASTER_CODE
                    }
                    const config = {
                        url: process.env.MSG91_RESEND_MSG,
                        method: 'get',
                        params: params
                    }
                    const response = await Axios.request(config);
                    if (response.status == 200) {
                        return true;
                    } else {
                        return false;
                    }
                    break;
            }
        } catch (err) {
            console.log('Error while resending OTP', err);
            return false;
        }
    }

    static validateMobile = async (countryCode: string, mobile: string, platform: string) => {
        try {
            countryCode = countryCode.trim().replace(/\+/g, "");
            switch (platform) {
                case 'msg91':
                default:
                    const params = {
                        authkey: process.env.MSG91_AUTH_KEY
                    }
                    const config = {
                        url: process.env.MSG91_LOOKUP + `?country_code=${countryCode}&mobile=${mobile}`,
                        method: 'get',
                        params: params
                    }
                    const response = await Axios.request(config);
                    if (response.status == 200) {
                        return true;
                    } else {
                        return false;
                    }
            }
        } catch (err) {
            console.log('Error while valiating mobile', err);
            return false;
        }
    }

    static EmitEvent = async (roomName: string | null, eventName: string, payload: any) => {
        (globalThis as any).io?.emit('socketServerEvent', { roomName: roomName, eventName: eventName, payload: payload })
        return true;
    }

    static async executeRequest(
        url: string,
        type: Method,
        args?: {
            params?: any;   // for query params (GET)
            data?: any;     // for body (POST/PUT)
            headers?: any;  // custom headers
        }
    ) {
        try {
            const config: AxiosRequestConfig = {
                url,
                method: type,
                headers: {
                    "Content-Type": "application/json",
                    ...(args?.headers || {})
                },
                params: args?.params,
                data: args?.data
            };
            const response = await Axios(config);
            return response.data;
        } catch (error: any) {
            console.error("Axios Error:", error?.response?.data || error.message);
            throw error?.response?.data || { message: "Unknown error" };
        }
    }
}
