from flask import Flask, render_template, request, send_file, redirect, url_for
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib.units import inch
import qrcode
from datetime import date
import base64
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from xhtml2pdf import pisa
from io import BytesIO
import os
import pymysql

app = Flask(__name__)
app.config['SECRET_KEY'] = 'project'
# Detalles de la conexión local
LOCAL_DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': '12345678',
    'database': 'invoices_db'
}

def connect_to_database(config):
    try:
        connection = pymysql.connect(**config, cursorclass=pymysql.cursors.DictCursor)
        return connection
    except pymysql.Error as e:
        print("Error al conectar a la base de datos:", e)
        return None

def execute_query(connection, query, params=None, commit=False):
    try:
        with connection.cursor() as cursor:
            if params:
                cursor.execute(query, params)
            else:
                cursor.execute(query)

            if commit:  # Si se especifica commit como True, confirmar la transacción
                connection.commit()

            result = cursor.fetchall()
            return result
    except pymysql.Error as e:
        print("Error al ejecutar la consulta:", e)
        return []

# Tasa de IGV (18%)
IGV_RATE = 0.18

# Archivo para almacenar el número de factura
INVOICE_NUMBER_FILE = 'invoice_number.txt'

def get_next_invoice_number():
    # Leer el número de factura actual del archivo
    if not os.path.exists(INVOICE_NUMBER_FILE):
        with open(INVOICE_NUMBER_FILE, 'w') as f:
            f.write('F0001')
    
    with open(INVOICE_NUMBER_FILE, 'r') as f:
        current_invoice_number = f.read().strip()
    
    # Incrementar el número de factura
    prefix = current_invoice_number[:1]
    number = int(current_invoice_number[1:])
    next_number = number + 1
    next_invoice_number = f'{prefix}{next_number:04d}'
    
    # Guardar el nuevo número de factura en el archivo
    with open(INVOICE_NUMBER_FILE, 'w') as f:
        f.write(next_invoice_number)
    
    return current_invoice_number

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        # Obtener los datos del formulario
        data = request.form.to_dict()
        
        # Obtener listas de productos, descripciones, precios y cantidades
        products = request.form.getlist('products[]')
        descriptions = request.form.getlist('descriptions[]')
        prices = list(map(float, request.form.getlist('prices[]')))
        quantities = list(map(int, request.form.getlist('quantities[]')))
        
        # Calcular importes individuales y total
        subtotals = [prices[i] * quantities[i] for i in range(len(products))]
        subtotal = sum(subtotals)
        
        # Calcular IGV y total a pagar
        total_igv = subtotal * IGV_RATE
        total_amount = subtotal + total_igv
        
        # Obtener el próximo número de factura
        invoice_number = get_next_invoice_number()
        
        # Generate QR Code
        qr_data = f"Nombre: {data['name']}\nRUC: {data['ruc']}\nTipo de moneda: {data['money']}\nObservación: {data['observations']}\nTotal: S/{total_amount:.2f}"

        # Generar QR Code con tamaño reducido
        qr = qrcode.QRCode(
            version=1,  # Versión del QR (controla el tamaño)
            error_correction=qrcode.constants.ERROR_CORRECT_L,  # Nivel de corrección de errores
            box_size=4,  # Tamaño del módulo (cada cuadro del código)
            border=2,    # Ancho del borde blanco alrededor del código
        )
        qr.add_data(qr_data)
        qr.make(fit=True)

        # Crear la imagen del código QR en formato PNG
        qr_img = qr.make_image(fill_color="black", back_color="white")

        # Convertir QR Code a base64
        buffered = BytesIO()
        qr_img.save(buffered, format='PNG')
        qr_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')

        # Crear un diccionario con los datos a enviar a la plantilla
        invoice_data = {
            'invoice_number': invoice_number,
            'date': date.today().strftime('%d/%m/%Y'),
            'name': data['name'],
            'ruc': data['ruc'],
            'money': data['money'],
            'observations': data['observations'],
            'address': data['address'],
            'products': products,
            'descriptions': descriptions,
            'prices': prices,
            'quantities': quantities,
            'subtotals': subtotals,
            'subtotal': subtotal,
            'total_igv': total_igv,
            'total_amount': total_amount
        }

        # Render HTML template with data and QR code
        rendered_html = render_template('invoice.html', data=invoice_data, qr_base64=qr_base64)
        pdf = render_pdf(rendered_html)
         # Crear el directorio 'pdfs' si no existe
        if not os.path.exists('pdfs'):
            os.makedirs('pdfs')

        # Guardar el PDF en el sistema de archivos
        pdf_filename = f"factura_{invoice_number}.pdf"
        pdf_path = os.path.join('pdfs', pdf_filename)
        with open(pdf_path, 'wb') as f:
            f.write(pdf.read())

        # Guardar los datos en la base de datos
        connection = connect_to_database(LOCAL_DB_CONFIG)
        if connection:
            query = """
                INSERT INTO invoices (invoice_number, date, name, ruc, money, observations, address, total_amount, pdf_filename)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
            """
            params = (
                invoice_number,
                date.today().strftime('%d/%m/%Y'),
                data['name'],
                data['ruc'],
                data['money'],
                data['observations'],
                data['address'],
                total_amount,
                pdf_filename
            )
            execute_query(connection, query, params, commit=True)
            connection.close()

        # Mostrar la vista previa del PDF en el navegador
        pdf.seek(0)
        return send_file(pdf, mimetype='application/pdf')

    return render_template('index.html')

def render_pdf(html):
    # Crear un buffer de memoria para el PDF
    buffer = BytesIO()

    # Convertir el HTML en PDF
    pisa_status = pisa.CreatePDF(BytesIO(html.encode('utf-8')), dest=buffer)

    # Verificar si hubo algún error durante la conversión
    if pisa_status.err:
        return None

    buffer.seek(0)
    return buffer
@app.route('/historial')
def historial():
    connection = connect_to_database(LOCAL_DB_CONFIG)
    if connection:
        query = "SELECT date, invoice_number, name, ruc, pdf_filename FROM invoices"
        invoices = execute_query(connection, query)
        connection.close()
    else:
        invoices = []

    return render_template('historial.html', invoices=invoices)

@app.route('/ver_pdf/<pdf_filename>')
def ver_pdf(pdf_filename):
    # Ruta para ver un PDF específico
    pdf_path = os.path.join('pdfs', pdf_filename)  # Asegúrate de ajustar la ruta según donde guardes los PDFs
    return send_file(pdf_path, mimetype='application/pdf')

if __name__ == '__main__':
    app.run(debug=True)
