class PixQRGenerator {
    constructor() {
        this.initializePixInterface();
    }

    initializePixInterface() {
        // Listeners for realtime preview
        const fieldsToWatch = [
            'pix-key', 
            'pix-key-type',
            'pix-name', 
            'pix-city', 
            'pix-amount', 
            'pix-description', 
            'pix-txid'
        ];

        fieldsToWatch.forEach(fieldId => {
            const element = document.getElementById(fieldId);
            if (element) {
                element.addEventListener('input', () => this.updatePreview());
                element.addEventListener('change', () => this.updatePreview());
            }
        });
        
        // Add currency mask to amount field
        const amountInput = document.getElementById('pix-amount');
        if (amountInput) {
            amountInput.addEventListener('input', (e) => {
                let value = e.target.value.replace(/\D/g, '');
                if (value) {
                    value = (parseInt(value) / 100).toFixed(2) + '';
                    value = value.replace('.', ',');
                    value = value.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.');
                    e.target.value = value;
                }
                this.updatePreview();
            });
        }
    }

    updatePreview() {
        const data = this.collectPixData();
        const previewElement = document.getElementById('pix-preview-text');
        
        if (previewElement) {
            // Validação de "Preguiça" (Laziness Validation)
            // Checks if user selected one type but entered another
            const validationWarning = this.validateKeyType(data.keyType, data.key);
            
            if (validationWarning) {
                previewElement.innerHTML = `<span class="text-danger"><i class="fas fa-exclamation-triangle"></i> ${validationWarning}</span>`;
                return;
            }

            if (!data.key || !data.name || !data.city) {
                previewElement.textContent = "Preencha os campos obrigatórios (Chave, Nome, Cidade) para ver o preview.";
                return;
            }
            
            try {
                const payload = this.generatePixPayload();
                previewElement.textContent = payload;
            } catch (e) {
                previewElement.textContent = "Erro ao gerar payload: " + e.message;
            }
        }
    }

    validatePixData() {
        const data = this.collectPixData();
        const errors = [];

        // Required fields
        if (!data.key.trim()) errors.push('Chave PIX é obrigatória');
        if (!data.name.trim()) errors.push('Nome do beneficiário é obrigatório');
        if (!data.city.trim()) errors.push('Cidade do beneficiário é obrigatória');
        
        // Length limits
        if (data.name.length > 25) errors.push('Nome deve ter no máximo 25 caracteres');
        if (data.city.length > 15) errors.push('Cidade deve ter no máximo 15 caracteres (Regra do Banco Central)');

        // Amount validation
        if (data.amount) {
            const amount = parseFloat(data.amount.replace(/\./g, '').replace(',', '.'));
            if (isNaN(amount) || amount <= 0) {
                errors.push('Valor deve ser um número maior que zero');
            }
        }

        // Smart Key Validation
        const keyWarning = this.validateKeyType(data.keyType, data.key);
        if (keyWarning) {
            errors.push(keyWarning);
        }

        return errors;
    }

    validateKeyType(type, key) {
        if (!key) return null;
        const cleanKey = key.replace(/\D/g, ''); // Numbers only

        // Case 1: Selected CPF/CNPJ
        if (type === 'cpf') {
            if (cleanKey.length === 11) {
                if (!this.isValidCPF(cleanKey)) {
                    // Check if looks like phone (DDD + 9...)
                    if (cleanKey[2] === '9') {
                         return "Selecionado CPF, mas parece um Celular. Altere o tipo para 'Celular' ou corrija.";
                    }
                    return "CPF Inválido. Verifique os dígitos.";
                }
            } else if (cleanKey.length === 14) {
                 if (!this.isValidCNPJ(cleanKey)) {
                     return "CNPJ Inválido. Verifique os dígitos.";
                 }
            } else {
                 if (cleanKey.length > 0) return `CPF/CNPJ deve ter 11 ou 14 números. (Atual: ${cleanKey.length})`;
            }
        }

        // Case 2: Selected Phone
        if (type === 'phone') {
            if (cleanKey.length > 0) {
                if (cleanKey.length !== 10 && cleanKey.length !== 11) {
                    return `Telefone deve ter 10 ou 11 números (DDD + Número). (Atual: ${cleanKey.length})`;
                }
                
                // Smart check: Typed a CPF in Phone field?
                if (cleanKey.length === 11 && this.isValidCPF(cleanKey)) {
                    // Check if it's NOT a typical mobile number structure
                    // Mobile: DDD (11-99) + 9 + 8 digits.
                    const ddd = parseInt(cleanKey.substring(0, 2));
                    const ninthDigit = cleanKey[2];
                    
                    // If DDD is invalid or 9th digit is not 9, but it IS a valid CPF -> Warning
                    if (ddd < 11 || ddd > 99 || ninthDigit !== '9') {
                         return "Isso parece ser um CPF válido, mas o tipo selecionado é 'Celular'.";
                    }
                }
            }
        }

        // Case 3: Email
        if (type === 'email') {
             if (key.length > 0 && !key.includes('@')) {
                 return "Email inválido. Deve conter '@'.";
             }
        }

        return null;
    }

    isValidCPF(cpf) {
        if (typeof cpf !== "string") return false;
        cpf = cpf.replace(/[\s.-]*/igm, '');
        if (cpf.length !== 11 || !Array.from(cpf).filter(e => e !== cpf[0]).length) {
            return false;
        }
        var sum = 0;
        var remainder;
        for (var i = 1; i <= 9; i++) 
            sum = sum + parseInt(cpf.substring(i-1, i)) * (11 - i);
        remainder = (sum * 10) % 11;
        if ((remainder == 10) || (remainder == 11))  remainder = 0;
        if (remainder != parseInt(cpf.substring(9, 10)) ) return false;
        sum = 0;
        for (i = 1; i <= 10; i++) 
            sum = sum + parseInt(cpf.substring(i-1, i)) * (12 - i);
        remainder = (sum * 10) % 11;
        if ((remainder == 10) || (remainder == 11))  remainder = 0;
        if (remainder != parseInt(cpf.substring(10, 11)) ) return false;
        return true;
    }

