import { WebPlugin } from '@capacitor/core';
import QRCode from 'qrcode';
import QrScanner from 'qr-scanner';
import { BrowserMultiFormatReader, DecodeHintType, BarcodeFormat as ZXingFormat } from '@zxing/library';
import JsBarcode from 'jsbarcode';
import { QRType, BarcodeFormat } from './definitions';
export class QRCodeStudioWeb extends WebPlugin {
    constructor() {
        super(...arguments);
        this.scanner = null;
        this.barcodeReader = null;
        this.videoElement = null;
        this.scanListeners = [];
        this.errorListeners = [];
        this.torchListeners = [];
        this.history = [];
        this.currentStream = null;
        // private torchEnabled: boolean = false; // Not used in web implementation
        this.scanInterval = null;
    }
    async checkPermissions() {
        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
            return { camera: 'denied' };
        }
        try {
            const permissionStatus = await navigator.permissions.query({ name: 'camera' });
            return {
                camera: permissionStatus.state === 'granted' ? 'granted' :
                    permissionStatus.state === 'denied' ? 'denied' : 'prompt'
            };
        }
        catch (_a) {
            // Fallback for browsers that don't support permissions API
            try {
                const stream = await navigator.mediaDevices.getUserMedia({ video: true });
                stream.getTracks().forEach(track => track.stop());
                return { camera: 'granted' };
            }
            catch (_b) {
                return { camera: 'prompt' };
            }
        }
    }
    async requestPermissions() {
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ video: true });
            stream.getTracks().forEach(track => track.stop());
            return { camera: 'granted' };
        }
        catch (_a) {
            return { camera: 'denied' };
        }
    }
    async startScan(options) {
        try {
            // Create video element if not exists
            if (!this.videoElement) {
                this.videoElement = document.createElement('video');
                // Apply custom video styles or defaults
                const videoStyle = (options === null || options === void 0 ? void 0 : options.videoStyle) || {};
                this.videoElement.style.position = videoStyle.position || 'fixed';
                this.videoElement.style.top = videoStyle.top || '0';
                this.videoElement.style.left = videoStyle.left || '0';
                this.videoElement.style.width = videoStyle.width || '100%';
                this.videoElement.style.height = videoStyle.height || '100%';
                this.videoElement.style.objectFit = videoStyle.objectFit || 'cover';
                this.videoElement.style.zIndex = videoStyle.zIndex || '999999';
                document.body.appendChild(this.videoElement);
            }
            // Determine which formats to scan
            const requestedFormats = (options === null || options === void 0 ? void 0 : options.targetedFormats) || (options === null || options === void 0 ? void 0 : options.formats) || Object.values(BarcodeFormat);
            const hasOnlyQR = requestedFormats.length === 1 && requestedFormats[0] === BarcodeFormat.QR_CODE;
            if (hasOnlyQR) {
                // Use QrScanner for QR-only scanning (better performance)
                this.scanner = new QrScanner(this.videoElement, (result) => {
                    const scanResult = {
                        content: result.data,
                        format: BarcodeFormat.QR_CODE,
                        timestamp: Date.now(),
                        type: this.detectQRType(result.data),
                        parsedData: this.parseQRData(result.data),
                        cornerPoints: result.cornerPoints,
                    };
                    this.scanListeners.forEach(listener => listener(scanResult));
                }, {
                    preferredCamera: (options === null || options === void 0 ? void 0 : options.camera) || 'environment',
                    maxScansPerSecond: (options === null || options === void 0 ? void 0 : options.maxScansPerSecond) !== undefined ? options.maxScansPerSecond :
                        ((options === null || options === void 0 ? void 0 : options.scanDelay) ? 1000 / options.scanDelay : 5),
                    calculateScanRegion: options === null || options === void 0 ? void 0 : options.calculateScanRegion,
                    overlay: options === null || options === void 0 ? void 0 : options.overlay,
                    highlightCodeOutline: (options === null || options === void 0 ? void 0 : options.highlightCodeOutline) !== false,
                    highlightScanRegion: (options === null || options === void 0 ? void 0 : options.highlightScanRegion) !== false,
                });
                await this.scanner.start();
                // Enable torch if requested
                if ((options === null || options === void 0 ? void 0 : options.torch) && await this.scanner.hasFlash()) {
                    await this.scanner.turnFlashOn();
                    // this.torchEnabled = true;
                }
            }
            else {
                // Use ZXing for multi-format scanning
                this.barcodeReader = new BrowserMultiFormatReader();
                // Configure hints for better performance
                const hints = new Map();
                if ((options === null || options === void 0 ? void 0 : options.targetedFormats) || (options === null || options === void 0 ? void 0 : options.formats)) {
                    const zxingFormats = this.mapToZXingFormats(requestedFormats);
                    hints.set(DecodeHintType.POSSIBLE_FORMATS, zxingFormats);
                }
                this.barcodeReader.hints = hints;
                // Start video stream
                const constraints = {
                    video: {
                        facingMode: (options === null || options === void 0 ? void 0 : options.camera) === 'front' ? 'user' : 'environment',
                    }
                };
                this.currentStream = await navigator.mediaDevices.getUserMedia(constraints);
                this.videoElement.srcObject = this.currentStream;
                await this.videoElement.play();
                // Enable torch if requested
                if (options === null || options === void 0 ? void 0 : options.torch) {
                    await this.enableTorch();
                }
                // Start continuous scanning
                const scanDelay = (options === null || options === void 0 ? void 0 : options.scanDelay) || (1000 / ((options === null || options === void 0 ? void 0 : options.maxScansPerSecond) || 5));
                this.scanInterval = setInterval(async () => {
                    try {
                        const result = await this.barcodeReader.decodeFromVideoElement(this.videoElement);
                        if (result) {
                            const scanResult = {
                                content: result.getText(),
                                format: this.mapFromZXingFormat(result.getBarcodeFormat()),
                                timestamp: Date.now(),
                                type: this.detectQRType(result.getText()),
                                parsedData: this.parseQRData(result.getText()),
                                productInfo: await this.getProductInfo(result.getText(), this.mapFromZXingFormat(result.getBarcodeFormat())),
                            };
                            if (!(options === null || options === void 0 ? void 0 : options.multiple)) {
                                clearInterval(this.scanInterval);
                            }
                            this.scanListeners.forEach(listener => listener(scanResult));
                        }
                    }
                    catch (_a) {
                        // Ignore decode errors (no barcode found)
                    }
                }, scanDelay);
            }
        }
        catch (error) {
            const scanError = {
                code: 'SCAN_ERROR',
                message: error instanceof Error ? error.message : 'Failed to start scanner',
            };
            this.errorListeners.forEach(listener => listener(scanError));
            throw error;
        }
    }
    async stopScan() {
        if (this.scanner) {
            await this.scanner.stop();
            this.scanner.destroy();
            this.scanner = null;
        }
        if (this.barcodeReader) {
            this.barcodeReader.reset();
            this.barcodeReader = null;
        }
        if (this.scanInterval) {
            clearInterval(this.scanInterval);
            this.scanInterval = null;
        }
        if (this.currentStream) {
            this.currentStream.getTracks().forEach(track => track.stop());
            this.currentStream = null;
        }
        if (this.videoElement) {
            this.videoElement.remove();
            this.videoElement = null;
        }
        // this.torchEnabled = false;
    }
    async generate(options) {
        var _a, _b, _c, _d, _e;
        try {
            const qrData = this.formatQRData(options.type, options.data);
            const size = options.size || 300;
            // Generate QR code options with all user-provided options
            const qrOptions = {
                // Use user-provided width or size, with size as fallback
                width: options.width || size,
                // Use user-provided margin or design margin, with default of 4
                margin: options.margin !== undefined ? options.margin : (((_a = options.design) === null || _a === void 0 ? void 0 : _a.margin) || 4),
                // Use user-provided scale if width is not specified
                scale: options.width ? undefined : (options.scale || 4),
                color: {
                    dark: ((_c = (_b = options.design) === null || _b === void 0 ? void 0 : _b.colors) === null || _c === void 0 ? void 0 : _c.dark) || '#000000',
                    light: ((_e = (_d = options.design) === null || _d === void 0 ? void 0 : _d.colors) === null || _e === void 0 ? void 0 : _e.light) || '#FFFFFF',
                },
                errorCorrectionLevel: options.errorCorrectionLevel || 'M',
                // Pass through additional options
                version: options.version,
                maskPattern: options.maskPattern,
                toSJISFunc: options.toSJISFunc,
            };
            // Generate base64 data URL
            const dataUrl = await QRCode.toDataURL(qrData, qrOptions);
            // Generate SVG with same options
            const svg = await QRCode.toString(qrData, Object.assign(Object.assign({}, qrOptions), { type: 'svg' }));
            // Generate unique ID
            const id = this.generateId();
            // Store in history
            const historyItem = {
                id,
                type: options.type,
                data: options.data,
                createdAt: Date.now(),
                qrCode: { id, dataUrl, svg },
                scanCount: 0,
                isFavorite: false,
            };
            this.history.push(historyItem);
            this.saveHistory();
            return {
                id,
                dataUrl,
                svg,
                base64: dataUrl.split(',')[1],
            };
        }
        catch (error) {
            throw new Error(`Failed to generate QR code: ${error}`);
        }
    }
    async saveQRCode(options) {
        try {
            const { qrCode, fileName = 'qrcode', format = 'png' } = options;
            if (!qrCode.dataUrl && !qrCode.svg) {
                throw new Error('No QR code data to save');
            }
            // Create download link
            const link = document.createElement('a');
            link.download = `${fileName}.${format}`;
            switch (format) {
                case 'svg':
                    if (qrCode.svg) {
                        const blob = new Blob([qrCode.svg], { type: 'image/svg+xml' });
                        link.href = URL.createObjectURL(blob);
                    }
                    else {
                        throw new Error('SVG data not available');
                    }
                    break;
                case 'json':
                    // Export QR code data as JSON
                    const jsonData = {
                        id: qrCode.id,
                        dataUrl: qrCode.dataUrl,
                        svg: qrCode.svg,
                        timestamp: Date.now()
                    };
                    const jsonBlob = new Blob([JSON.stringify(jsonData, null, 2)], { type: 'application/json' });
                    link.href = URL.createObjectURL(jsonBlob);
                    break;
                case 'jpg':
                    // Convert PNG to JPG using canvas
                    if (qrCode.dataUrl) {
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');
                        const img = new Image();
                        await new Promise((resolve, reject) => {
                            img.onload = resolve;
                            img.onerror = reject;
                            img.src = qrCode.dataUrl;
                        });
                        canvas.width = img.width;
                        canvas.height = img.height;
                        ctx.fillStyle = '#FFFFFF';
                        ctx.fillRect(0, 0, canvas.width, canvas.height);
                        ctx.drawImage(img, 0, 0);
                        link.href = canvas.toDataURL('image/jpeg', 0.95);
                    }
                    break;
                case 'webp':
                    // Convert to WebP if supported
                    if (qrCode.dataUrl) {
                        const canvas = document.createElement('canvas');
                        const ctx = canvas.getContext('2d');
                        const img = new Image();
                        await new Promise((resolve, reject) => {
                            img.onload = resolve;
                            img.onerror = reject;
                            img.src = qrCode.dataUrl;
                        });
                        canvas.width = img.width;
                        canvas.height = img.height;
                        ctx.drawImage(img, 0, 0);
                        link.href = canvas.toDataURL('image/webp', 0.95);
                    }
                    break;
                case 'pdf':
                    // For PDF, we would need a library like jsPDF
                    // For now, throw an informative error
                    throw new Error('PDF export requires additional libraries. Please use PNG or SVG format.');
                case 'gif':
                case 'eps':
                case 'wmf':
                    // These formats require specialized libraries
                    throw new Error(`${format.toUpperCase()} export is not yet implemented. Please use PNG, JPG, or SVG format.`);
                case 'png':
                default:
                    if (qrCode.dataUrl) {
                        link.href = qrCode.dataUrl;
                    }
                    else {
                        throw new Error('PNG data not available');
                    }
                    break;
            }
            // Trigger download
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            return {
                uri: link.href,
                path: `${fileName}.${format}`,
            };
        }
        catch (error) {
            throw new Error(`Failed to save QR code: ${error}`);
        }
    }
    async getHistory(options) {
        this.loadHistory();
        let filteredHistory = [...this.history];
        // Apply filters
        if (options === null || options === void 0 ? void 0 : options.type) {
            filteredHistory = filteredHistory.filter(item => item.type === options.type);
        }
        if (options === null || options === void 0 ? void 0 : options.dateRange) {
            const start = options.dateRange.start.getTime();
            const end = options.dateRange.end.getTime();
            filteredHistory = filteredHistory.filter(item => item.createdAt >= start && item.createdAt <= end);
        }
        // Sort by date (newest first)
        filteredHistory.sort((a, b) => b.createdAt - a.createdAt);
        // Apply pagination
        const offset = (options === null || options === void 0 ? void 0 : options.offset) || 0;
        const limit = (options === null || options === void 0 ? void 0 : options.limit) || 50;
        const paginatedHistory = filteredHistory.slice(offset, offset + limit);
        return {
            items: paginatedHistory,
            total: filteredHistory.length,
        };
    }
    async clearHistory() {
        this.history = [];
        localStorage.removeItem('qrcode_studio_history');
    }
    async getAnalytics(options) {
        // Web implementation would need a backend service for real analytics
        // This is a mock implementation
        const qrCode = this.history.find(item => item.id === options.qrCodeId);
        if (!qrCode) {
            throw new Error('QR code not found');
        }
        return {
            totalScans: qrCode.scanCount || 0,
            uniqueScans: Math.floor((qrCode.scanCount || 0) * 0.7),
            locations: [
                { country: 'United States', region: 'California', city: 'San Francisco', count: 45 },
                { country: 'United Kingdom', region: 'England', city: 'London', count: 23 },
            ],
            devices: [
                { type: 'mobile', os: 'iOS', count: 42 },
                { type: 'mobile', os: 'Android', count: 26 },
            ],
            timeDistribution: this.generateMockTimeDistribution(),
        };
    }
    async scan(options) {
        return new Promise((resolve, reject) => {
            const handleScan = (result) => {
                this.stopScan();
                resolve(result);
            };
            const handleError = (error) => {
                this.stopScan();
                reject(new Error(error.message));
            };
            this.addListener('scanResult', handleScan);
            this.addListener('scanError', handleError);
            this.startScan(options).catch(reject);
        });
    }
    async readBarcodesFromImage(options) {
        try {
            const reader = new BrowserMultiFormatReader();
            // Configure formats if specified
            if (options.formats) {
                const hints = new Map();
                hints.set(DecodeHintType.POSSIBLE_FORMATS, this.mapToZXingFormats(options.formats));
                reader.hints = hints;
            }
            let imageElement;
            if (options.path) {
                // Load from path
                imageElement = new Image();
                await new Promise((resolve, reject) => {
                    imageElement.onload = resolve;
                    imageElement.onerror = reject;
                    imageElement.src = options.path;
                });
            }
            else if (options.base64) {
                // Load from base64
                imageElement = new Image();
                await new Promise((resolve, reject) => {
                    imageElement.onload = resolve;
                    imageElement.onerror = reject;
                    imageElement.src = `data:image/png;base64,${options.base64}`;
                });
            }
            else {
                throw new Error('Either path or base64 must be provided');
            }
            const result = await reader.decodeFromImageElement(imageElement);
            return [{
                    content: result.getText(),
                    format: this.mapFromZXingFormat(result.getBarcodeFormat()),
                    timestamp: Date.now(),
                    type: this.detectQRType(result.getText()),
                    parsedData: this.parseQRData(result.getText()),
                    productInfo: await this.getProductInfo(result.getText(), this.mapFromZXingFormat(result.getBarcodeFormat())),
                }];
        }
        catch (error) {
            throw new Error(`Failed to read barcode from image: ${error}`);
        }
    }
    async getSupportedFormats() {
        // Web platform supports all formats through ZXing
        return Object.values(BarcodeFormat);
    }
    async enableTorch() {
        try {
            if (this.scanner && await this.scanner.hasFlash()) {
                await this.scanner.turnFlashOn();
                // this.torchEnabled = true;
                this.torchListeners.forEach(listener => listener({ isEnabled: true }));
            }
            else if (this.currentStream) {
                const videoTrack = this.currentStream.getVideoTracks()[0];
                const capabilities = videoTrack.getCapabilities();
                if (capabilities.torch) {
                    await videoTrack.applyConstraints({
                        advanced: [{ torch: true }],
                    });
                    // this.torchEnabled = true;
                    this.torchListeners.forEach(listener => listener({ isEnabled: true }));
                }
                else {
                    throw new Error('Torch not available on this device');
                }
            }
        }
        catch (error) {
            throw new Error(`Failed to enable torch: ${error}`);
        }
    }
    async disableTorch() {
        try {
            if (this.scanner && await this.scanner.hasFlash()) {
                await this.scanner.turnFlashOff();
                // this.torchEnabled = false;
                this.torchListeners.forEach(listener => listener({ isEnabled: false }));
            }
            else if (this.currentStream) {
                const videoTrack = this.currentStream.getVideoTracks()[0];
                const capabilities = videoTrack.getCapabilities();
                if (capabilities.torch) {
                    await videoTrack.applyConstraints({
                        advanced: [{ torch: false }],
                    });
                    // this.torchEnabled = false;
                    this.torchListeners.forEach(listener => listener({ isEnabled: false }));
                }
            }
        }
        catch (error) {
            throw new Error(`Failed to disable torch: ${error}`);
        }
    }
    async isTorchAvailable() {
        try {
            if (this.scanner) {
                return { available: await this.scanner.hasFlash() };
            }
            const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } });
            const videoTrack = stream.getVideoTracks()[0];
            const capabilities = videoTrack.getCapabilities();
            stream.getTracks().forEach(track => track.stop());
            return { available: !!capabilities.torch };
        }
        catch (_a) {
            return { available: false };
        }
    }
    async setZoomRatio(options) {
        try {
            if (this.currentStream) {
                const videoTrack = this.currentStream.getVideoTracks()[0];
                const capabilities = videoTrack.getCapabilities();
                if (capabilities.zoom) {
                    const minZoom = capabilities.zoom.min || 1;
                    const maxZoom = capabilities.zoom.max || 1;
                    const zoom = Math.min(maxZoom, Math.max(minZoom, options.ratio));
                    await videoTrack.applyConstraints({
                        advanced: [{ zoom }],
                    });
                }
                else {
                    throw new Error('Zoom not available on this device');
                }
            }
            else {
                throw new Error('No active video stream');
            }
        }
        catch (error) {
            throw new Error(`Failed to set zoom: ${error}`);
        }
    }
    async generateBarcode(options) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
        try {
            // Create canvas element
            const canvas = document.createElement('canvas');
            // Generate barcode
            JsBarcode(canvas, options.data, {
                format: this.mapToJSBarcodeFormat(options.format),
                width: options.width ? options.width / 100 : 2,
                height: options.height || 100,
                displayValue: options.displayText !== false,
                text: options.text || options.data,
                textAlign: ((_a = options.fontOptions) === null || _a === void 0 ? void 0 : _a.textAlign) || 'center',
                textPosition: ((_b = options.fontOptions) === null || _b === void 0 ? void 0 : _b.textPosition) || 'bottom',
                textMargin: ((_c = options.fontOptions) === null || _c === void 0 ? void 0 : _c.textMargin) || 2,
                fontSize: ((_d = options.fontOptions) === null || _d === void 0 ? void 0 : _d.size) || 20,
                font: ((_e = options.fontOptions) === null || _e === void 0 ? void 0 : _e.font) || 'monospace',
                background: ((_f = options.colors) === null || _f === void 0 ? void 0 : _f.background) || '#FFFFFF',
                lineColor: ((_g = options.colors) === null || _g === void 0 ? void 0 : _g.lineColor) || '#000000',
                margin: options.margins ? Math.min(options.margins.top || 10, options.margins.right || 10, options.margins.bottom || 10, options.margins.left || 10) : 10,
            });
            // Convert to requested format
            let result = {
                format: options.format,
                data: options.data,
            };
            switch (options.outputFormat) {
                case 'svg':
                    // For SVG, we need to regenerate using SVG element
                    const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                    JsBarcode(svgElement, options.data, {
                        format: this.mapToJSBarcodeFormat(options.format),
                        width: options.width ? options.width / 100 : 2,
                        height: options.height || 100,
                        displayValue: options.displayText !== false,
                        text: options.text || options.data,
                        textAlign: ((_h = options.fontOptions) === null || _h === void 0 ? void 0 : _h.textAlign) || 'center',
                        textPosition: ((_j = options.fontOptions) === null || _j === void 0 ? void 0 : _j.textPosition) || 'bottom',
                        textMargin: ((_k = options.fontOptions) === null || _k === void 0 ? void 0 : _k.textMargin) || 2,
                        fontSize: ((_l = options.fontOptions) === null || _l === void 0 ? void 0 : _l.size) || 20,
                        font: ((_m = options.fontOptions) === null || _m === void 0 ? void 0 : _m.font) || 'monospace',
                        background: ((_o = options.colors) === null || _o === void 0 ? void 0 : _o.background) || '#FFFFFF',
                        lineColor: ((_p = options.colors) === null || _p === void 0 ? void 0 : _p.lineColor) || '#000000',
                        margin: options.margins ? Math.min(options.margins.top || 10, options.margins.right || 10, options.margins.bottom || 10, options.margins.left || 10) : 10,
                    });
                    result.svg = new XMLSerializer().serializeToString(svgElement);
                    break;
                case 'jpg':
                    result.dataUrl = canvas.toDataURL('image/jpeg', 0.95);
                    result.base64 = result.dataUrl.split(',')[1];
                    break;
                case 'png':
                default:
                    result.dataUrl = canvas.toDataURL('image/png');
                    result.base64 = result.dataUrl.split(',')[1];
                    break;
            }
            return result;
        }
        catch (error) {
            throw new Error(`Failed to generate barcode: ${error}`);
        }
    }
    async addListener(eventName, listenerFunc) {
        if (eventName === 'scanResult') {
            this.scanListeners.push(listenerFunc);
        }
        else if (eventName === 'scanError') {
            this.errorListeners.push(listenerFunc);
        }
        else if (eventName === 'torchStateChanged') {
            this.torchListeners.push(listenerFunc);
        }
        return {
            remove: async () => {
                if (eventName === 'scanResult') {
                    this.scanListeners = this.scanListeners.filter(l => l !== listenerFunc);
                }
                else if (eventName === 'scanError') {
                    this.errorListeners = this.errorListeners.filter(l => l !== listenerFunc);
                }
                else if (eventName === 'torchStateChanged') {
                    this.torchListeners = this.torchListeners.filter(l => l !== listenerFunc);
                }
            },
        };
    }
    async removeAllListeners() {
        this.scanListeners = [];
        this.errorListeners = [];
        this.torchListeners = [];
    }
    // Helper methods
    detectQRType(content) {
        // URL patterns
        if (/^https?:\/\//i.test(content)) {
            if (content.includes('youtube.com') || content.includes('youtu.be')) {
                return QRType.VIDEO;
            }
            if (content.includes('facebook.com')) {
                return QRType.FACEBOOK;
            }
            if (content.includes('instagram.com')) {
                return QRType.INSTAGRAM;
            }
            if (content.includes('.pdf')) {
                return QRType.PDF;
            }
            return QRType.WEBSITE;
        }
        // WiFi pattern
        if (/^WIFI:/i.test(content)) {
            return QRType.WIFI;
        }
        // vCard pattern
        if (/^BEGIN:VCARD/i.test(content)) {
            return QRType.VCARD;
        }
        // Email pattern
        if (/^mailto:/i.test(content)) {
            return QRType.EMAIL;
        }
        // Phone pattern
        if (/^tel:/i.test(content)) {
            return QRType.PHONE;
        }
        // SMS pattern
        if (/^sms:/i.test(content)) {
            return QRType.SMS;
        }
        // WhatsApp pattern
        if (/^https:\/\/wa\.me\//i.test(content)) {
            return QRType.WHATSAPP;
        }
        // Location pattern
        if (/^geo:/i.test(content)) {
            return QRType.LOCATION;
        }
        // Event pattern
        if (/^BEGIN:VEVENT/i.test(content)) {
            return QRType.EVENT;
        }
        // Default to text
        return QRType.TEXT;
    }
    parseQRData(content) {
        const type = this.detectQRType(content);
        switch (type) {
            case QRType.WEBSITE:
            case QRType.PDF:
            case QRType.VIDEO:
                return { url: content };
            case QRType.WIFI:
                const wifiMatch = content.match(/WIFI:T:([^;]+);S:([^;]+);P:([^;]+);/);
                if (wifiMatch) {
                    return {
                        security: wifiMatch[1],
                        ssid: wifiMatch[2],
                        password: wifiMatch[3],
                    };
                }
                break;
            case QRType.EMAIL:
                const emailMatch = content.match(/mailto:([^?]+)\??(.*)$/);
                if (emailMatch) {
                    const params = new URLSearchParams(emailMatch[2]);
                    return {
                        to: emailMatch[1],
                        subject: params.get('subject') || undefined,
                        body: params.get('body') || undefined,
                    };
                }
                break;
            case QRType.PHONE:
                return { phoneNumber: content.replace('tel:', '') };
            case QRType.SMS:
                const smsMatch = content.match(/sms:([^?]+)\??(.*)$/);
                if (smsMatch) {
                    const params = new URLSearchParams(smsMatch[2]);
                    return {
                        phoneNumber: smsMatch[1],
                        message: params.get('body') || undefined,
                    };
                }
                break;
            case QRType.TEXT:
            default:
                return { text: content };
        }
        return { text: content };
    }
    formatQRData(type, data) {
        switch (type) {
            case QRType.WEBSITE:
            case QRType.PDF:
            case QRType.VIDEO:
                return data.url;
            case QRType.WIFI:
                return `WIFI:T:${data.security};S:${data.ssid};P:${data.password || ''};H:${data.hidden ? 'true' : 'false'};`;
            case QRType.VCARD:
                return this.generateVCard(data);
            case QRType.EMAIL:
                let emailUrl = `mailto:${data.to}`;
                const emailParams = new URLSearchParams();
                if (data.subject)
                    emailParams.append('subject', data.subject);
                if (data.body)
                    emailParams.append('body', data.body);
                if (data.cc)
                    emailParams.append('cc', data.cc);
                if (data.bcc)
                    emailParams.append('bcc', data.bcc);
                if (emailParams.toString())
                    emailUrl += `?${emailParams.toString()}`;
                return emailUrl;
            case QRType.PHONE:
                return `tel:${data.phoneNumber}`;
            case QRType.SMS:
                let smsUrl = `sms:${data.phoneNumber}`;
                if (data.message)
                    smsUrl += `?body=${encodeURIComponent(data.message)}`;
                return smsUrl;
            case QRType.WHATSAPP:
                let whatsappUrl = `https://wa.me/${data.phoneNumber.replace(/[^0-9]/g, '')}`;
                if (data.message)
                    whatsappUrl += `?text=${encodeURIComponent(data.message)}`;
                return whatsappUrl;
            case QRType.LOCATION:
                return `geo:${data.latitude},${data.longitude}`;
            case QRType.EVENT:
                return this.generateVEvent(data);
            case QRType.FACEBOOK:
                return data.pageUrl;
            case QRType.INSTAGRAM:
                return data.profileUrl;
            case QRType.IMAGES:
                // For images, create a landing page URL or JSON representation
                return JSON.stringify({
                    type: 'images',
                    title: data.title,
                    description: data.description,
                    images: data.images
                });
            case QRType.MENU:
                // For menu, create a structured JSON representation
                return JSON.stringify({
                    type: 'menu',
                    restaurant: data.restaurantName,
                    currency: data.currency || 'USD',
                    categories: data.categories
                });
            case QRType.BUSINESS:
                // Business card format
                const businessLines = ['BEGIN:BUSINESS'];
                if (data.name)
                    businessLines.push(`NAME:${data.name}`);
                if (data.industry)
                    businessLines.push(`INDUSTRY:${data.industry}`);
                if (data.phone)
                    businessLines.push(`PHONE:${data.phone}`);
                if (data.email)
                    businessLines.push(`EMAIL:${data.email}`);
                if (data.website)
                    businessLines.push(`URL:${data.website}`);
                if (data.address)
                    businessLines.push(`ADDRESS:${data.address}`);
                if (data.hours)
                    businessLines.push(`HOURS:${data.hours}`);
                if (data.description)
                    businessLines.push(`DESC:${data.description}`);
                businessLines.push('END:BUSINESS');
                return businessLines.join('\n');
            case QRType.MP3:
                // For MP3, create a structured representation
                return JSON.stringify({
                    type: 'mp3',
                    url: data.url,
                    title: data.title,
                    artist: data.artist,
                    album: data.album,
                    coverArt: data.coverArt
                });
            case QRType.APPS:
                // For apps, create a multi-platform URL or JSON
                if (data.customUrl)
                    return data.customUrl;
                if (data.appStoreUrl)
                    return data.appStoreUrl;
                if (data.playStoreUrl)
                    return data.playStoreUrl;
                if (data.windowsStoreUrl)
                    return data.windowsStoreUrl;
                return JSON.stringify({
                    type: 'apps',
                    appName: data.appName,
                    description: data.description,
                    stores: {
                        appStore: data.appStoreUrl,
                        playStore: data.playStoreUrl,
                        windowsStore: data.windowsStoreUrl
                    }
                });
            case QRType.LINKS_LIST:
                // For links list, create a JSON representation
                return JSON.stringify({
                    type: 'links',
                    title: data.title,
                    links: data.links
                });
            case QRType.COUPON:
                // For coupon, create a structured format
                return JSON.stringify({
                    type: 'coupon',
                    code: data.code,
                    description: data.description,
                    discount: data.discount,
                    validUntil: data.validUntil,
                    terms: data.terms
                });
            case QRType.SOCIAL_MEDIA:
                // For social media, create a multi-link format
                const socialLinks = Object.entries(data)
                    .filter(([key, value]) => value && key !== 'type')
                    .map(([network, url]) => `${network}: ${url}`)
                    .join('\n');
                return socialLinks || JSON.stringify(data);
            case QRType.TEXT:
            default:
                return data.text || JSON.stringify(data);
        }
    }
    generateVCard(data) {
        const vcard = [
            'BEGIN:VCARD',
            'VERSION:3.0',
        ];
        if (data.firstName || data.lastName) {
            vcard.push(`FN:${data.firstName || ''} ${data.lastName || ''}`.trim());
            vcard.push(`N:${data.lastName || ''};${data.firstName || ''};;;`);
        }
        if (data.organization)
            vcard.push(`ORG:${data.organization}`);
        if (data.title)
            vcard.push(`TITLE:${data.title}`);
        if (data.phone)
            vcard.push(`TEL:${data.phone}`);
        if (data.mobile)
            vcard.push(`TEL;TYPE=CELL:${data.mobile}`);
        if (data.email)
            vcard.push(`EMAIL:${data.email}`);
        if (data.website)
            vcard.push(`URL:${data.website}`);
        if (data.address)
            vcard.push(`ADR:;;${data.address};;;;`);
        if (data.note)
            vcard.push(`NOTE:${data.note}`);
        vcard.push('END:VCARD');
        return vcard.join('\n');
    }
    generateVEvent(data) {
        const vevent = [
            'BEGIN:VCALENDAR',
            'VERSION:2.0',
            'PRODID:-//QRCode Studio//EN',
            'BEGIN:VEVENT',
        ];
        const dtstart = new Date(data.startDate).toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
        vevent.push(`DTSTART:${dtstart}`);
        if (data.endDate) {
            const dtend = new Date(data.endDate).toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
            vevent.push(`DTEND:${dtend}`);
        }
        vevent.push(`SUMMARY:${data.title}`);
        if (data.location)
            vevent.push(`LOCATION:${data.location}`);
        if (data.description)
            vevent.push(`DESCRIPTION:${data.description}`);
        if (data.url)
            vevent.push(`URL:${data.url}`);
        vevent.push('END:VEVENT');
        vevent.push('END:VCALENDAR');
        return vevent.join('\n');
    }
    generateId() {
        return `qr_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
    saveHistory() {
        localStorage.setItem('qrcode_studio_history', JSON.stringify(this.history));
    }
    loadHistory() {
        const saved = localStorage.getItem('qrcode_studio_history');
        if (saved) {
            try {
                this.history = JSON.parse(saved);
            }
            catch (_a) {
                this.history = [];
            }
        }
    }
    generateMockTimeDistribution() {
        const distribution = [];
        const today = new Date();
        for (let i = 6; i >= 0; i--) {
            const date = new Date(today);
            date.setDate(date.getDate() - i);
            distribution.push({
                date: date.toISOString().split('T')[0],
                count: Math.floor(Math.random() * 20) + 5,
            });
        }
        return distribution;
    }
    mapToZXingFormats(formats) {
        return formats.map(format => {
            switch (format) {
                case BarcodeFormat.QR_CODE: return ZXingFormat.QR_CODE;
                case BarcodeFormat.DATA_MATRIX: return ZXingFormat.DATA_MATRIX;
                case BarcodeFormat.AZTEC: return ZXingFormat.AZTEC;
                case BarcodeFormat.PDF_417: return ZXingFormat.PDF_417;
                case BarcodeFormat.MAXICODE: return ZXingFormat.MAXICODE;
                case BarcodeFormat.EAN_13: return ZXingFormat.EAN_13;
                case BarcodeFormat.EAN_8: return ZXingFormat.EAN_8;
                case BarcodeFormat.UPC_A: return ZXingFormat.UPC_A;
                case BarcodeFormat.UPC_E: return ZXingFormat.UPC_E;
                case BarcodeFormat.CODE_128: return ZXingFormat.CODE_128;
                case BarcodeFormat.CODE_39: return ZXingFormat.CODE_39;
                case BarcodeFormat.CODE_93: return ZXingFormat.CODE_93;
                case BarcodeFormat.CODABAR: return ZXingFormat.CODABAR;
                case BarcodeFormat.ITF: return ZXingFormat.ITF;
                case BarcodeFormat.RSS_14: return ZXingFormat.RSS_14;
                case BarcodeFormat.RSS_EXPANDED: return ZXingFormat.RSS_EXPANDED;
                default: return ZXingFormat.QR_CODE;
            }
        });
    }
    mapFromZXingFormat(format) {
        switch (format) {
            case ZXingFormat.QR_CODE: return BarcodeFormat.QR_CODE;
            case ZXingFormat.DATA_MATRIX: return BarcodeFormat.DATA_MATRIX;
            case ZXingFormat.AZTEC: return BarcodeFormat.AZTEC;
            case ZXingFormat.PDF_417: return BarcodeFormat.PDF_417;
            case ZXingFormat.MAXICODE: return BarcodeFormat.MAXICODE;
            case ZXingFormat.EAN_13: return BarcodeFormat.EAN_13;
            case ZXingFormat.EAN_8: return BarcodeFormat.EAN_8;
            case ZXingFormat.UPC_A: return BarcodeFormat.UPC_A;
            case ZXingFormat.UPC_E: return BarcodeFormat.UPC_E;
            case ZXingFormat.CODE_128: return BarcodeFormat.CODE_128;
            case ZXingFormat.CODE_39: return BarcodeFormat.CODE_39;
            case ZXingFormat.CODE_93: return BarcodeFormat.CODE_93;
            case ZXingFormat.CODABAR: return BarcodeFormat.CODABAR;
            case ZXingFormat.ITF: return BarcodeFormat.ITF;
            case ZXingFormat.RSS_14: return BarcodeFormat.RSS_14;
            case ZXingFormat.RSS_EXPANDED: return BarcodeFormat.RSS_EXPANDED;
            default: return BarcodeFormat.QR_CODE;
        }
    }
    mapToJSBarcodeFormat(format) {
        switch (format) {
            case BarcodeFormat.CODE_128: return 'CODE128';
            case BarcodeFormat.CODE_39: return 'CODE39';
            case BarcodeFormat.EAN_13: return 'EAN13';
            case BarcodeFormat.EAN_8: return 'EAN8';
            case BarcodeFormat.UPC_A: return 'UPC';
            case BarcodeFormat.UPC_E: return 'UPC_E';
            case BarcodeFormat.ITF: return 'ITF';
            case BarcodeFormat.ITF_14: return 'ITF14';
            case BarcodeFormat.MSI: return 'MSI';
            case BarcodeFormat.MSI_PLESSEY: return 'MSI';
            case BarcodeFormat.PHARMACODE: return 'pharmacode';
            case BarcodeFormat.CODABAR: return 'codabar';
            default:
                throw new Error(`Unsupported barcode format for generation: ${format}`);
        }
    }
    async getProductInfo(content, format) {
        // Only process product codes
        if (![BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8].includes(format)) {
            return undefined;
        }
        // In a real implementation, this would call a product API service
        // For now, return mock data for demonstration
        return {
            name: 'Sample Product',
            brand: 'Sample Brand',
            category: 'General',
            description: 'This is a sample product description',
            metadata: {
                barcode: content,
                format: format,
            }
        };
    }
}
//# sourceMappingURL=web.js.map