import {Zpl} from "react-native-zpl-code";
import {convertPdfToBitmaps} from "../connectors/PdfToBitmap";
import TcpSocket from "react-native-tcp-socket";
import * as SecureStore from 'expo-secure-store';

class PrintingService {
    private static instance: PrintingService | null = null;
    private readonly apiUrl: string;
    private readonly port: number;

    public static getInstance(port?: number): PrintingService {
        if (!this.instance) {
            this.instance = new PrintingService(port);
        }
        return this.instance;
    }

    private constructor(port = 2282) {
        this.apiUrl = "127.0.0.1";
        this.port = port;
    }

    private async printLabelAsync(pdf: string) {
        const printerIp = await SecureStore.getItemAsync("printerIp");
        if (!printerIp) {
            throw new Error("Printer IP not found in secure store");
        }
        // Fetch the PDF, convert to bitmaps, generate ZPL codes
        const images = await convertPdfToBitmaps(pdf);
        const codes = await this.generateZplCodes(images);

        return new Promise<void>((resolve, reject) => {
            // Create and connect the socket
            const client = TcpSocket.createConnection({host: printerIp, port: 9100}, () => {

                // Write each ZPL chunk
                codes.forEach((code, idx) => {
                    console.log(`Printing ${idx}`);
                    client.write(code);
                });

                client.end();
            });

            // Reject on socket error
            client.on("error", (err) => {
                console.error("Socket error:", err);
                reject(err);
            });

            // Resolve when the socket fully closes
            client.on("close", (hadError) => {
                if (hadError) {
                    // close after an error will have already rejected
                    return;
                }
                console.log("Connection closed");
                resolve();
            });
        });
    }

    private async generateZplCodes(images: string[]) {
        const zplCodes = [];

        for (const image of images) {
            const zplBuilder = new Zpl.Builder();
            zplBuilder.setup({
                size: {
                    heightDots: 320, // 40mm at 203 DPI
                    widthDots: 464,  // 58mm at 203 DPI
                },
                labelHome: {
                    x: 0,
                    y: 0,
                },
                labelTop: 0,
                labeShift: 0,
                orientation: "NORMAL",
                media: {
                    type: "MARK_SENSING",
                    dots: 0,
                },
            });

            zplBuilder.image({
                uri: `data:image/png;base64,${image}`,
                x: 0,
                y: 0,
                width: 464,
                height: 320,
                dither: true,
            });

            const zplCode = await zplBuilder.build();
            zplCodes.push(zplCode);
        }

        return zplCodes;
    }

    private async print(printer: string, type: string, bytes: string): Promise<boolean> {
        try {

            await this.printLabelAsync(bytes);
            return true;
        } catch (error) {
            console.log(error);
            return false;
        }
    }

    public async printPdf(printer: string, pdfBytes: string): Promise<boolean> {
        return this.print(printer, "pdf", pdfBytes);
    }


    public getPrinter(baseMarketplace: number): string {
        if (baseMarketplace == 2) return 'ozon';
        return "wildberries";
        // return "ozon";
    }
}

export default PrintingService;