    isValidCNPJ(cnpj) {
        if (!cnpj) return false;
        cnpj = cnpj.replace(/[^\d]+/g,'');
        if (cnpj.length != 14) return false;
        // Elimina CNPJs invalidos conhecidos
        if (cnpj == "00000000000000" || 
            cnpj == "11111111111111" || 
            cnpj == "22222222222222" || 
            cnpj == "33333333333333" || 
            cnpj == "44444444444444" || 
            cnpj == "55555555555555" || 
            cnpj == "66666666666666" || 
            cnpj == "77777777777777" || 
            cnpj == "88888888888888" || 
            cnpj == "99999999999999")
            return false;
            
        // Valida DVs
        let tamanho = cnpj.length - 2
        let numeros = cnpj.substring(0,tamanho);
        let digitos = cnpj.substring(tamanho);
        let soma = 0;
        let pos = tamanho - 7;
        for (let i = tamanho; i >= 1; i--) {
          soma += numeros.charAt(tamanho - i) * pos--;
          if (pos < 2) pos = 9;
        }
        let resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
        if (resultado != digitos.charAt(0)) return false;
             
        tamanho = tamanho + 1;
        numeros = cnpj.substring(0,tamanho);
        soma = 0;
        pos = tamanho - 7;
        for (let i = tamanho; i >= 1; i--) {
          soma += numeros.charAt(tamanho - i) * pos--;
          if (pos < 2) pos = 9;
        }
        resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
        if (resultado != digitos.charAt(1)) return false;
               
        return true;
    }

    collectPixData() {
        return {
            keyType: document.getElementById('pix-key-type')?.value || 'cpf',
            key: document.getElementById('pix-key')?.value || '',
            name: document.getElementById('pix-name')?.value || '',
            city: document.getElementById('pix-city')?.value || '',
            amount: document.getElementById('pix-amount')?.value || '',
            description: document.getElementById('pix-description')?.value || '',
            txid: document.getElementById('pix-txid')?.value || ''
        };
    }

    generateCRC16(payload) {
        let crc = 0xFFFF;
        const polynomial = 0x1021;

        for (let i = 0; i < payload.length; i++) {
            crc ^= payload.charCodeAt(i) << 8;
            for (let j = 0; j < 8; j++) {
                if ((crc & 0x8000) !== 0) {
                    crc = ((crc << 1) ^ polynomial) & 0xFFFF;
                } else {
                    crc = (crc << 1) & 0xFFFF;
                }
            }
        }
        
        return crc.toString(16).toUpperCase().padStart(4, '0');
    }

    formatField(id, value) {
        const valStr = value.toString();
        const len = valStr.length.toString().padStart(2, '0');
        return `${id}${len}${valStr}`;
    }
    
    formatKey(type, key) {
        if (!key) return '';
        const cleanKey = key.trim();
        
        switch(type) {
            case 'phone':
                // Remove non-digits
                let nums = cleanKey.replace(/\D/g, '');
                // If 10 or 11 digits (DDD+Number), add +55
                if ((nums.length === 10 || nums.length === 11) && !nums.startsWith('55')) {
                    return `+55${nums}`;
                }
                // If user typed 55..., ensure +
                if (nums.startsWith('55') && !cleanKey.startsWith('+')) {
                    return `+${nums}`;
                }
                // If user typed +..., keep it
                if (cleanKey.startsWith('+')) {
                    return cleanKey; // Assume correct
                }
                return `+${nums}`; // Fallback
                
            case 'cpf':
            case 'cnpj':
                // Numbers only
                return cleanKey.replace(/\D/g, '');
                
            case 'email':
                return cleanKey.toLowerCase();
                
            case 'random':
            default:
                return cleanKey;
        }
    }

    generatePixPayload() {
        const data = this.collectPixData();
        
        // Format key based on type
        const key = this.formatKey(data.keyType, data.key);
        
        const name = this.removeAccents(data.name.trim()).substring(0, 25);
        const city = this.removeAccents(data.city.trim()).substring(0, 15); // Standard limit 15 chars
        const amount = data.amount ? parseFloat(data.amount.replace(/\./g, '').replace(',', '.')).toFixed(2) : null;
        const description = this.removeAccents(data.description.trim()) || '';
        const txid = this.removeAccents(data.txid.trim()) || '***';

        let payload = this.formatField('00', '01');

        const gui = this.formatField('00', 'br.gov.bcb.pix');
        const keyField = this.formatField('01', key);
        
        let merchantAccountInfo = gui + keyField;
        if (description) {
             merchantAccountInfo += this.formatField('02', description);
        }
        payload += this.formatField('26', merchantAccountInfo);

        payload += this.formatField('52', '0000'); // Merchant Category Code
        payload += this.formatField('53', '986');  // Transaction Currency (BRL)

        if (amount) {
            payload += this.formatField('54', amount); // Transaction Amount
        }

        payload += this.formatField('58', 'BR'); // Country Code
        payload += this.formatField('59', name); // Merchant Name
        payload += this.formatField('60', city); // Merchant City

        // Field 62: Additional Data Field Template
        // Subfields: 05 (Reference Label / TxID)
        const txidField = this.formatField('05', txid);
        payload += this.formatField('62', txidField);

        payload += '6304'; // CRC16 ID + Length

        const crc = this.generateCRC16(payload);
        
        return payload + crc;
    }

    removeAccents(str) {
        return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    }
}